Compare commits

...

3 Commits

Author SHA1 Message Date
079f41ce8a refactor: 从 core 中抽出跨模块契约建立 interface/common 模块分层
引入 interface/(零实现声明层)与 common/(共享 ADT 操作层),把跨模块
契约从 core 实现里抽出来,依赖方向回到单向(base ← interface ← common ←
各实现层)。docs/module-layering.org 记录完整方案与判定标准。

interface/(纯类型与多态接口声明,零 .c):
- types.h / event.h / backend.h 从 core 移入
- effect.h 新建(effect_t 从 plan.h 抽出)

common/(多实现层共用的自包含操作,.h + .c):
- event.{h,c}:event_reset / event_cleanup
- listeners.{h,c}:listeners 维护(add / cleanup);notify 留 core
- window.{h,c}:window_list + layer_props/metadata cleanup + window_classify_layer
- workspace.{h,c}:workspace_desc(从 wm_desc.h 拆出,改真实函数)

window 相关整理:
- window_layer_type_t 上浮 interface/types.h(common 的 classify 需要)
- window_classify_layer 移 common/window
- window_info_t 独立成 core/window_info.h(state/command 共享,不寄生)
- 删除 wm_desc.h,base/window_list 并入 common/window

全项目 include 路径同步更新
2026-06-25 03:00:30 +08:00
e1113c0052 docs: 新增模块分层与系统托盘设计文档 2026-06-24 13:54:21 +08:00
bf3de7fb92 style: 禁掉 clang-format 的 AlignConsecutiveAssignments 规则并重新格式化整个项目 2026-06-24 13:05:56 +08:00
71 changed files with 1787 additions and 1354 deletions

View File

@@ -6,12 +6,6 @@ IndentWidth: 2
ConstructorInitializerIndentWidth: 2 ConstructorInitializerIndentWidth: 2
ContinuationIndentWidth: 2 ContinuationIndentWidth: 2
AlignConsecutiveAssignments:
Enabled: true
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: true
PadOperators: true
AlignConsecutiveBitFields: AlignConsecutiveBitFields:
Enabled: true Enabled: true

View File

@@ -42,15 +42,18 @@ add_executable(${APP_NAME}
${SOURCE_DIR}/base/log.c ${SOURCE_DIR}/base/log.c
${SOURCE_DIR}/base/process.c ${SOURCE_DIR}/base/process.c
${SOURCE_DIR}/base/time.c ${SOURCE_DIR}/base/time.c
${SOURCE_DIR}/base/window_list.c
${SOURCE_DIR}/config/defaults.c ${SOURCE_DIR}/config/defaults.c
${SOURCE_DIR}/config/loader.c ${SOURCE_DIR}/config/loader.c
${SOURCE_DIR}/config/runtime_config.c ${SOURCE_DIR}/config/runtime_config.c
${SOURCE_DIR}/common/event.c
${SOURCE_DIR}/common/listeners.c
${SOURCE_DIR}/common/window.c
${SOURCE_DIR}/common/workspace.c
${SOURCE_DIR}/core/binding.c ${SOURCE_DIR}/core/binding.c
${SOURCE_DIR}/core/command_buffer.c ${SOURCE_DIR}/core/command_buffer.c
${SOURCE_DIR}/core/event.c
${SOURCE_DIR}/core/layer.c ${SOURCE_DIR}/core/layer.c
${SOURCE_DIR}/core/layout.c ${SOURCE_DIR}/core/layout.c
${SOURCE_DIR}/core/listeners.c ${SOURCE_DIR}/core/listeners.c

136
docs/module-layering.org Normal file
View File

@@ -0,0 +1,136 @@
#+title: ZDWM 模块分层与依赖方向
#+OPTIONS: toc:2
* 动机
随着模块增加,跨模块的"契约"和"共享数据结构"开始散落:有的进了 =core/=(和窗口管理逻辑混在一起),有的不得不靠依赖倒置塞进消费方目录(如 tray 契约放 =bar/= 导致 backend 反向依赖 bar。结果是 core 职责不清、=bar ↔ backend= 出现交叉依赖、依赖方向不再单向。
本文档定义一套分层约定,把"跨模块共享的东西"从具体实现里抽出来,集中到两个目录,使依赖方向回到干净的单向。
* 核心标准:按"谁直接消费类型"归类
判断一个跨模块的东西进哪个目录,不看它"属于哪个模块",也不只看"是声明还是实现",而是看**它的类型被哪些层直接消费**
- 类型被**两个或以上对等的实现层**直接消费 → 类型放 =interface/=(跨模块声明)
- 只有**操作函数**被多个实现层共用、且这些层不该互相依赖 → 操作放 =common/=
- 类型 + 操作都只被一个实现层(及其依赖者)用 → 整个 ADT 放 =common/=,或就近放该实现层
关键推论:**只需消费"类型"的层,不该被迫背上"操作函数"的依赖**。这是把类型和操作分到两个目录的根本理由。
* 目录的定位
先明确三层关系:=base/= 是**项目无关**的通用底层(任何 C 项目都能直接用),=interface/= 和 =common/= 是**项目业务相关**的通用内容。后两者依赖前者(业务依赖基础设施)。
** =src/base/= :项目无关的通用底层,零业务依赖
放任何 C 项目都能直接用的纯工具(=memory= / =array= / =macros= / =color= / =log= / =time= / =process=)。不依赖 interface/common/任何实现层——它根本不知道 ZDWM 的业务。=interface/= 和 =common/= 都可以依赖它。
** =src/interface/= :跨模块共享的【声明】,零 .c
只放类型定义、多态接口的函数声明。绝对不放假装、零实现代码。被所有实现层依赖,自身不依赖任何实现层(可依赖 =base/= 的纯类型)。
** =src/common/= :被多实现层共用的【操作函数】,.h + .c
放自包含的 ADT 操作(构造/清理/查询)。操作只依赖 =interface/= 里的类型(和 =base/= 工具),不依赖任何实现层的内部状态。被"需要这些操作的层"依赖。
注意:=common/= 不是"什么都往里塞的杂物间"。只有当操作被**多个不该互相依赖的实现层**共用时,才进 =common/=;只被单一实现层用的操作,就近放该层。
* 依赖方向
#+begin_example
base/ ← 项目无关的通用底层(任何 C 项目可用),零业务依赖
interface/ ← 零业务依赖(纯类型声明,含 backend 抽象接口);可依赖 base
common/ ← 项目业务通用的共享 ADT 操作;依赖 interface + base
core/ runtime/ backend/ bar/ ← 实现层,都依赖 common + interface+ base
#+end_example
注意:没有实现层"只依赖 interface"——所有实现层都用 =common/= 的业务通用操作。interface 的纯净性约束的是 interface *内部*(含 backend 抽象接口不依赖 interface 之外的任何东西),不是约束某个实现层的依赖深度。
不变量:
- =base/= 不依赖任何业务层interface/common/实现层),是项目无关的纯工具。
- =interface/=(含 backend 抽象接口)不依赖 =interface/= 之外的任何业务内容;可依赖 =base/= 的纯类型(业务层依赖基础设施,合理)。
- =common/= 只依赖 =interface/==base/=,不依赖任何实现层。
- 所有实现层core/runtime/backend/bar都依赖 =common/= + =interface/=+ =base/=);它们之间不直接相互依赖跨模块契约,都经由 =interface/==common/=
- 因此 =bar ↔ backend= 这类对等层之间不再有交叉依赖:都通过 =interface/tray.h= 通信。
* 判定示例effect / plan / event / listeners
用上面的标准,逐个判定现有跨模块类型:
** =effect_t= → interface类型无 .c
消费方corepolicy/plan 产生 =effect_t=+ backend执行 =effect_t=)。两个对等层直接消费类型,所以类型进 =interface/effect.h==effect_t= 是纯数据,构造它的活(=plan_push_*=)属于 plan 的操作,所以 effect 在 interface 里只有类型、没有 .c。
#+begin_src c
/* backend 只消费展开后的 effect 数组,从不碰 plan_t */
bool backend_apply_effect(backend_t *backend, const effect_t *effects, size_t effect_count);
#+end_src
** =plan_t= → 留 core完整 ADT类型 + 操作)
消费方:只 corepolicy 产生、收集 effect和 runtime提交后 reset/cleanup。两者之间是 *runtime→core 的天然单向依赖*runtime 是桥接层,本就依赖 core 的 policy/state 等)。把 =plan_t==core/plan.h= + =core/plan.c=runtime 正向 include 即可,不破坏任何方向——所以它*不必*进 common。
这把 common 的门槛精确化common 是为"对等、无天然依赖"的消费者中立化(见下文 =listeners_t=);若消费者之间已有单向依赖(如 plan 的 core+runtime共享操作放被依赖方core即可不必上浮 common。
** =event_t= → interface类型+ common操作
=event_t= 类型进 =interface/event.h= 的关键理由interface 内的 =backend.h= 契约直接 *#include 了 event.h*——=backend_poll_event= / =backend_next_event= 的参数是 =event_t *=,且契约注释讨论 event 的所有权与 =event_cleanup= 语义。一份完整的后端契约要让读者看到 event_t 全貌(字段、联合、生命周期责任),而非甩一个前向声明。所以 event_t 必须在 interface若放 common=backend.h= 要么退化为前向声明(契约不完整),要么 interface 反向依赖 common破坏零依赖
=event_reset= / =event_cleanup= 这些操作被 backend 和 runtime 共用,两者对等、不该互相依赖 → 操作落 =common/event.h= + =common/event.c=。于是 event 是"类型在 interface、操作在 common"的典型。
** =listeners_t= → common类型 + 维护)+ corenotify
=listeners_t= 类型被 bar订阅、core发布、runtime生命周期消费但 **backend 完全不碰它**。判定关键它的消费者bar/config/runtime都*既用类型又用维护操作*=add_*= / =cleanup=),没有哪个层"只需类型、不需操作"——按核心推论(只有"只需消费类型"的层才迫使类型单独上提 interface类型不必进 interface。与 =event_t= 的对照就在这里:=event_t= 因被 interface 内的 =backend.h= 契约需要完整定义而必须留 interface=listeners_t= 则*不被 interface 内任何契约依赖*=backend.h= 完全不碰它),所以能整个进 common
- 类型 =listeners_t= + 维护操作 =add_*= / =cleanup=:自包含容器操作,被 bar/config/runtime 多个对等层共用 → 整个 ADT 进 =common/listeners.{h,c}=
- =notify_*=(触发):单消费者(只 core/runtime 发布侧调用),且依赖 core 内部(把 =state_t= 翻译成 =zdwm_window_t= 等 DTO→ 声明 + 实现都留 =core/listeners=
真正的跨层契约(回调签名 =zdwm_window_added=+ DTO已在 =include/zdwm/listeners.h=(比 interface 更公开的那层),=listeners_t= 只是这些回调的容器,所以它整个待在 common 自洽,不必单独占一个 interface 头。
* 汇总表
| 东西 | 类型在哪 | 操作在哪 | 判定理由 |
|------------------------------+-----------------------+-------------------------------------------+--------------------------------------------------------------------------|
| =effect_t= | =interface/effect.h= | (无,构造归 plan 操作) | 类型跨模块core 产 + backend 执行),纯数据 |
| =plan_t= | =core/plan.h= | =core/plan.c= | 消费者 runtime→core 单向,放 core 不破坏方向,不必 common |
| =event_t= | =interface/event.h= | =common/event.h= + =common/event.c= | 类型跨模块;操作对等共用 |
| 后端接口(=backend_t= 等) | =interface/backend.h= | =backend/x11/*.c= | 多态接口:声明在 interface实现在具体后端 |
| tray 契约(=tray_t= 等) | =interface/tray.h= | =backend/x11/tray.c= | 多态接口bar 用、backend 实现,声明在 interface 消除 =bar↔backend= 交叉 |
| 通知协议listeners | =common/listeners.h= | =common/listeners.c= + =core/listeners.c= | 消费者 bar↔core 对等,必须 common 中立化notify 依赖 core 留 core |
| 基础类型(=window_id_t= 等) | =interface/types.h= | (按需) | 所有层共用 |
* 多态接口 vs 共享 ADT.c 归属的不同
=interface/= 里有两类声明,它们的 .c 归属不同,务必区分:
- **多态接口**=backend.h==tray.h=):声明一组"由谁来实现"的函数实现依赖具体实现层xcb / 未来 wayland。这类 .c **必须在实现层**=backend/x11/==core/=),不能在 interface——否则 interface 就"知道"了具体实现。
- **共享 ADT 的操作**event 的操作):实现自包含、不依赖任何实现层。这类 .c 进 =common/=
换句话说:=interface/= 永远零 .c。多态接口的 .c 在实现层,共享操作的 .c 在 =common/=
* 和 include/zdwm/ 的区别
- =include/zdwm/= 是**对外公共 API**(给用户配置、插件使用)。
- =src/interface/= 是**内部跨模块契约**(给各子系统互相通信)。
两者职责不同,不合并。像 =backend.h==event.h==effect.h= 是内部的,不该进 =include/zdwm/= 暴露给外部。
* 迁移指引
把现有代码按本分层整理时,建议顺序:
1.=src/interface/==src/common/= 目录,加入 CMakeLists。
2. 先迁移"纯类型、零依赖"的声明进 =interface/==types.h==effect.h=(从 =core/plan.h= 抽出 =effect_t=)、=event.h= 的类型部分。
3. 多态接口声明迁移:=backend.h==interface/==.c= 留原处)。=listeners= 走共享 ADT、不进 interface=listeners_t= 类型 + =add_*= / =cleanup= 整体进 =common/listeners.{h,c}==notify_*==core/listeners=(详见上方判定示例)。
4. 共享 ADT 迁移:=event.h= 操作部分 + =event.c==common/=。(=plan= 留 core消费者 runtime→core 单向,不必上浮。)
5. 更新全项目 include 路径(="core/types.h"=="interface/types.h"= 等)。
6. 每步后编译验证,确保依赖方向单向、无循环。
注意边界:遇到"看起来该进 interface、但其类型依赖还在 core"的情况(如某个 event 子结构引用了 =core/window.h= 的类型),要么把那个被引用的类型也提到 =interface/=,要么承认它暂不进 interface——**进 interface 的前提是它的所有依赖都在 interface**,不能硬塞。
* tray 的落点
tray 的契约(=tray_t= / =tray_api_t=)是 bar 与 backend 之间的多态接口,按本分层落 =interface/tray.h=(声明),实现在 =backend/x11/tray.c=。这样 bar 和 backend 都只依赖 =interface/tray.h=,彻底消除 =bar ↔ backend= 交叉依赖——这正是引入这套分层的最初动机之一。详见 [[file:tray-design.org][tray-design.org]]。

256
docs/tray-design.org Normal file
View File

@@ -0,0 +1,256 @@
#+title: ZDWM Tray 系统托盘设计
#+OPTIONS: toc:2
* 背景与动机
ZDWM 当前没有系统托盘system tray / systray功能。本文档描述如何在 bar 中实现 X11 系统托盘,让外部应用(输入法、音量、蓝牙、网络等)的托盘图标显示在状态栏右侧并正常交互,同时保持现有前后端分离架构,为未来 Wayland 后端预留扩展空间。
* 设计目标与约束
** 前后端分离
tray 协议(=_NET_SYSTEM_TRAY= + XEMBED必须*闭环在后端内部*。core 的 =event_t= / =policy= / =plan= 完全不感知 tray——tray 不产生 =event_t=、不进 policy 路由、不进 plan/effect。
这与现有架构的三条解耦通道一致:
- =backend -> core=:后端把平台原始事件归一化为 =event_t=
- =core -> backend=core 产出 =effect_t=,后端执行
- =runtime= 作为唯一桥接点bar 模块本身拿不到 backend所有平台访问经 runtime 中转
** Wayland 预留
bar 与 runtime 层必须后端无关、零 xcb。未来加 Wayland 后端时只需新增一个后端实现——Wayland 用 StatusNotifierItemSNIover D-Busicon 是像素数据而非真实窗口,由前端 cairo 绘制。只要后端接口形状不变上层bar/runtime零改动。
** tray 是 bar 的附属组件
没有 bar 就没有 tray。tray 的生命周期随 bar 窗口,*不*作为独立公共接口(不进 =include/zdwm/=。tray 能力内嵌在 bar 窗口的创建/销毁里。
* 方案选型嵌入式容器子窗口A'
X11 系统托盘协议只要求tray 创建一个 window 成为 =_NET_SYSTEM_TRAY_S<n>= 的 selection owner客户端向 owner 发 =_NET_SYSTEM_TRAY_REQUEST_DOCK= 请求tray 用 XEMBED reparent icon。协议本身*不*规定 icon reparent 到 bar 窗口还是独立窗口。
** 为何不用独立 top-level 窗口
完全独立的 top-level tray 窗口(如 stalonetray是为*没有状态栏*的环境设计的。ZDWM 已有 bar用独立窗口会引入"两个窗口的几何/对齐同步"问题tray 窗口要贴 bar 右端、随 icon 数动态 resize、跟随 bar 移动),且无功能收益。
** 为何用专门的容器子窗口
虽然直接 reparent 到 bar 的 cairo 绘制窗口技术上可行bar 已是 ARGB子窗口叠加在 cairo 内容之上),但用一个*专门的 tray 容器子窗口*做 selection owner 更正统、更干净:
1. *职责分离*bar 窗口专注 cairo 绘制tray 容器专注 XEMBED / icon 管理。dock 请求和 =_XEMBED= 消息定向到容器,不进 bar 的 =handle_client_message=
2. *事件隔离*tray 协议事件在容器窗口闭环bar 的窗口管理事件流零污染。
3. *视觉不变*:容器是 bar 窗口的子窗口,位于 tray region 内icon 跟随 bar 移动/resizeX 子窗口语义),不占额外屏幕空间。
* 后端接口设计
tray 契约独立成头 =src/bar/tray.h= —— *不放 core*,因为 tray 与 core 无关core 不感知 tray。由 bar 定义、后端实现(消费方定义接口、提供方实现的依赖倒置;契约是纯抽象头)。它只依赖 =core/types.h==window_id_t=),不含 =backend_t=,所以 bar include 它而不碰 =core/backend.h=,保持"bar 不知道后端内部"。=core/backend.h= 反过来 include =bar/tray.h=,让 =backend_bar_window_t= 内嵌 =tray_t=
#+begin_src c
typedef void (*tray_icons_change_cb_t)(void *user_data);
typedef struct tray_api_t {
/* 返回 tray 当前挂载的 bar window_idinvalid 表示无 tray 挂载 */
window_id_t (*host_window)(void *handle);
/* 当前 icon 数量 */
size_t (*icon_count)(void *handle);
/* icon 边长(= bar heightbar 据此算 cell 宽度 */
int32_t (*icon_size)(void *handle);
/* 把容器 + icon 摆到 region 起点 x */
void (*place)(void *handle, int32_t x);
/* 注册 icon 数量变化回调 */
void (*set_listener)(void *handle,
tray_icons_change_cb_t cb,
void *user_data);
} tray_api_t;
typedef struct tray_t {
tray_api_t api; /* 值类型,后端总填充,一直可用 */
void *handle; /* 指向 backendbar 不知其类型) */
} tray_t;
typedef struct backend_bar_window_t {
window_id_t window_id;
cairo_t *cr;
tray_t tray;
} backend_bar_window_t;
/* 扩展:加 enable_trayicon_size 直接用 geometry.height */
backend_bar_window_t backend_create_bar_window(
backend_t *backend, rect_t geometry, uint32_t bg_pixel, bool enable_tray);
#+end_src
** 关键设计点
- *api 是值类型*:后端用一个全局 =static const= vtable 填充保证一直可用bar 不需判 NULL。这与项目现有 =zdwm_bar_item_type_t=(纯 vtable+ =zdwm_bar_item_t=(实例持有 api + state的模式一致。
- *handle 总有效*:实际指向 =backend_t*=tray api 函数内用 =backend->conn==backend->tray= host对 bar 透明(=void*=)。有无 tray 统一由 =host_window()= 返回值判断invalid = 无),不靠 api 是否 NULL避免"先判 api、再判 host_window"两个判断点。
- *icon_size 来自 handle*(单一数据源):后端 configure icon 用的尺寸 = bar 查布局用的尺寸,杜绝两边各算导致 icon 错位/溢出。这比在 =tray_t= 冗余存一份快照更纯粹。
- *生命周期随 bar/backend*=backend_create_bar_window(enable_tray=true)= 时创建/迁移 host=backend_destroy= 释放。无 =tray_host_create/destroy= 独立入口,体现"tray 是 bar 附属"。
** 挂载语义
X11 的 =_NET_SYSTEM_TRAY_S0= selection owner *整个 display 只能有一个*,但 =backend_create_bar_window= 是 per-output 调用的。处理方式:
- tray host 是后端单例(内联在 =backend_t=)。
- 每次传 =enable_tray=true==create_bar_window= 把容器 reparent 到本次 bar 窗口,最终挂在*最后一个* true 的 output 上。
- =host_window()= 返回当前挂载的 bar window_idbar 据此决定哪个 output 渲染 tray。
** 为何 set_listener 不配 remove_listener
tray icon 变化的唯一消费者是 bar 的 tray item且其生命周期 = host 生命周期(=backend_destroy= 时自然消失)。与 core 的 =listeners= 模块一致listener 跟宿主容器走,靠容器销毁回收),不引入 =remove_listener=
* bar item 框架扩展
tray 作为 right-side 的普通 item复用 =zdwm_bar_item_type_t= 框架。为支持 tray 的两个本质差异cell 无文本 + 需要在 layout 后把结果同步到后端真实窗口),对框架做最小*通用*扩展——不为 tray 特例化。
** cell_api 全包 cell 相关(不引入 item_api
=set_cell_count= / =get_cell_count= 本质是 *cell 集合的管理*(类比 =std::vector==size()/resize()==operator[]= 同属 vector留在 =zdwm_bar_cell_api_t=
新增两个 cell 级接口:
#+begin_src c
/* 固定宽度:>0 = 固定宽度0 = 走文本测量(零值默认),<0 = 隐藏 */
void cell_set_fixed_width(zdwm_bar_item_t *, size_t index, int32_t width);
/* 单个 cell 的 regionlayout 后的坐标) */
bar_x_region_t cell_get_region(zdwm_bar_item_t *, size_t index);
#+end_src
=bar_cell_t==int32_t fixed_width=,默认 =0=(走文本测量)。把零值留给最常见的默认行为(测量),=p_clear= 清零后新 cell 天然正确,=set_cell_count= 无需补初始化;=-1= 当"隐藏"哨兵(负数宽度本就无意义),与 =0=(测量)明确区分,没有歧义。
=bar_output_layout= 改一处:
#+begin_src c
int32_t width;
if (cell->fixed_width > 0) width = cell->fixed_width; /* 固定 */
else if (cell->fixed_width == 0) width = ; /* 测量(默认)*/
else width = 0; /* 隐藏 */
#+end_src
** after_layout / after_draw 钩子
普通 item 是 cairo 绘制tray 是"layout 后把 region 应用到后端真实窗口"。给 =zdwm_bar_item_type_t= 加两个*可空*通用钩子,参数打包(仿现有 =zdwm_bar_click_params_t= 先例):
#+begin_src c
typedef struct zdwm_bar_item_layout_params_t {
zdwm_bar_item_t *item;
const zdwm_bar_cell_api_t *cell_api;
bar_x_region_t region;
void *state;
} zdwm_bar_item_layout_params_t;
void (*after_layout)(const zdwm_bar_item_layout_params_t *); /* 可空 */
void (*after_draw)(const zdwm_bar_item_layout_params_t *); /* 可空 */
#+end_src
设计要点:
- 钩子为 NULL 则跳过,普通 item 零影响。
- =after_layout= / =after_draw==update= 多一个 =region=(它们在 layout 之后调用),且通过 =cell_api= 可调 =cell_get_region= 取 per-cell 位置。
- =update= 不打包参数3 个参数不多,保持现有 =workspaces= / =binding= / =windows= 三个 item 零改动)。
=bar_draw= 流程:
#+begin_src c
bar_output_layout(bo, ctx);
for each item: if (after_layout) after_layout(params); /* params 含 region */
bar_output_draw(bo, ctx, bg);
for each item: if (after_draw) after_draw(params);
#+end_src
* bar tray item
新增 =src/bar/tray.c=,作为普通 right-side item参考 [[file:../src/bar/workspaces.c][workspaces.c]] 的实现模式):
#+begin_src c
zdwm_bar_item_type_t bar_tray = {
.create_state = bar_tray_create_state,
.update = bar_tray_update,
.on_click = bar_tray_on_click, /* 返回 NONEicon 真实子窗口自收点击 */
.after_layout = bar_tray_after_layout,
.destroy_state = bar_tray_destroy_state,
};
#+end_src
- =create_state=:拷贝 =tray_t=,调 =set_listener= 注册回调(回调置 =state->dirty = true=)。
- =update==dirty==set_cell_count(icon_count)= + 循环 =cell_set_fixed_width(i, icon_size)=
- =after_layout==place(handle, params->region.start)=
tray cell 不画 cairo 内容text 为空,=bar_item_draw= 只画融入 bar 的背景色块,被真实 icon 窗口盖住)。
* runtime 桥接
=runtime_init_bar==src/runtime/runtime.c=)的 create 循环:
#+begin_src c
for (size_t i = 0; i < count; ++i) {
bool enable_tray = ((int32_t)i == runtime->bar.config.tray_output_index);
auto bar_window = backend_create_bar_window(backend, bar_rect, color, enable_tray);
...
runtime->bar.tray = bar_window.tray; /* 每个返回都一样,存一份 */
}
bar_init(&runtime->bar, &runtime->listeners);
#+end_src
=bar_init= 遍历 =bar_output=,对 =host_window()= 匹配自身 =window_id= 的那个 output 调 =bar_output_add_tray=right side其余不加。tray 生命周期随 =backend_destroy=runtime 无特殊清理。
* 配置
=zdwm_bar_config_t==include/zdwm/config.h=)加:
#+begin_src c
int32_t tray_output_index; /* 默认 0 = 第一个 output */
#+end_src
配置 setup 中可通过 output 信息确定具体 index。
* 数据流(触发链)
#+begin_example
icon 增删
-> 后端 set_listener 回调 -> state->dirty = true
-> 下个 timerfd tick -> bar_update -> bar_tray_update
-> set_cell_count + cell_set_fixed_width -> item 标 dirty
-> bar_draw -> bar_output_layout 重算 regioncell 数变了)
-> tray 的 after_layout -> backend place(handle, region.start)
-> 后端 move 容器 + configure 每个 icon 到 (region.start + i*icon_size, 0)
#+end_example
bar 重绘是 timerfdfps驱动非事件驱动。tray icon 是真实窗口X server 自管绘制,不依赖 cairo 重绘。
* 实现范围(第一版)
第一版做*基础可用*
- =_NET_SYSTEM_TRAY_S0= selection owner + MANAGER 广播
- 基础 XEMBEDreparent 容器、=_XEMBED_EMBEDDED_NOTIFY=
- icon 显示与点击
- icon 尺寸 = bar 高度(统一,不缩放)
放后续迭代:
- 完整 XEMBED 焦点 / 激活转发
- icon 尺寸协商与缩放
- 客户端异常断开的清理
*透明背景*第一版基本白送——bar 窗口已是 ARGB visual=backend_create_bar_window= 调用 =window_get_visual(backend, true)=tray 容器作为子窗口继承。
* 关键文件清单
| 文件 | 改动 |
|------------------------------+----------------------------------------------------------------------------------------------------------|
| =src/bar/tray.h= | **新增** tray 契约:=tray_t= / =tray_api_t= / =tray_icons_change_cb_t=bar 定义、后端实现;不进 core |
| =src/core/backend.h= | include =bar/tray.h==backend_bar_window_t= 内嵌 =tray_t=;扩展 =backend_create_bar_window=(加 =enable_tray= |
| =src/backend/x11/tray.c= | *新增*selection / MANAGER / 基础 XEMBED / icon 管理 / =place= |
| =src/backend/x11/internal.h= | =ATOM_LIST= 追加 tray/XEMBED atoms=backend_t= 加 =tray= 字段 |
| =src/backend/x11/event.c= | 消化 tray 相关 client message不产 =event_t= |
| =src/backend/x11/backend.c= | =backend_create_bar_window= 实现 enable_tray 分支;=backend_destroy= 释放 tray |
| =src/bar/types.h= | =bar_cell_t= 加 =fixed_width==bar_t= 加 =tray= |
| =src/bar/cell.h= / =cell.c= | =cell_api= 加 =cell_set_fixed_width= / =cell_get_region= |
| =src/bar/bar.c= | layout 支持 =fixed_width==bar_draw= 调 after 钩子;=bar_init= 加 tray item新增 layout params 类型 |
| =src/bar/tray.c= | *新增*tray item 实现 |
| =src/runtime/runtime.c= | =runtime_init_bar= 传 =enable_tray=、存 =bar->tray= |
| =include/zdwm/config.h= | =zdwm_bar_config_t= 加 =tray_output_index= |
* 复用现有
- =backend_create_bar_window==src/backend/x11/backend.c=bar 窗口已是 ARGBtray 容器继承透明。
- =zdwm_bar_item_type_t= vtable 框架 + [[file:../src/bar/workspaces.c][workspaces.c]]tray item 同模式落地。
- =zdwm_bar_click_params_t==after_layout= / =after_draw= 的 params 打包仿此先例。
- =cell_api= 机制tray =update= 通过它操作 cell与 workspaces 一致)。

View File

@@ -56,7 +56,7 @@ zdwm_layout_result_push(zdwm_layout_result_t *result, zdwm_layout_item_t item) {
realloc(result->items, capacity * sizeof(*result->items)); realloc(result->items, capacity * sizeof(*result->items));
if (!items) abort(); if (!items) abort();
result->items = items; result->items = items;
result->item_capacity = capacity; result->item_capacity = capacity;
} }

View File

@@ -25,6 +25,7 @@ typedef enum zdwm_button_t {
ZDWM_BUTTON_MIDDLE, ZDWM_BUTTON_MIDDLE,
} zdwm_button_t; } zdwm_button_t;
/* clang-format off */
typedef enum zdwm_modifier_bit_t { typedef enum zdwm_modifier_bit_t {
ZDWM_MOD_NONE = 0u, ZDWM_MOD_NONE = 0u,
ZDWM_MOD_SHIFT = 1u << 0, ZDWM_MOD_SHIFT = 1u << 0,
@@ -35,6 +36,8 @@ typedef enum zdwm_modifier_bit_t {
ZDWM_MOD_4 = 1u << 5, ZDWM_MOD_4 = 1u << 5,
ZDWM_MOD_5 = 1u << 6, ZDWM_MOD_5 = 1u << 6,
} zdwm_modifier_bit_t; } zdwm_modifier_bit_t;
/* clang-format on */
typedef uint32_t zdwm_modifier_mask_t; typedef uint32_t zdwm_modifier_mask_t;
typedef struct zdwm_rect_t { typedef struct zdwm_rect_t {

View File

@@ -4,8 +4,8 @@
#include <stdint.h> #include <stdint.h>
#include "base/memory.h" #include "base/memory.h"
#include "core/backend.h" #include "interface/backend.h"
#include "core/types.h" #include "interface/types.h"
static inline int32_t right(rect_t a) { return a.x + a.width; } static inline int32_t right(rect_t a) { return a.x + a.width; }
static inline int32_t bottom(rect_t a) { return a.y + a.height; } static inline int32_t bottom(rect_t a) { return a.y + a.height; }
@@ -42,14 +42,14 @@ output_remove_duplication(const output_info_t *output, const size_t count) {
} }
output_info_t *list = p_new(output_info_t, amount); output_info_t *list = p_new(output_info_t, amount);
amount = 0; amount = 0;
for (size_t i = 0; i < count; i++) { for (size_t i = 0; i < count; i++) {
if (remove[i]) continue; if (remove[i]) continue;
list[amount++] = output[i]; list[amount++] = output[i];
} }
p_delete(&remove); p_delete(&remove);
backend_detect_t *detect = p_new(backend_detect_t, 1); backend_detect_t *detect = p_new(backend_detect_t, 1);
detect->outputs = list; detect->outputs = list;
detect->output_count = amount; detect->output_count = amount;
return detect; return detect;
} }

View File

@@ -2,8 +2,7 @@
#include <stddef.h> #include <stddef.h>
#include "core/backend.h" #include "interface/backend.h"
#include "core/types.h"
backend_detect_t * backend_detect_t *
output_remove_duplication(const output_info_t *output, const size_t count); output_remove_duplication(const output_info_t *output, const size_t count);

View File

@@ -1,4 +1,4 @@
#include "core/backend.h" #include "interface/backend.h"
#include <cairo-xcb.h> #include <cairo-xcb.h>
#include <cairo.h> #include <cairo.h>
@@ -25,11 +25,7 @@
#include "base/log.h" #include "base/log.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/memory.h" #include "base/memory.h"
#include "base/window_list.h" #include "common/window.h"
#include "core/event.h"
#include "core/plan.h"
#include "core/types.h"
#include "core/window.h"
#include "internal.h" #include "internal.h"
typedef struct atom_item_t { typedef struct atom_item_t {
@@ -40,7 +36,7 @@ typedef struct atom_item_t {
static void atoms_init(backend_t *backend) { static void atoms_init(backend_t *backend) {
xcb_connection_t *conn = backend->conn; xcb_connection_t *conn = backend->conn;
atoms_t *atoms = &backend->atoms; atoms_t *atoms = &backend->atoms;
#define ATOM_ITEM(name) {#name, sizeof(#name) - 1, &atoms->name}, #define ATOM_ITEM(name) {#name, sizeof(#name) - 1, &atoms->name},
atom_item_t atom_list[] = {ATOM_LIST(ATOM_ITEM)}; atom_item_t atom_list[] = {ATOM_LIST(ATOM_ITEM)};
@@ -58,7 +54,7 @@ static void atoms_init(backend_t *backend) {
if (!reply) continue; if (!reply) continue;
atom_item_t *atom = &atom_list[i]; atom_item_t *atom = &atom_list[i];
*atom->atom = reply->atom; *atom->atom = reply->atom;
p_delete(&reply); p_delete(&reply);
} }
@@ -80,22 +76,22 @@ static void atoms_init(backend_t *backend) {
static void create_wm_check_window(backend_t *backend) { static void create_wm_check_window(backend_t *backend) {
xcb_connection_t *conn = backend->conn; xcb_connection_t *conn = backend->conn;
xcb_window_t root = backend->screen->root; xcb_window_t root = backend->screen->root;
uint8_t depth = backend->screen->root_depth; uint8_t depth = backend->screen->root_depth;
xcb_visualid_t v = backend->screen->root_visual; xcb_visualid_t v = backend->screen->root_visual;
uint16_t _c = XCB_WINDOW_CLASS_COPY_FROM_PARENT; uint16_t _c = XCB_WINDOW_CLASS_COPY_FROM_PARENT;
uint32_t m = XCB_NONE; uint32_t m = XCB_NONE;
void *p = nullptr; void *p = nullptr;
xcb_window_t win = xcb_generate_id(conn); xcb_window_t win = xcb_generate_id(conn);
xcb_create_window(conn, depth, win, root, -1, -1, 1, 1, 0, _c, v, m, p); xcb_create_window(conn, depth, win, root, -1, -1, 1, 1, 0, _c, v, m, p);
window_set_class_instance(conn, win); window_set_class_instance(conn, win);
window_set_name_static(conn, win, APP_NAME); window_set_name_static(conn, win, APP_NAME);
uint8_t mode = XCB_PROP_MODE_REPLACE; uint8_t mode = XCB_PROP_MODE_REPLACE;
xcb_atom_t prop = backend->atoms._NET_WM_NAME; xcb_atom_t prop = backend->atoms._NET_WM_NAME;
xcb_atom_t type = backend->atoms.UTF8_STRING; xcb_atom_t type = backend->atoms.UTF8_STRING;
auto data_len = sizeof(APP_NAME) - 1; auto data_len = sizeof(APP_NAME) - 1;
xcb_change_property(conn, mode, win, prop, type, 8, data_len, APP_NAME); xcb_change_property(conn, mode, win, prop, type, 8, data_len, APP_NAME);
prop = backend->atoms._NET_SUPPORTING_WM_CHECK; prop = backend->atoms._NET_SUPPORTING_WM_CHECK;
@@ -103,27 +99,27 @@ static void create_wm_check_window(backend_t *backend) {
xcb_change_property(conn, mode, win, prop, type, 32, 1, &win); xcb_change_property(conn, mode, win, prop, type, 32, 1, &win);
xcb_change_property(conn, mode, root, prop, type, 32, 1, &win); xcb_change_property(conn, mode, root, prop, type, 32, 1, &win);
prop = backend->atoms._NET_WM_PID; prop = backend->atoms._NET_WM_PID;
type = XCB_ATOM_CARDINAL; type = XCB_ATOM_CARDINAL;
pid_t pid = getpid(); pid_t pid = getpid();
xcb_change_property(conn, mode, win, prop, type, 32, 1, &pid); xcb_change_property(conn, mode, win, prop, type, 32, 1, &pid);
} }
static void create_no_focus_window(backend_t *backend) { static void create_no_focus_window(backend_t *backend) {
xcb_connection_t *conn = backend->conn; xcb_connection_t *conn = backend->conn;
xcb_window_t root = backend->screen->root; xcb_window_t root = backend->screen->root;
uint8_t d = backend->screen->root_depth; uint8_t d = backend->screen->root_depth;
xcb_visualid_t v = backend->screen->root_visual; xcb_visualid_t v = backend->screen->root_visual;
uint16_t _c = XCB_WINDOW_CLASS_COPY_FROM_PARENT; uint16_t _c = XCB_WINDOW_CLASS_COPY_FROM_PARENT;
xcb_window_t win = xcb_generate_id(conn); xcb_window_t win = xcb_generate_id(conn);
uint32_t m = XCB_CW_BACK_PIXEL | XCB_CW_BORDER_PIXEL | uint32_t m = XCB_CW_BACK_PIXEL | XCB_CW_BORDER_PIXEL |
XCB_CW_OVERRIDE_REDIRECT | XCB_CW_COLORMAP; XCB_CW_OVERRIDE_REDIRECT | XCB_CW_COLORMAP;
const xcb_create_window_value_list_t p = { const xcb_create_window_value_list_t p = {
.override_redirect = true, .override_redirect = true,
.background_pixel = backend->screen->black_pixel, .background_pixel = backend->screen->black_pixel,
.border_pixel = backend->screen->black_pixel, .border_pixel = backend->screen->black_pixel,
.colormap = backend->screen->default_colormap, .colormap = backend->screen->default_colormap,
}; };
xcb_create_window_aux(conn, d, win, root, -1, -1, 1, 1, 0, _c, v, m, &p); xcb_create_window_aux(conn, d, win, root, -1, -1, 1, 1, 0, _c, v, m, &p);
window_set_class_instance(conn, win); window_set_class_instance(conn, win);
@@ -134,9 +130,9 @@ static void create_no_focus_window(backend_t *backend) {
} }
backend_t *backend_create(const char *display_name) { backend_t *backend_create(const char *display_name) {
int screen_num = 0; int screen_num = 0;
xcb_connection_t *conn = xcb_connect(display_name, &screen_num); xcb_connection_t *conn = xcb_connect(display_name, &screen_num);
int xcb_conn_error = xcb_connection_has_error(conn); int xcb_conn_error = xcb_connection_has_error(conn);
if (xcb_conn_error) { if (xcb_conn_error) {
fatal("cannot open display %s, error %d", display_name, xcb_conn_error); fatal("cannot open display %s, error %d", display_name, xcb_conn_error);
} }
@@ -145,7 +141,7 @@ backend_t *backend_create(const char *display_name) {
if (!screen) fatal("cannot get screen info"); if (!screen) fatal("cannot get screen info");
xcb_window_t root = screen->root; xcb_window_t root = screen->root;
uint32_t mask = XCB_CW_EVENT_MASK; uint32_t mask = XCB_CW_EVENT_MASK;
const xcb_params_cw_t params = { const xcb_params_cw_t params = {
.event_mask = XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, .event_mask = XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT,
}; };
@@ -159,9 +155,9 @@ backend_t *backend_create(const char *display_name) {
} }
backend_t *backend = p_new(backend_t, 1); backend_t *backend = p_new(backend_t, 1);
backend->conn = conn; backend->conn = conn;
backend->screen = screen; backend->screen = screen;
backend->screenp = screen_num; backend->screenp = screen_num;
xcb_prefetch_extension_data(conn, &xcb_xfixes_id); xcb_prefetch_extension_data(conn, &xcb_xfixes_id);
const xcb_query_extension_reply_t *query = const xcb_query_extension_reply_t *query =
@@ -268,10 +264,10 @@ static bool detect_monitor_by_randr(
xcb_randr_monitor_info_iterator_t iter = xcb_randr_monitor_info_iterator_t iter =
xcb_randr_get_monitors_monitors_iterator(monitors_reply); xcb_randr_get_monitors_monitors_iterator(monitors_reply);
for (int i = 0; iter.rem; xcb_randr_monitor_info_next(&iter), i++) { for (int i = 0; iter.rem; xcb_randr_monitor_info_next(&iter), i++) {
output_info_t *output = &output_list[i]; output_info_t *output = &output_list[i];
output->geometry.x = iter.data->x; output->geometry.x = iter.data->x;
output->geometry.y = iter.data->y; output->geometry.y = iter.data->y;
output->geometry.width = iter.data->width; output->geometry.width = iter.data->width;
output->geometry.height = iter.data->height; output->geometry.height = iter.data->height;
xcb_get_atom_name_cookie_t name_cookie = xcb_get_atom_name_cookie_t name_cookie =
@@ -280,8 +276,8 @@ static bool detect_monitor_by_randr(
xcb_get_atom_name_reply(backend->conn, name_cookie, nullptr); xcb_get_atom_name_reply(backend->conn, name_cookie, nullptr);
if (name_reply) { if (name_reply) {
char *name = xcb_get_atom_name_name(name_reply); char *name = xcb_get_atom_name_name(name_reply);
int length = xcb_get_atom_name_name_length(name_reply); int length = xcb_get_atom_name_name_length(name_reply);
output->name = p_strndup(name, length); output->name = p_strndup(name, length);
p_delete(&name_reply); p_delete(&name_reply);
} }
@@ -350,10 +346,10 @@ static bool detect_monitor_by_xinerama(
output_info_t *output_list = p_new(output_info_t, len); output_info_t *output_list = p_new(output_info_t, len);
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
output_info_t *output = &output_list[i]; output_info_t *output = &output_list[i];
output->geometry.x = screen_info[i].x_org; output->geometry.x = screen_info[i].x_org;
output->geometry.y = screen_info[i].y_org; output->geometry.y = screen_info[i].y_org;
output->geometry.width = screen_info[i].width; output->geometry.width = screen_info[i].width;
output->geometry.height = screen_info[i].height; output->geometry.height = screen_info[i].height;
} }
p_delete(&screens_reply); p_delete(&screens_reply);
@@ -371,7 +367,7 @@ static bool detect_monitor_by_xinerama(
backend_detect_t *backend_detect(backend_t *backend) { backend_detect_t *backend_detect(backend_t *backend) {
output_info_t *outputs = nullptr; output_info_t *outputs = nullptr;
size_t count = 0; size_t count = 0;
if (detect_monitor_by_randr(backend, &outputs, &count)) { if (detect_monitor_by_randr(backend, &outputs, &count)) {
backend_detect_t *detect = output_remove_duplication(outputs, count); backend_detect_t *detect = output_remove_duplication(outputs, count);
@@ -385,15 +381,15 @@ backend_detect_t *backend_detect(backend_t *backend) {
return detect; return detect;
} }
output_info_t *output = p_new(output_info_t, 1); output_info_t *output = p_new(output_info_t, 1);
output->geometry.x = 0; output->geometry.x = 0;
output->geometry.y = 0; output->geometry.y = 0;
output->geometry.width = backend->screen->width_in_pixels; output->geometry.width = backend->screen->width_in_pixels;
output->geometry.height = backend->screen->height_in_pixels; output->geometry.height = backend->screen->height_in_pixels;
backend_detect_t *detect = p_new(backend_detect_t, 1); backend_detect_t *detect = p_new(backend_detect_t, 1);
detect->outputs = output; detect->outputs = output;
detect->output_count = 1; detect->output_count = 1;
return detect; return detect;
} }
@@ -410,16 +406,16 @@ void backend_detect_destroy(backend_detect_t *detect) {
static void backend_focus_window(backend_t *backend, xcb_window_t window) { static void backend_focus_window(backend_t *backend, xcb_window_t window) {
xcb_connection_t *conn = backend->conn; xcb_connection_t *conn = backend->conn;
xcb_window_t root = backend->screen->root; xcb_window_t root = backend->screen->root;
const atoms_t *atoms = &backend->atoms; const atoms_t *atoms = &backend->atoms;
xcb_atom_t property = atoms->_NET_ACTIVE_WINDOW; xcb_atom_t property = atoms->_NET_ACTIVE_WINDOW;
xcb_timestamp_t time = XCB_TIME_CURRENT_TIME; xcb_timestamp_t time = XCB_TIME_CURRENT_TIME;
if (window == XCB_WINDOW_NONE || window == root) { if (window == XCB_WINDOW_NONE || window == root) {
window = backend->window_no_focus; window = backend->window_no_focus;
xcb_set_input_focus(conn, XCB_INPUT_FOCUS_PARENT, window, time); xcb_set_input_focus(conn, XCB_INPUT_FOCUS_PARENT, window, time);
xcb_delete_property(conn, root, property); xcb_delete_property(conn, root, property);
} else { } else {
uint8_t mode = XCB_PROP_MODE_REPLACE; uint8_t mode = XCB_PROP_MODE_REPLACE;
xcb_atom_t type = XCB_ATOM_WINDOW; xcb_atom_t type = XCB_ATOM_WINDOW;
xcb_set_input_focus(conn, XCB_INPUT_FOCUS_PARENT, window, time); xcb_set_input_focus(conn, XCB_INPUT_FOCUS_PARENT, window, time);
xcb_change_property(conn, mode, root, property, type, 32, 1, &window); xcb_change_property(conn, mode, root, property, type, 32, 1, &window);
@@ -449,12 +445,12 @@ static void
backend_restack_windows(backend_t *backend, const effect_window_list_t *list) { backend_restack_windows(backend_t *backend, const effect_window_list_t *list) {
if (list->count == 0) return; if (list->count == 0) return;
xcb_connection_t *conn = backend->conn; xcb_connection_t *conn = backend->conn;
xcb_window_t sibling_window = backend->window_no_focus; xcb_window_t sibling_window = backend->window_no_focus;
for (size_t i = 0; i < list->count; ++i) { for (size_t i = 0; i < list->count; ++i) {
uint16_t mask = XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE; uint16_t mask = XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE;
xcb_configure_window_value_list_t params = { xcb_configure_window_value_list_t params = {
.sibling = sibling_window, .sibling = sibling_window,
.stack_mode = XCB_STACK_MODE_ABOVE .stack_mode = XCB_STACK_MODE_ABOVE
}; };
sibling_window = list->windows[i]; sibling_window = list->windows[i];
@@ -468,7 +464,7 @@ static void window_configure_list_reset(window_configure_list_t *configs) {
} }
static void backend_apply_window_configure_list(backend_t *backend) { static void backend_apply_window_configure_list(backend_t *backend) {
xcb_connection_t *conn = backend->conn; xcb_connection_t *conn = backend->conn;
window_configure_list_t *configs = &backend->config_list; window_configure_list_t *configs = &backend->config_list;
for (size_t i = 0; i < configs->count; ++i) { for (size_t i = 0; i < configs->count; ++i) {
window_configure_t *cfg = &configs->cfgs[i]; window_configure_t *cfg = &configs->cfgs[i];
@@ -489,7 +485,7 @@ find_or_push_configure(window_configure_list_t *configs, xcb_window_t window) {
cfg = array_push(configs->cfgs, configs->count, configs->capacity); cfg = array_push(configs->cfgs, configs->count, configs->capacity);
p_clear(cfg, 1); p_clear(cfg, 1);
cfg->window = window; cfg->window = window;
cfg->mask = 0; cfg->mask = 0;
return cfg; return cfg;
} }
@@ -501,8 +497,8 @@ static void merge_window_configure_params(
#define FIELD_MERGE(MASK, VALUE_FIELD, DATA_FIELD) \ #define FIELD_MERGE(MASK, VALUE_FIELD, DATA_FIELD) \
if (data->changed_fields & (MASK)) { \ if (data->changed_fields & (MASK)) { \
cfg->mask |= (MASK); \ cfg->mask |= (MASK); \
cfg->value.VALUE_FIELD = data->DATA_FIELD; \ cfg->value.VALUE_FIELD = data->DATA_FIELD; \
} }
FIELD_MERGE(ZDWM_CONFIGURE_FIELD_X, x, x); FIELD_MERGE(ZDWM_CONFIGURE_FIELD_X, x, x);
@@ -526,13 +522,13 @@ static void backend_grab_button(
backend_t *backend, backend_t *backend,
const effect_grab_button_t *grab_button const effect_grab_button_t *grab_button
) { ) {
auto conn = backend->conn; auto conn = backend->conn;
auto window = grab_button->window; auto window = grab_button->window;
xcb_ungrab_button(conn, XCB_BUTTON_INDEX_ANY, window, XCB_MOD_MASK_ANY); xcb_ungrab_button(conn, XCB_BUTTON_INDEX_ANY, window, XCB_MOD_MASK_ANY);
auto buttons = grab_button->buttons; auto buttons = grab_button->buttons;
for (size_t i = 0; i < grab_button->count; ++i) { for (size_t i = 0; i < grab_button->count; ++i) {
auto button = buttons[i].button; auto button = buttons[i].button;
auto modifiers = buttons[i].modifiers; auto modifiers = buttons[i].modifiers;
window_grab_button(backend, window, button, modifiers); window_grab_button(backend, window, button, modifiers);
} }
@@ -543,9 +539,9 @@ static void backend_grab_pointer(backend_t *backend, cursor_t cursor) {
auto root = backend->screen->root; auto root = backend->screen->root;
auto mask = XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE | auto mask = XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE |
XCB_EVENT_MASK_POINTER_MOTION; XCB_EVENT_MASK_POINTER_MOTION;
auto mode = XCB_GRAB_MODE_ASYNC; auto mode = XCB_GRAB_MODE_ASYNC;
auto xcursor = cursor_get_xcb_cursor(backend, cursor); auto xcursor = cursor_get_xcb_cursor(backend, cursor);
auto time = XCB_TIME_CURRENT_TIME; auto time = XCB_TIME_CURRENT_TIME;
xcb_grab_pointer(conn, false, root, mask, mode, mode, root, xcursor, time); xcb_grab_pointer(conn, false, root, mask, mode, mode, root, xcursor, time);
} }
@@ -584,7 +580,7 @@ static void backend_merge_effects(
backend_grab_pointer(backend, ZDWM_CURSOR_RESIZE); backend_grab_pointer(backend, ZDWM_CURSOR_RESIZE);
break; break;
case ZDWM_EFFECT_MINIMIZE_WINDOW: { case ZDWM_EFFECT_MINIMIZE_WINDOW: {
auto window = e->as.minimize.window; auto window = e->as.minimize.window;
xcb_icccm_wm_state_t state = XCB_ICCCM_WM_STATE_NORMAL; xcb_icccm_wm_state_t state = XCB_ICCCM_WM_STATE_NORMAL;
if (e->as.minimize.value) state = XCB_ICCCM_WM_STATE_ICONIC; if (e->as.minimize.value) state = XCB_ICCCM_WM_STATE_ICONIC;
window_set_icccm_wm_state(backend->conn, window, state); window_set_icccm_wm_state(backend->conn, window, state);
@@ -697,10 +693,10 @@ bool backend_apply_effect(
} }
backend_scan_result_t *backend_scan_windows(backend_t *backend) { backend_scan_result_t *backend_scan_windows(backend_t *backend) {
auto conn = backend->conn; auto conn = backend->conn;
auto root = backend->screen->root; auto root = backend->screen->root;
auto cookie = xcb_query_tree_unchecked(conn, root); auto cookie = xcb_query_tree_unchecked(conn, root);
auto reply = xcb_query_tree_reply(conn, cookie, nullptr); auto reply = xcb_query_tree_reply(conn, cookie, nullptr);
if (!reply) return nullptr; if (!reply) return nullptr;
auto length = xcb_query_tree_children_length(reply); auto length = xcb_query_tree_children_length(reply);
@@ -711,20 +707,20 @@ backend_scan_result_t *backend_scan_windows(backend_t *backend) {
auto list = xcb_query_tree_children(reply); auto list = xcb_query_tree_children(reply);
auto result = p_new(backend_scan_result_t, 1); auto result = p_new(backend_scan_result_t, 1);
auto sub_result = p_new(backend_scan_result_t, 1); auto sub_result = p_new(backend_scan_result_t, 1);
for (typeof(length) i = 0; i < length; ++i) { for (typeof(length) i = 0; i < length; ++i) {
auto window = list[i]; auto window = list[i];
auto wa = window_get_attributes(backend, window); auto wa = window_get_attributes(backend, window);
if (!wa) continue; if (!wa) continue;
auto override_redirect = wa->override_redirect; auto override_redirect = wa->override_redirect;
auto map_state = wa->map_state; auto map_state = wa->map_state;
p_delete(&wa); p_delete(&wa);
if (override_redirect) continue; if (override_redirect) continue;
auto hints = (xcb_icccm_wm_hints_t){0}; auto hints = (xcb_icccm_wm_hints_t){0};
auto hints_getted = window_get_wm_hints(backend, window, &hints); auto hints_getted = window_get_wm_hints(backend, window, &hints);
if (!(map_state == XCB_MAP_STATE_VIEWABLE || if (!(map_state == XCB_MAP_STATE_VIEWABLE ||
(hints_getted && hints.initial_state == XCB_ICCCM_WM_STATE_ICONIC))) { (hints_getted && hints.initial_state == XCB_ICCCM_WM_STATE_ICONIC))) {
@@ -732,10 +728,11 @@ backend_scan_result_t *backend_scan_windows(backend_t *backend) {
} }
auto transient_for = window_get_transient_for(backend, window); auto transient_for = window_get_transient_for(backend, window);
auto r = transient_for == XCB_WINDOW_NONE ? result : sub_result; auto r = transient_for == XCB_WINDOW_NONE ? result : sub_result;
auto slot = array_push(r->windows, r->count, r->capacity); auto slot = array_push(r->windows, r->count, r->capacity);
if (!populate_window_event(backend, list[i], slot) || if (
slot->override_redirect) { !populate_window_event(backend, list[i], slot) || slot->override_redirect
) {
window_layer_props_cleanup(&slot->props); window_layer_props_cleanup(&slot->props);
window_metadata_cleanup(&slot->metadata); window_metadata_cleanup(&slot->metadata);
r->count--; r->count--;
@@ -746,7 +743,7 @@ backend_scan_result_t *backend_scan_windows(backend_t *backend) {
for (size_t i = 0; i < sub_result->count; ++i) { for (size_t i = 0; i < sub_result->count; ++i) {
auto slot = array_push(result->windows, result->count, result->capacity); auto slot = array_push(result->windows, result->count, result->capacity);
*slot = sub_result->windows[i]; *slot = sub_result->windows[i];
} }
p_clear(sub_result->windows, sub_result->count); p_clear(sub_result->windows, sub_result->count);
@@ -779,13 +776,13 @@ backend_bar_window_t backend_create_bar_window(
rect_t geometry, rect_t geometry,
uint32_t bg_pixel uint32_t bg_pixel
) { ) {
auto conn = backend->conn; auto conn = backend->conn;
auto root = backend->screen->root; auto root = backend->screen->root;
auto visual = window_get_visual(backend, true); auto visual = window_get_visual(backend, true);
static xcb_colormap_t colormap = XCB_NONE; static xcb_colormap_t colormap = XCB_NONE;
if (colormap == XCB_NONE) { if (colormap == XCB_NONE) {
colormap = xcb_generate_id(conn); colormap = xcb_generate_id(conn);
uint8_t alloc = XCB_COLORMAP_ALLOC_NONE; uint8_t alloc = XCB_COLORMAP_ALLOC_NONE;
xcb_create_colormap(conn, alloc, colormap, root, visual->visual->visual_id); xcb_create_colormap(conn, alloc, colormap, root, visual->visual->visual_id);
} }
@@ -793,18 +790,18 @@ backend_bar_window_t backend_create_bar_window(
window_clean_event_mask(conn, root); window_clean_event_mask(conn, root);
xcb_grab_server(conn); xcb_grab_server(conn);
auto window_id = xcb_generate_id(conn); auto window_id = xcb_generate_id(conn);
uint16_t _class = XCB_WINDOW_CLASS_INPUT_OUTPUT; uint16_t _class = XCB_WINDOW_CLASS_INPUT_OUTPUT;
uint32_t value_mask = XCB_CW_OVERRIDE_REDIRECT | XCB_CW_BACK_PIXEL | uint32_t value_mask = XCB_CW_OVERRIDE_REDIRECT | XCB_CW_BACK_PIXEL |
XCB_CW_BORDER_PIXEL | XCB_CW_EVENT_MASK | XCB_CW_BORDER_PIXEL | XCB_CW_EVENT_MASK |
XCB_CW_COLORMAP; XCB_CW_COLORMAP;
const xcb_create_window_value_list_t value_list = { const xcb_create_window_value_list_t value_list = {
.override_redirect = true, .override_redirect = true,
.background_pixel = bg_pixel, .background_pixel = bg_pixel,
.border_pixel = 0, .border_pixel = 0,
.event_mask = XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_EXPOSURE, .event_mask = XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_EXPOSURE,
.colormap = colormap, .colormap = colormap,
}; };
auto cookie = xcb_create_window_aux_checked( auto cookie = xcb_create_window_aux_checked(
conn, conn,
@@ -833,11 +830,11 @@ backend_bar_window_t backend_create_bar_window(
root_set_event_mask(backend); root_set_event_mask(backend);
xcb_aux_sync(conn); xcb_aux_sync(conn);
auto width = geometry.width; auto width = geometry.width;
auto height = geometry.height; auto height = geometry.height;
auto vid = visual->visual; auto vid = visual->visual;
auto surface = cairo_xcb_surface_create(conn, window_id, vid, width, height); auto surface = cairo_xcb_surface_create(conn, window_id, vid, width, height);
auto cr = cairo_create(surface); auto cr = cairo_create(surface);
cairo_surface_destroy(surface); cairo_surface_destroy(surface);
p_delete(&visual); p_delete(&visual);

View File

@@ -5,7 +5,7 @@
#include <xcb/xproto.h> #include <xcb/xproto.h>
#include "base/macros.h" #include "base/macros.h"
#include "core/types.h" #include "interface/types.h"
typedef struct modifier_map_t { typedef struct modifier_map_t {
modifier_bit_t modifier; modifier_bit_t modifier;

View File

@@ -3,7 +3,7 @@
#include <stdint.h> #include <stdint.h>
#include <xcb/xproto.h> #include <xcb/xproto.h>
#include "core/types.h" #include "interface/types.h"
modifier_mask_t modifiers_xcb_to_zdwm(uint16_t mask); modifier_mask_t modifiers_xcb_to_zdwm(uint16_t mask);
uint16_t modifiers_zdwm_to_xcb(modifier_mask_t mask); uint16_t modifiers_zdwm_to_xcb(modifier_mask_t mask);

View File

@@ -8,14 +8,14 @@
static const char *const cursor_name_map[] = { static const char *const cursor_name_map[] = {
[ZDWM_CURSOR_NORMAL] = "left_ptr", [ZDWM_CURSOR_NORMAL] = "left_ptr",
[ZDWM_CURSOR_MOVE] = "fleur", [ZDWM_CURSOR_MOVE] = "fleur",
[ZDWM_CURSOR_RESIZE] = "bottom_right_corner", [ZDWM_CURSOR_RESIZE] = "bottom_right_corner",
}; };
static xcb_cursor_context_t *get_xcb_cursor_context(backend_t *backend) { static xcb_cursor_context_t *get_xcb_cursor_context(backend_t *backend) {
if (backend->cursor_context) return backend->cursor_context; if (backend->cursor_context) return backend->cursor_context;
auto conn = backend->conn; auto conn = backend->conn;
auto screen = backend->screen; auto screen = backend->screen;
if (xcb_cursor_context_new(conn, screen, &backend->cursor_context) == 0) { if (xcb_cursor_context_new(conn, screen, &backend->cursor_context) == 0) {
return backend->cursor_context; return backend->cursor_context;
@@ -29,7 +29,7 @@ void cursor_init(backend_t *backend) {
if (!ctx) return; if (!ctx) return;
for (size_t i = 0; i < countof(backend->cursors); ++i) { for (size_t i = 0; i < countof(backend->cursors); ++i) {
auto cursor_name = cursor_name_map[i]; auto cursor_name = cursor_name_map[i];
backend->cursors[i] = xcb_cursor_load_cursor(ctx, cursor_name); backend->cursors[i] = xcb_cursor_load_cursor(ctx, cursor_name);
} }
} }

View File

@@ -1,4 +1,4 @@
#include "core/event.h" #include "common/event.h"
#include <assert.h> #include <assert.h>
#include <stdint.h> #include <stdint.h>
@@ -12,9 +12,8 @@
#include "backend/x11/common.h" #include "backend/x11/common.h"
#include "backend/x11/window.h" #include "backend/x11/window.h"
#include "base/memory.h" #include "base/memory.h"
#include "core/backend.h" #include "interface/backend.h"
#include "core/types.h" #include "interface/event.h"
#include "core/window.h"
#include "internal.h" #include "internal.h"
static window_state_t *derive_window_states( static window_state_t *derive_window_states(
@@ -28,7 +27,7 @@ static window_state_t *derive_window_states(
return nullptr; return nullptr;
} }
window_state_t *buf = p_new(window_state_t, count); window_state_t *buf = p_new(window_state_t, count);
size_t valid = 0; size_t valid = 0;
for (uint32_t i = 0; i < count; i++) { for (uint32_t i = 0; i < count; i++) {
window_state_t s = atom_to_window_state(atoms, raw[i]); window_state_t s = atom_to_window_state(atoms, raw[i]);
if (s != (window_state_t)-1) buf[valid++] = s; if (s != (window_state_t)-1) buf[valid++] = s;
@@ -58,8 +57,10 @@ static bool maximized_from_states(
uint32_t state_count uint32_t state_count
) { ) {
for (uint32_t i = 0; i < state_count; i++) { for (uint32_t i = 0; i < state_count; i++) {
if (state_atoms[i] == atoms->_NET_WM_STATE_MAXIMIZED_VERT || if (
state_atoms[i] == atoms->_NET_WM_STATE_MAXIMIZED_HORZ) state_atoms[i] == atoms->_NET_WM_STATE_MAXIMIZED_VERT ||
state_atoms[i] == atoms->_NET_WM_STATE_MAXIMIZED_HORZ
)
return true; return true;
} }
return false; return false;
@@ -101,11 +102,11 @@ static void parse_size_hints(
*max = (zdwm_size_t){.width = INT32_MAX, .height = INT32_MAX}; *max = (zdwm_size_t){.width = INT32_MAX, .height = INT32_MAX};
if (hints->flags & XCB_ICCCM_SIZE_HINT_P_MIN_SIZE) { if (hints->flags & XCB_ICCCM_SIZE_HINT_P_MIN_SIZE) {
min->width = hints->min_width; min->width = hints->min_width;
min->height = hints->min_height; min->height = hints->min_height;
} }
if (hints->flags & XCB_ICCCM_SIZE_HINT_P_MAX_SIZE) { if (hints->flags & XCB_ICCCM_SIZE_HINT_P_MAX_SIZE) {
max->width = hints->max_width; max->width = hints->max_width;
max->height = hints->max_height; max->height = hints->max_height;
} }
} }
@@ -115,7 +116,7 @@ bool populate_window_event(
xcb_window_t window, xcb_window_t window,
window_map_request_event_t *ev window_map_request_event_t *ev
) { ) {
ev->window = (window_id_t)window; ev->window = (window_id_t)window;
ev->transient_for = window_get_transient_for(backend, window); ev->transient_for = window_get_transient_for(backend, window);
auto wa = window_get_attributes(backend, window); auto wa = window_get_attributes(backend, window);
@@ -125,7 +126,7 @@ bool populate_window_event(
xcb_icccm_wm_hints_t wm_hints = {0}; xcb_icccm_wm_hints_t wm_hints = {0};
if (window_get_wm_hints(backend, window, &wm_hints)) { if (window_get_wm_hints(backend, window, &wm_hints)) {
ev->urgent = (bool)xcb_icccm_wm_hints_get_urgency(&wm_hints); ev->urgent = (bool)xcb_icccm_wm_hints_get_urgency(&wm_hints);
ev->minimized = wm_hints.initial_state == XCB_ICCCM_WM_STATE_ICONIC; ev->minimized = wm_hints.initial_state == XCB_ICCCM_WM_STATE_ICONIC;
} }
@@ -135,9 +136,9 @@ bool populate_window_event(
if (!window_get_geometry(backend, window, &ev->rect)) return false; if (!window_get_geometry(backend, window, &ev->rect)) return false;
const atoms_t *atoms = &backend->atoms; const atoms_t *atoms = &backend->atoms;
xcb_atom_t *state_atoms = nullptr; xcb_atom_t *state_atoms = nullptr;
uint32_t state_count = 0; uint32_t state_count = 0;
if (!window_get_atom_array( if (!window_get_atom_array(
backend, backend,
window, window,
@@ -149,8 +150,8 @@ bool populate_window_event(
} }
if (state_atoms) { if (state_atoms) {
ev->maximized = maximized_from_states(atoms, state_atoms, state_count); ev->maximized = maximized_from_states(atoms, state_atoms, state_count);
ev->fullscreen = fullscreen_from_states(atoms, state_atoms, state_count); ev->fullscreen = fullscreen_from_states(atoms, state_atoms, state_count);
ev->skip_taskbar = derive_skip_taskbar(atoms, state_atoms, state_count); ev->skip_taskbar = derive_skip_taskbar(atoms, state_atoms, state_count);
ev->props.states = derive_window_states( ev->props.states = derive_window_states(
atoms, atoms,
@@ -171,7 +172,7 @@ bool populate_window_event(
return false; return false;
} }
ev->metadata.role = window_get_role(backend, window); ev->metadata.role = window_get_role(backend, window);
ev->metadata.title = window_get_title(backend, window); ev->metadata.title = window_get_title(backend, window);
window_get_class( window_get_class(
backend, backend,
@@ -201,7 +202,7 @@ static bool handle_unmap_notify(
event_t *event, event_t *event,
const xcb_unmap_notify_event_t *xcb_event const xcb_unmap_notify_event_t *xcb_event
) { ) {
event->type = ZDWM_EVENT_WINDOW_REMOVE; event->type = ZDWM_EVENT_WINDOW_REMOVE;
event->as.window_remove.window = xcb_event->window; event->as.window_remove.window = xcb_event->window;
if (XCB_EVENT_SENT(xcb_event)) { if (XCB_EVENT_SENT(xcb_event)) {
event->as.window_remove.reason = ZDWM_WINDOW_REMOVE_WITHDRAWN; event->as.window_remove.reason = ZDWM_WINDOW_REMOVE_WITHDRAWN;
@@ -217,7 +218,7 @@ static bool handle_destroy_notify(
event_t *event, event_t *event,
const xcb_destroy_notify_event_t *xcb_event const xcb_destroy_notify_event_t *xcb_event
) { ) {
event->type = ZDWM_EVENT_WINDOW_REMOVE; event->type = ZDWM_EVENT_WINDOW_REMOVE;
event->as.window_remove.window = xcb_event->window; event->as.window_remove.window = xcb_event->window;
event->as.window_remove.reason = ZDWM_WINDOW_REMOVE_DESTROY; event->as.window_remove.reason = ZDWM_WINDOW_REMOVE_DESTROY;
@@ -229,14 +230,14 @@ static bool handle_configure_request(
event_t *event, event_t *event,
const xcb_configure_request_event_t *xcb_event const xcb_configure_request_event_t *xcb_event
) { ) {
event->type = ZDWM_EVENT_CONFIGURE_REQUEST; event->type = ZDWM_EVENT_CONFIGURE_REQUEST;
auto data = &event->as.configure_request; auto data = &event->as.configure_request;
data->window = xcb_event->window; data->window = xcb_event->window;
data->changed_fields = 0u; data->changed_fields = 0u;
#define EXTRACT_FIELD(XCB_MASK, FIELD_MASK, DATA_FIELD, EVENT_FIELD) \ #define EXTRACT_FIELD(XCB_MASK, FIELD_MASK, DATA_FIELD, EVENT_FIELD) \
if (xcb_event->value_mask & XCB_CONFIG_WINDOW_##XCB_MASK) { \ if (xcb_event->value_mask & XCB_CONFIG_WINDOW_##XCB_MASK) { \
data->DATA_FIELD = xcb_event->EVENT_FIELD; \ data->DATA_FIELD = xcb_event->EVENT_FIELD; \
data->changed_fields |= ZDWM_CONFIGURE_FIELD_##FIELD_MASK; \ data->changed_fields |= ZDWM_CONFIGURE_FIELD_##FIELD_MASK; \
} }
@@ -263,9 +264,9 @@ static bool handle_key_press(
/* keysym without any modifiers */ /* keysym without any modifiers */
auto keysym = xcb_key_symbols_get_keysym(backend->key_symbols, keycode, 0); auto keysym = xcb_key_symbols_get_keysym(backend->key_symbols, keycode, 0);
event->type = ZDWM_EVENT_KEY_PRESS; event->type = ZDWM_EVENT_KEY_PRESS;
event->as.key_press.keycode = keycode; event->as.key_press.keycode = keycode;
event->as.key_press.keysym = keysym; event->as.key_press.keysym = keysym;
event->as.key_press.modifiers = modifiers_xcb_to_zdwm(xcb_event->state); event->as.key_press.modifiers = modifiers_xcb_to_zdwm(xcb_event->state);
return true; return true;
@@ -278,10 +279,10 @@ static bool fill_button_event(
auto button = button_xcb_to_zdwm(xcb_event->detail); auto button = button_xcb_to_zdwm(xcb_event->detail);
data->modifiers = modifiers_xcb_to_zdwm(xcb_event->state); data->modifiers = modifiers_xcb_to_zdwm(xcb_event->state);
data->button = button; data->button = button;
data->window = xcb_event->event; data->window = xcb_event->event;
data->root = (point_t){.x = xcb_event->root_x, .y = xcb_event->root_y}; data->root = (point_t){.x = xcb_event->root_x, .y = xcb_event->root_y};
data->local = (point_t){.x = xcb_event->event_x, .y = xcb_event->event_y}; data->local = (point_t){.x = xcb_event->event_x, .y = xcb_event->event_y};
return true; return true;
} }
@@ -291,7 +292,7 @@ static bool handle_button_press(
event_t *event, event_t *event,
const xcb_button_press_event_t *xcb_event const xcb_button_press_event_t *xcb_event
) { ) {
auto press = &event->as.pointer_button_press; auto press = &event->as.pointer_button_press;
auto handled = fill_button_event(xcb_event, press); auto handled = fill_button_event(xcb_event, press);
if (handled) event->type = ZDWM_EVENT_POINTER_BUTTON_PRESS; if (handled) event->type = ZDWM_EVENT_POINTER_BUTTON_PRESS;
@@ -317,10 +318,10 @@ static bool handle_motion_notify(
) { ) {
event->type = ZDWM_EVENT_POINTER_MOTION; event->type = ZDWM_EVENT_POINTER_MOTION;
auto data = &event->as.pointer_motion; auto data = &event->as.pointer_motion;
data->window = xcb_event->event; data->window = xcb_event->event;
data->root = (point_t){.x = xcb_event->root_x, .y = xcb_event->root_y}; data->root = (point_t){.x = xcb_event->root_x, .y = xcb_event->root_y};
data->local = (point_t){.x = xcb_event->event_x, .y = xcb_event->event_y}; data->local = (point_t){.x = xcb_event->event_x, .y = xcb_event->event_y};
return true; return true;
} }
@@ -329,7 +330,7 @@ static bool handle_enter_notify(
event_t *event, event_t *event,
const xcb_enter_notify_event_t *xcb_event const xcb_enter_notify_event_t *xcb_event
) { ) {
event->type = ZDWM_EVENT_POINTER_ENTER; event->type = ZDWM_EVENT_POINTER_ENTER;
event->as.pointer_enter.window = xcb_event->event; event->as.pointer_enter.window = xcb_event->event;
return true; return true;
@@ -341,12 +342,14 @@ static bool handle_property_notify(
const xcb_property_notify_event_t *xcb_event const xcb_property_notify_event_t *xcb_event
) { ) {
auto window_id = xcb_event->window; auto window_id = xcb_event->window;
if (xcb_event->atom == backend->atoms.WM_NAME || if (
xcb_event->atom == backend->atoms._NET_WM_NAME) { xcb_event->atom == backend->atoms.WM_NAME ||
xcb_event->atom == backend->atoms._NET_WM_NAME
) {
event->type = ZDWM_EVENT_WINDOW_METADATA_CHANGED; event->type = ZDWM_EVENT_WINDOW_METADATA_CHANGED;
auto data = &event->as.window_metadata_change; auto data = &event->as.window_metadata_change;
data->window = window_id; data->window = window_id;
data->metadata.title = window_get_title(backend, window_id); data->metadata.title = window_get_title(backend, window_id);
data->changed_fields = ZDWM_WINDOW_METADATA_CHANGE_TITLE; data->changed_fields = ZDWM_WINDOW_METADATA_CHANGE_TITLE;
return true; return true;
@@ -355,9 +358,9 @@ static bool handle_property_notify(
if (xcb_event->atom == backend->atoms.WM_WINDOW_ROLE) { if (xcb_event->atom == backend->atoms.WM_WINDOW_ROLE) {
event->type = ZDWM_EVENT_WINDOW_METADATA_CHANGED; event->type = ZDWM_EVENT_WINDOW_METADATA_CHANGED;
auto data = &event->as.window_metadata_change; auto data = &event->as.window_metadata_change;
data->window = window_id; data->window = window_id;
data->metadata.role = window_get_role(backend, window_id); data->metadata.role = window_get_role(backend, window_id);
data->changed_fields = ZDWM_WINDOW_METADATA_CHANGE_ROLE; data->changed_fields = ZDWM_WINDOW_METADATA_CHANGE_ROLE;
return true; return true;
} }
@@ -365,7 +368,7 @@ static bool handle_property_notify(
if (xcb_event->atom == XCB_ATOM_WM_CLASS) { if (xcb_event->atom == XCB_ATOM_WM_CLASS) {
event->type = ZDWM_EVENT_WINDOW_METADATA_CHANGED; event->type = ZDWM_EVENT_WINDOW_METADATA_CHANGED;
auto data = &event->as.window_metadata_change; auto data = &event->as.window_metadata_change;
data->window = window_id; data->window = window_id;
window_get_class( window_get_class(
backend, backend,
@@ -384,11 +387,11 @@ static bool handle_property_notify(
event->type = ZDWM_EVENT_WINDOW_HINTS_CHANGED; event->type = ZDWM_EVENT_WINDOW_HINTS_CHANGED;
auto data = &event->as.hints; auto data = &event->as.hints;
data->window = window_id; data->window = window_id;
if (hints.flags & XCB_ICCCM_WM_HINT_X_URGENCY) { if (hints.flags & XCB_ICCCM_WM_HINT_X_URGENCY) {
data->changed_fields |= ZDWM_HINT_FIELD_URGENT; data->changed_fields |= ZDWM_HINT_FIELD_URGENT;
data->urgent = xcb_icccm_wm_hints_get_urgency(&hints); data->urgent = xcb_icccm_wm_hints_get_urgency(&hints);
return true; return true;
} }
return false; return false;
@@ -400,7 +403,7 @@ static bool handle_property_notify(
event->type = ZDWM_EVENT_WINDOW_HINTS_CHANGED; event->type = ZDWM_EVENT_WINDOW_HINTS_CHANGED;
auto data = &event->as.hints; auto data = &event->as.hints;
data->window = window_id; data->window = window_id;
data->changed_fields |= ZDWM_HINT_FIELD_SIZE; data->changed_fields |= ZDWM_HINT_FIELD_SIZE;
@@ -427,7 +430,7 @@ static bool handle_client_message(
if (xcb_event->type == atoms->WM_CHANGE_STATE) { if (xcb_event->type == atoms->WM_CHANGE_STATE) {
if (xcb_event->data.data32[0] == XCB_ICCCM_WM_STATE_ICONIC) { if (xcb_event->data.data32[0] == XCB_ICCCM_WM_STATE_ICONIC) {
event->type = ZDWM_EVENT_WINDOW_STATE_REQUEST; event->type = ZDWM_EVENT_WINDOW_STATE_REQUEST;
event->as.window_state_request.window = xcb_event->window; event->as.window_state_request.window = xcb_event->window;
event->as.window_state_request.type = ZDWM_WINDOW_STATE_REQUEST_MINIMIZED; event->as.window_state_request.type = ZDWM_WINDOW_STATE_REQUEST_MINIMIZED;
event->as.window_state_request.action = ZDWM_WINDOW_STATE_ACTION_ADD; event->as.window_state_request.action = ZDWM_WINDOW_STATE_ACTION_ADD;
@@ -437,8 +440,8 @@ static bool handle_client_message(
} }
if (xcb_event->type == atoms->_NET_WM_STATE) { if (xcb_event->type == atoms->_NET_WM_STATE) {
event->type = ZDWM_EVENT_WINDOW_STATE_REQUEST; event->type = ZDWM_EVENT_WINDOW_STATE_REQUEST;
auto data = &event->as.window_state_request; auto data = &event->as.window_state_request;
data->window = xcb_event->window; data->window = xcb_event->window;
/** /**
* _NET_WM_STATE 协议数据格式为 * _NET_WM_STATE 协议数据格式为
@@ -467,7 +470,7 @@ static bool handle_client_message(
break; break;
} }
auto properties = &xcb_event->data.data32[1]; auto properties = &xcb_event->data.data32[1];
uint32_t count = 2; uint32_t count = 2;
if (maximized_from_states(atoms, properties, count)) { if (maximized_from_states(atoms, properties, count)) {
data->type = ZDWM_WINDOW_STATE_REQUEST_MAXIMIZED; data->type = ZDWM_WINDOW_STATE_REQUEST_MAXIMIZED;
@@ -484,9 +487,9 @@ static bool handle_client_message(
} }
if (urgent_from_states(atoms, properties, count)) { if (urgent_from_states(atoms, properties, count)) {
event->type = ZDWM_EVENT_WINDOW_HINTS_CHANGED; event->type = ZDWM_EVENT_WINDOW_HINTS_CHANGED;
event->as.hints = (typeof(event->as.hints)){ event->as.hints = (typeof(event->as.hints)){
.urgent = true, .urgent = true,
.changed_fields = ZDWM_HINT_FIELD_URGENT, .changed_fields = ZDWM_HINT_FIELD_URGENT,
}; };
return true; return true;
@@ -504,7 +507,7 @@ static bool handle_event(
event_t *event event_t *event
) { ) {
uint8_t response_type = XCB_EVENT_RESPONSE_TYPE(raw_event); uint8_t response_type = XCB_EVENT_RESPONSE_TYPE(raw_event);
bool handled = false; bool handled = false;
auto label = xcb_event_get_label(response_type); auto label = xcb_event_get_label(response_type);
printf("xcb event type: %s[%u]\n", label, response_type); printf("xcb event type: %s[%u]\n", label, response_type);

View File

@@ -7,8 +7,8 @@
#include <xcb/xcb_keysyms.h> #include <xcb/xcb_keysyms.h>
#include <xcb/xproto.h> #include <xcb/xproto.h>
#include "base/window_list.h" #include "common/window.h"
#include "core/event.h" #include "interface/event.h"
#define EWMH_ATOMS(X) \ #define EWMH_ATOMS(X) \
X(_NET_WM_NAME) \ X(_NET_WM_NAME) \

View File

@@ -12,8 +12,6 @@
#include "backend/x11/cursor.h" #include "backend/x11/cursor.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/memory.h" #include "base/memory.h"
#include "core/backend.h"
#include "core/types.h"
#include "internal.h" #include "internal.h"
static char *window_get_text_property( static char *window_get_text_property(
@@ -34,14 +32,16 @@ static char *window_get_text_property(
xcb_get_property_reply(backend->conn, cookie, nullptr); xcb_get_property_reply(backend->conn, cookie, nullptr);
if (!reply) return nullptr; if (!reply) return nullptr;
int length = xcb_get_property_value_length(reply); int length = xcb_get_property_value_length(reply);
char *value = (char *)xcb_get_property_value(reply); char *value = (char *)xcb_get_property_value(reply);
char *text = nullptr; char *text = nullptr;
if (length && reply->format == 8 && if (
(reply->type == XCB_ATOM_STRING || length && reply->format == 8 &&
reply->type == backend->atoms.UTF8_STRING || (reply->type == XCB_ATOM_STRING ||
reply->type == backend->atoms.COMPOUND_TEXT)) { reply->type == backend->atoms.UTF8_STRING ||
reply->type == backend->atoms.COMPOUND_TEXT)
) {
text = p_strndup(value, (size_t)length); text = p_strndup(value, (size_t)length);
} }
@@ -56,10 +56,10 @@ char *window_get_role(backend_t *backend, xcb_window_t window) {
char *window_get_title(backend_t *backend, xcb_window_t window) { char *window_get_title(backend_t *backend, xcb_window_t window) {
xcb_atom_t property = backend->atoms._NET_WM_NAME; xcb_atom_t property = backend->atoms._NET_WM_NAME;
char *name = window_get_text_property(backend, window, property); char *name = window_get_text_property(backend, window, property);
if (!name) { if (!name) {
property = backend->atoms.WM_NAME; property = backend->atoms.WM_NAME;
name = window_get_text_property(backend, window, property); name = window_get_text_property(backend, window, property);
} }
return name; return name;
} }
@@ -134,7 +134,7 @@ bool window_get_types(
size_t *count size_t *count
) { ) {
uint32_t atom_count = 0; uint32_t atom_count = 0;
xcb_atom_t *atoms = nullptr; xcb_atom_t *atoms = nullptr;
if (!window_get_atom_array( if (!window_get_atom_array(
backend, backend,
window, window,
@@ -181,9 +181,9 @@ bool window_get_geometry(backend_t *backend, xcb_window_t window, rect_t *out) {
xcb_get_geometry_reply(backend->conn, cookie, nullptr); xcb_get_geometry_reply(backend->conn, cookie, nullptr);
if (!reply) return false; if (!reply) return false;
out->x = reply->x; out->x = reply->x;
out->y = reply->y; out->y = reply->y;
out->width = reply->width; out->width = reply->width;
out->height = reply->height; out->height = reply->height;
p_delete(&reply); p_delete(&reply);
@@ -215,7 +215,7 @@ bool window_get_atom_array(
*out_atoms = *out_atoms =
p_copy((xcb_atom_t *)xcb_get_property_value(reply), reply->value_len); p_copy((xcb_atom_t *)xcb_get_property_value(reply), reply->value_len);
} else { } else {
*out_len = 0; *out_len = 0;
*out_atoms = nullptr; *out_atoms = nullptr;
} }
@@ -251,7 +251,7 @@ window_send_event(backend_t *backend, xcb_window_t window, xcb_atom_t atom) {
bool exist = false; bool exist = false;
xcb_connection_t *conn = backend->conn; xcb_connection_t *conn = backend->conn;
auto WM_PROTOCOLS = backend->atoms.WM_PROTOCOLS; auto WM_PROTOCOLS = backend->atoms.WM_PROTOCOLS;
xcb_get_property_cookie_t cookie = xcb_get_property_cookie_t cookie =
xcb_icccm_get_wm_protocols_unchecked(conn, window, WM_PROTOCOLS); xcb_icccm_get_wm_protocols_unchecked(conn, window, WM_PROTOCOLS);
@@ -266,10 +266,10 @@ window_send_event(backend_t *backend, xcb_window_t window, xcb_atom_t atom) {
if (exist) { if (exist) {
xcb_client_message_event_t ev = { xcb_client_message_event_t ev = {
.response_type = XCB_CLIENT_MESSAGE, .response_type = XCB_CLIENT_MESSAGE,
.format = 32, .format = 32,
.window = window, .window = window,
.type = WM_PROTOCOLS, .type = WM_PROTOCOLS,
.data.data32 = {atom, XCB_CURRENT_TIME}, .data.data32 = {atom, XCB_CURRENT_TIME},
}; };
xcb_send_event(conn, false, window, XCB_EVENT_MASK_NO_EVENT, (char *)&ev); xcb_send_event(conn, false, window, XCB_EVENT_MASK_NO_EVENT, (char *)&ev);
} }
@@ -288,9 +288,9 @@ void window_kill(backend_t *backend, xcb_window_t window) {
} }
void root_set_event_mask(backend_t *backend) { void root_set_event_mask(backend_t *backend) {
xcb_connection_t *conn = backend->conn; xcb_connection_t *conn = backend->conn;
xcb_window_t root = backend->screen->root; xcb_window_t root = backend->screen->root;
xcb_cw_t change_mask = XCB_CW_EVENT_MASK; xcb_cw_t change_mask = XCB_CW_EVENT_MASK;
xcb_change_window_attributes_value_list_t value_list = { xcb_change_window_attributes_value_list_t value_list = {
.event_mask = .event_mask =
XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_KEY_PRESS, XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_KEY_PRESS,
@@ -299,7 +299,7 @@ void root_set_event_mask(backend_t *backend) {
} }
void window_set_event_mask(xcb_connection_t *conn, xcb_window_t window) { void window_set_event_mask(xcb_connection_t *conn, xcb_window_t window) {
xcb_cw_t change_mask = XCB_CW_EVENT_MASK; xcb_cw_t change_mask = XCB_CW_EVENT_MASK;
xcb_change_window_attributes_value_list_t value_list = { xcb_change_window_attributes_value_list_t value_list = {
.event_mask = XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_FOCUS_CHANGE | .event_mask = XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_FOCUS_CHANGE |
XCB_EVENT_MASK_PROPERTY_CHANGE | XCB_EVENT_MASK_PROPERTY_CHANGE |
@@ -310,7 +310,7 @@ void window_set_event_mask(xcb_connection_t *conn, xcb_window_t window) {
} }
void window_clean_event_mask(xcb_connection_t *conn, xcb_window_t window) { void window_clean_event_mask(xcb_connection_t *conn, xcb_window_t window) {
xcb_cw_t change_mask = XCB_CW_EVENT_MASK; xcb_cw_t change_mask = XCB_CW_EVENT_MASK;
xcb_change_window_attributes_value_list_t value_list = { xcb_change_window_attributes_value_list_t value_list = {
.event_mask = XCB_EVENT_MASK_NO_EVENT, .event_mask = XCB_EVENT_MASK_NO_EVENT,
}; };
@@ -385,7 +385,7 @@ void window_grab_keys(
const key_bind_t *keys, const key_bind_t *keys,
size_t count size_t count
) { ) {
auto conn = backend->conn; auto conn = backend->conn;
auto key_symbols = backend->key_symbols; auto key_symbols = backend->key_symbols;
xcb_ungrab_key(conn, XCB_GRAB_ANY, window, XCB_MOD_MASK_ANY); xcb_ungrab_key(conn, XCB_GRAB_ANY, window, XCB_MOD_MASK_ANY);
@@ -393,7 +393,7 @@ void window_grab_keys(
xcb_grab_mode_t mode = XCB_GRAB_MODE_ASYNC; xcb_grab_mode_t mode = XCB_GRAB_MODE_ASYNC;
for (size_t i = 0; i < count; ++i) { for (size_t i = 0; i < count; ++i) {
auto key = &keys[i]; auto key = &keys[i];
auto keycodes = xcb_key_symbols_get_keycode(key_symbols, key->keysym); auto keycodes = xcb_key_symbols_get_keycode(key_symbols, key->keysym);
if (!keycodes) continue; if (!keycodes) continue;
@@ -413,9 +413,9 @@ static visual_t *get_alpha_visual(backend_t *backend) {
auto visual_iter = xcb_depth_visuals_iterator(depth_iter.data); auto visual_iter = xcb_depth_visuals_iterator(depth_iter.data);
for (; visual_iter.rem; xcb_visualtype_next(&visual_iter)) { for (; visual_iter.rem; xcb_visualtype_next(&visual_iter)) {
if (visual_iter.data->_class == XCB_VISUAL_CLASS_TRUE_COLOR) { if (visual_iter.data->_class == XCB_VISUAL_CLASS_TRUE_COLOR) {
auto visual = p_new(visual_t, 1); auto visual = p_new(visual_t, 1);
visual->visual = visual_iter.data; visual->visual = visual_iter.data;
visual->depth = depth_iter.data->depth; visual->depth = depth_iter.data->depth;
return visual; return visual;
} }
} }
@@ -426,14 +426,14 @@ static visual_t *get_alpha_visual(backend_t *backend) {
static visual_t *get_root_visual(backend_t *backend) { static visual_t *get_root_visual(backend_t *backend) {
auto depth_iter = xcb_screen_allowed_depths_iterator(backend->screen); auto depth_iter = xcb_screen_allowed_depths_iterator(backend->screen);
auto visual_id = backend->screen->root_visual; auto visual_id = backend->screen->root_visual;
for (; depth_iter.rem; xcb_depth_next(&depth_iter)) { for (; depth_iter.rem; xcb_depth_next(&depth_iter)) {
auto visual_iter = xcb_depth_visuals_iterator(depth_iter.data); auto visual_iter = xcb_depth_visuals_iterator(depth_iter.data);
for (; visual_iter.rem; xcb_visualtype_next(&visual_iter)) { for (; visual_iter.rem; xcb_visualtype_next(&visual_iter)) {
if (visual_iter.data->visual_id == visual_id) { if (visual_iter.data->visual_id == visual_id) {
auto visual = p_new(visual_t, 1); auto visual = p_new(visual_t, 1);
visual->visual = visual_iter.data; visual->visual = visual_iter.data;
visual->depth = depth_iter.data->depth; visual->depth = depth_iter.data->depth;
return visual; return visual;
} }
} }
@@ -456,7 +456,7 @@ void window_change_cursor(
xcb_window_t window, xcb_window_t window,
cursor_t cursor cursor_t cursor
) { ) {
auto conn = backend->conn; auto conn = backend->conn;
xcb_params_cw_t params = {.cursor = cursor_get_xcb_cursor(backend, cursor)}; xcb_params_cw_t params = {.cursor = cursor_get_xcb_cursor(backend, cursor)};
xcb_aux_change_window_attributes(conn, window, XCB_CW_CURSOR, &params); xcb_aux_change_window_attributes(conn, window, XCB_CW_CURSOR, &params);
} }

View File

@@ -8,7 +8,7 @@
#include <xcb/xproto.h> #include <xcb/xproto.h>
#include "base/app.h" #include "base/app.h"
#include "core/backend.h" #include "interface/backend.h"
#include "internal.h" #include "internal.h"
typedef struct atoms_t atoms_t; typedef struct atoms_t atoms_t;

View File

@@ -20,7 +20,6 @@
#include "base/macros.h" #include "base/macros.h"
#include "base/memory.h" #include "base/memory.h"
#include "base/time.h" #include "base/time.h"
#include "core/listeners.h"
static zdwm_bar_item_t *bar_add_item( static zdwm_bar_item_t *bar_add_item(
zdwm_output_id_t output_id, zdwm_output_id_t output_id,
@@ -61,16 +60,16 @@ void bar_output_add_workspace(
listeners_t *listeners listeners_t *listeners
) { ) {
bar_workspace_config_t workspace_config = { bar_workspace_config_t workspace_config = {
.cell_padding = VALUE(config->tag_cell_padding_x, config->padding_x), .cell_padding = VALUE(config->tag_cell_padding_x, config->padding_x),
.indicator_width = VALUE(config->tag_indicator_width, 4), .indicator_width = VALUE(config->tag_indicator_width, 4),
.bg = VALUE(config->tag_bg, config->bg), .bg = VALUE(config->tag_bg, config->bg),
.fg = VALUE(config->tag_fg, config->fg), .fg = VALUE(config->tag_fg, config->fg),
.active_bg = config->tag_active_bg, .active_bg = config->tag_active_bg,
.active_fg = config->tag_active_fg, .active_fg = config->tag_active_fg,
.urgent_bg = config->tag_urgent_bg, .urgent_bg = config->tag_urgent_bg,
.urgent_fg = config->tag_urgent_fg, .urgent_fg = config->tag_urgent_fg,
.layout_bg = VALUE(config->layout_bg, config->bg), .layout_bg = VALUE(config->layout_bg, config->bg),
.layout_fg = VALUE(config->layout_fg, config->fg), .layout_fg = VALUE(config->layout_fg, config->fg),
}; };
auto item = bar_add_item( auto item = bar_add_item(
bar_output->output_id, bar_output->output_id,
@@ -78,7 +77,7 @@ void bar_output_add_workspace(
bar_workspace, bar_workspace,
&workspace_config &workspace_config
); );
item->cell_padding = workspace_config.cell_padding; item->cell_padding = workspace_config.cell_padding;
item->indicator_width = workspace_config.indicator_width; item->indicator_width = workspace_config.indicator_width;
bar_workspace_add_listeners(listeners, item->state); bar_workspace_add_listeners(listeners, item->state);
@@ -92,8 +91,8 @@ static void bar_output_add_binding(
bar_binding_config_t binding_config = { bar_binding_config_t binding_config = {
.show_default = config->binding_show_default, .show_default = config->binding_show_default,
.cell_padding = VALUE(config->binding_padding_x, config->padding_x), .cell_padding = VALUE(config->binding_padding_x, config->padding_x),
.bg = VALUE(config->binding_mode_bg, config->bg), .bg = VALUE(config->binding_mode_bg, config->bg),
.fg = VALUE(config->binding_mode_fg, config->fg), .fg = VALUE(config->binding_mode_fg, config->fg),
}; };
auto item = bar_add_item( auto item = bar_add_item(
bar_output->output_id, bar_output->output_id,
@@ -115,24 +114,24 @@ static void bar_output_add_windows(
bar_windows_config_t window_config = { bar_windows_config_t window_config = {
.cell_padding = VALUE(config->window_padding_x, config->padding_x), .cell_padding = VALUE(config->window_padding_x, config->padding_x),
.bg = VALUE(config->window_bg, config->bg), .bg = VALUE(config->window_bg, config->bg),
.fg = VALUE(config->window_fg, config->fg), .fg = VALUE(config->window_fg, config->fg),
.focused_bg = VALUE(config->window_focused_bg, config->bg), .focused_bg = VALUE(config->window_focused_bg, config->bg),
.focused_fg = VALUE(config->window_focused_fg, config->fg), .focused_fg = VALUE(config->window_focused_fg, config->fg),
}; };
item->cell_padding = window_config.cell_padding; item->cell_padding = window_config.cell_padding;
item->api = bar_windows; item->api = bar_windows;
auto create_state = item->api.create_state; auto create_state = item->api.create_state;
auto output_id = bar_output->output_id; auto output_id = bar_output->output_id;
if (create_state) item->state = create_state(output_id, &window_config); if (create_state) item->state = create_state(output_id, &window_config);
bar_windows_add_listeners(listeners, item->state); bar_windows_add_listeners(listeners, item->state);
} }
void bar_init(bar_t *bar, listeners_t *listeners) { void bar_init(bar_t *bar, listeners_t *listeners) {
auto c = &bar->config; auto c = &bar->config;
bar->ctx = text_context_create(c->font_family, c->font_size, c->dpi); bar->ctx = text_context_create(c->font_family, c->font_size, c->dpi);
for (size_t i = 0; i < bar->count; ++i) { for (size_t i = 0; i < bar->count; ++i) {
@@ -179,8 +178,8 @@ static inline void bar_item_update(zdwm_bar_item_t *item) {
if (!update) return; if (!update) return;
auto update_interval_ms = item->api.update_interval_ms; auto update_interval_ms = item->api.update_interval_ms;
auto last_updated_time = item->last_updated_time; auto last_updated_time = item->last_updated_time;
auto now = time_monotonic_ms(); auto now = time_monotonic_ms();
if (now < last_updated_time + update_interval_ms) return; if (now < last_updated_time + update_interval_ms) return;
item->last_updated_time = now; item->last_updated_time = now;
@@ -204,7 +203,7 @@ void bar_update(bar_t *bar) {
static void bar_output_layout(bar_output_t *bar_output, text_context_t *ctx) { static void bar_output_layout(bar_output_t *bar_output, text_context_t *ctx) {
int32_t start = 0; int32_t start = 0;
auto end = bar_output->width; auto end = bar_output->width;
auto left = &bar_output->left; auto left = &bar_output->left;
for (size_t i = 0; i < left->count; ++i) { for (size_t i = 0; i < left->count; ++i) {
@@ -219,7 +218,7 @@ static void bar_output_layout(bar_output_t *bar_output, text_context_t *ctx) {
bar_x_region_t region = { bar_x_region_t region = {
.start = start, .start = start,
.end = start + width + item->cell_padding * 2, .end = start + width + item->cell_padding * 2,
}; };
bar_cell_set_region(item, j, region); bar_cell_set_region(item, j, region);
@@ -229,25 +228,25 @@ static void bar_output_layout(bar_output_t *bar_output, text_context_t *ctx) {
} }
if (left->count) { if (left->count) {
left->region.start = left->items[0].region.start; left->region.start = left->items[0].region.start;
left->region.end = left->items[left->count - 1].region.end; left->region.end = left->items[left->count - 1].region.end;
} }
auto right = &bar_output->right; auto right = &bar_output->right;
for (size_t i = right->count; i > 0; --i) { for (size_t i = right->count; i > 0; --i) {
auto item_index = i - 1; auto item_index = i - 1;
auto item = &right->items[item_index]; auto item = &right->items[item_index];
item->region.end = end; item->region.end = end;
for (size_t j = item->count; j > 0; --j) { for (size_t j = item->count; j > 0; --j) {
auto cell_index = j - 1; auto cell_index = j - 1;
auto cell = &item->cells[cell_index]; auto cell = &item->cells[cell_index];
int32_t width = 0; int32_t width = 0;
text_context_get_text_size(ctx, cell->text, &width, nullptr); text_context_get_text_size(ctx, cell->text, &width, nullptr);
bar_x_region_t region = { bar_x_region_t region = {
.start = end - width - item->cell_padding * 2, .start = end - width - item->cell_padding * 2,
.end = end, .end = end,
}; };
bar_cell_set_region(item, cell_index, region); bar_cell_set_region(item, cell_index, region);
@@ -257,7 +256,7 @@ static void bar_output_layout(bar_output_t *bar_output, text_context_t *ctx) {
} }
if (right->count) { if (right->count) {
right->region.start = right->items[0].region.start; right->region.start = right->items[0].region.start;
right->region.end = right->items[right->count - 1].region.end; right->region.end = right->items[right->count - 1].region.end;
} }
auto center = &bar_output->center; auto center = &bar_output->center;
@@ -268,7 +267,7 @@ static void bar_output_layout(bar_output_t *bar_output, text_context_t *ctx) {
for (size_t i = 0; i < center->count; ++i) { for (size_t i = 0; i < center->count; ++i) {
bar_x_region_t region = { bar_x_region_t region = {
.start = start, .start = start,
.end = start + width + center->cell_padding * 2, .end = start + width + center->cell_padding * 2,
}; };
start = region.end; start = region.end;
bar_cell_set_region(center, i, region); bar_cell_set_region(center, i, region);
@@ -282,13 +281,13 @@ static void bar_item_draw(
int32_t height int32_t height
) { ) {
for (size_t i = 0; i < item->count; ++i) { for (size_t i = 0; i < item->count; ++i) {
auto cell = &item->cells[i]; auto cell = &item->cells[i];
auto region = &cell->region; auto region = &cell->region;
zdwm_rect_t cell_area = { zdwm_rect_t cell_area = {
.x = region->start, .x = region->start,
.y = 0, .y = 0,
.width = region->end - region->start, .width = region->end - region->start,
.height = height, .height = height,
}; };
if (cell_area.width <= 0) { if (cell_area.width <= 0) {
@@ -300,13 +299,13 @@ static void bar_item_draw(
if (cell->show_indicator) { if (cell->show_indicator) {
auto size = MIN(item->indicator_width, cell_area.width); auto size = MIN(item->indicator_width, cell_area.width);
size = MIN(size, height); size = MIN(size, height);
if (size > 0) { if (size > 0) {
zdwm_rect_t indicator_area = { zdwm_rect_t indicator_area = {
.x = region->start, .x = region->start,
.y = 0, .y = 0,
.width = size, .width = size,
.height = size, .height = size,
}; };
draw_background(cr, &cell->fg, indicator_area); draw_background(cr, &cell->fg, indicator_area);
@@ -314,9 +313,9 @@ static void bar_item_draw(
} }
zdwm_rect_t text_area = { zdwm_rect_t text_area = {
.x = cell_area.x + item->cell_padding, .x = cell_area.x + item->cell_padding,
.y = 0, .y = 0,
.width = cell_area.width - item->cell_padding * 2, .width = cell_area.width - item->cell_padding * 2,
.height = height, .height = height,
}; };
if (text_area.width > 0 && cell->text && cell->text[0] != '\0') { if (text_area.width > 0 && cell->text && cell->text[0] != '\0') {
@@ -368,9 +367,9 @@ bar_output_draw(bar_output_t *bar_output, text_context_t *ctx, color_t *bg) {
clean_cairo_context(cr); clean_cairo_context(cr);
zdwm_rect_t output_area = { zdwm_rect_t output_area = {
.x = 0, .x = 0,
.y = 0, .y = 0,
.width = bar_output->width, .width = bar_output->width,
.height = bar_output->height, .height = bar_output->height,
}; };
draw_background(cr, bg, output_area); draw_background(cr, bg, output_area);
@@ -418,12 +417,12 @@ static inline bool bar_item_click(
auto cell = &item->cells[i]; auto cell = &item->cells[i];
if (cell->region.start <= x && cell->region.end >= x) { if (cell->region.start <= x && cell->region.end >= x) {
zdwm_bar_click_params_t params = { zdwm_bar_click_params_t params = {
.item = item, .item = item,
.cell_index = i, .cell_index = i,
.x = x, .x = x,
.modifiers = info.modifiers, .modifiers = info.modifiers,
.button = info.button, .button = info.button,
.state = item->state, .state = item->state,
}; };
*action = item->api.on_click(&params); *action = item->api.on_click(&params);
return true; return true;

View File

@@ -10,7 +10,7 @@
#include "bar/text.h" #include "bar/text.h"
#include "bar/types.h" #include "bar/types.h"
#include "base/color.h" #include "base/color.h"
#include "core/listeners.h" #include "common/listeners.h"
typedef struct bar_output_t { typedef struct bar_output_t {
cairo_t *cr; cairo_t *cr;

View File

@@ -9,7 +9,7 @@
#include <zdwm/types.h> #include <zdwm/types.h>
#include "base/memory.h" #include "base/memory.h"
#include "core/listeners.h" #include "common/listeners.h"
typedef struct bar_binding_state_t { typedef struct bar_binding_state_t {
zdwm_binding_mode_notify_t mode; zdwm_binding_mode_notify_t mode;
@@ -25,7 +25,7 @@ bar_binding_create_state(zdwm_output_id_t output_id, void *config) {
const bar_binding_config_t *bar_config = config; const bar_binding_config_t *bar_config = config;
assert(bar_config); assert(bar_config);
auto state = p_new(bar_binding_state_t, 1); auto state = p_new(bar_binding_state_t, 1);
state->config = *bar_config; state->config = *bar_config;
return state; return state;
@@ -40,7 +40,7 @@ static void bar_binding_update(
if (!data->inited || !data->dirty) return; if (!data->inited || !data->dirty) return;
auto config = &data->config; auto config = &data->config;
auto mode = &data->mode; auto mode = &data->mode;
if (!config->show_default && mode->is_default_mode) { if (!config->show_default && mode->is_default_mode) {
cells->set_cell_count(item, 0); cells->set_cell_count(item, 0);
@@ -57,7 +57,7 @@ static void bar_binding_update(
static zdwm_action_t bar_binding_on_click(zdwm_bar_click_params_t *params) { static zdwm_action_t bar_binding_on_click(zdwm_bar_click_params_t *params) {
return (zdwm_action_t){ return (zdwm_action_t){
.type = ZDWM_ACTION_BINDING_MODE_CYCLE, .type = ZDWM_ACTION_BINDING_MODE_CYCLE,
.as.binding_mode_cycle = {.delta = 1}, .as.binding_mode_cycle = {.delta = 1},
}; };
} }
@@ -70,10 +70,10 @@ static void bar_binding_destroy_state(void *state) {
} }
zdwm_bar_item_type_t bar_binding = { zdwm_bar_item_type_t bar_binding = {
.create_state = bar_binding_create_state, .create_state = bar_binding_create_state,
.update = bar_binding_update, .update = bar_binding_update,
.on_click = bar_binding_on_click, .on_click = bar_binding_on_click,
.destroy_state = bar_binding_destroy_state, .destroy_state = bar_binding_destroy_state,
.update_interval_ms = 0, .update_interval_ms = 0,
}; };
@@ -84,7 +84,7 @@ bar_binding_mode_notify(zdwm_binding_mode_notify_t mode, void *user_data) {
state->mode = mode; state->mode = mode;
state->inited = true; state->inited = true;
state->dirty = true; state->dirty = true;
return; return;
} }

View File

@@ -3,7 +3,7 @@
#include <stdint.h> #include <stdint.h>
#include <zdwm/bar.h> #include <zdwm/bar.h>
#include "core/listeners.h" #include "common/listeners.h"
typedef struct bar_binding_config_t { typedef struct bar_binding_config_t {
bool show_default; bool show_default;

View File

@@ -78,19 +78,23 @@ static void
bar_cell_set_icon(zdwm_bar_item_t *item, size_t index, zdwm_icon_t icon) { bar_cell_set_icon(zdwm_bar_item_t *item, size_t index, zdwm_icon_t icon) {
if (index >= item->count) return; if (index >= item->count) return;
auto cell = &item->cells[index]; auto cell = &item->cells[index];
auto icon_ptr = &cell->icon; auto icon_ptr = &cell->icon;
if (icon_ptr->type == icon.type) { if (icon_ptr->type == icon.type) {
switch (icon.type) { switch (icon.type) {
case ZDWM_ICON_TEXT: case ZDWM_ICON_TEXT:
if (icon_ptr->as.text == icon.as.text || if (
strcmp(icon_ptr->as.text, icon.as.text) == 0) { icon_ptr->as.text == icon.as.text ||
strcmp(icon_ptr->as.text, icon.as.text) == 0
) {
return; return;
} }
case ZDWM_ICON_IMAGE: case ZDWM_ICON_IMAGE:
if (icon_ptr->as.image_path == icon.as.image_path || if (
strcmp(icon_ptr->as.image_path, icon.as.image_path) == 0) { icon_ptr->as.image_path == icon.as.image_path ||
strcmp(icon_ptr->as.image_path, icon.as.image_path) == 0
) {
return; return;
} }
} }
@@ -115,6 +119,7 @@ bar_cell_set_indicator(zdwm_bar_item_t *item, size_t index, bool show) {
item->dirty = true; item->dirty = true;
} }
/* clang-format off */
zdwm_bar_cell_api_t bar_cell_api = { zdwm_bar_cell_api_t bar_cell_api = {
.get_cell_count = bar_cell_get_count, .get_cell_count = bar_cell_get_count,
.set_cell_count = bar_cell_set_count, .set_cell_count = bar_cell_set_count,
@@ -124,6 +129,7 @@ zdwm_bar_cell_api_t bar_cell_api = {
.cell_set_icon = bar_cell_set_icon, .cell_set_icon = bar_cell_set_icon,
.cell_set_indicator = bar_cell_set_indicator, .cell_set_indicator = bar_cell_set_indicator,
}; };
/* clang-format on */
void bar_cell_set_region( void bar_cell_set_region(
zdwm_bar_item_t *item, zdwm_bar_item_t *item,
@@ -133,7 +139,7 @@ void bar_cell_set_region(
if (index >= item->count) return; if (index >= item->count) return;
auto cell = &item->cells[index]; auto cell = &item->cells[index];
auto r = &cell->region; auto r = &cell->region;
if (r->start == region.start && r->end == region.end) return; if (r->start == region.start && r->end == region.end) return;

View File

@@ -41,10 +41,10 @@ text_context_create(const char *family, uint32_t size, uint32_t dpi) {
g_object_unref(fontmap); g_object_unref(fontmap);
auto ctx = p_new(text_context_t, 1); auto ctx = p_new(text_context_t, 1);
*ctx = (text_context_t){ *ctx = (text_context_t){
.context = context, .context = context,
.layout = layout, .layout = layout,
.attr_list = attr_list, .attr_list = attr_list,
}; };
return ctx; return ctx;

View File

@@ -8,7 +8,7 @@
#include "base/array.h" #include "base/array.h"
#include "base/memory.h" #include "base/memory.h"
#include "core/listeners.h" #include "common/listeners.h"
typedef struct bar_windows_state_t { typedef struct bar_windows_state_t {
zdwm_output_id_t output_id; zdwm_output_id_t output_id;
@@ -39,10 +39,10 @@ bar_windows_create_state(zdwm_output_id_t output_id, void *config) {
const bar_windows_config_t *windows_config = config; const bar_windows_config_t *windows_config = config;
assert(windows_config); assert(windows_config);
auto state = p_new(bar_windows_state_t, 1); auto state = p_new(bar_windows_state_t, 1);
state->output_id = output_id; state->output_id = output_id;
state->workspace_id = ZDWM_WORKSPACE_ID_INVALID; state->workspace_id = ZDWM_WORKSPACE_ID_INVALID;
state->config = *windows_config; state->config = *windows_config;
return state; return state;
} }
@@ -62,14 +62,14 @@ static void bar_windows_update(
if (win->workspace != data->workspace_id || win->skip_taskbar) continue; if (win->workspace != data->workspace_id || win->skip_taskbar) continue;
auto window = array_push(windows, count, capacity); auto window = array_push(windows, count, capacity);
*window = *win; *window = *win;
} }
cells->set_cell_count(item, count); cells->set_cell_count(item, count);
for (size_t i = 0; i < count; ++i) { for (size_t i = 0; i < count; ++i) {
auto window = &windows[i]; auto window = &windows[i];
auto bg = window->focused ? data->config.focused_bg : data->config.bg; auto bg = window->focused ? data->config.focused_bg : data->config.bg;
auto fg = window->focused ? data->config.focused_fg : data->config.fg; auto fg = window->focused ? data->config.focused_fg : data->config.fg;
cells->cell_set_text(item, i, window->title); cells->cell_set_text(item, i, window->title);
cells->cell_set_bg(item, i, bg); cells->cell_set_bg(item, i, bg);
cells->cell_set_fg(item, i, fg); cells->cell_set_fg(item, i, fg);
@@ -87,9 +87,9 @@ static void bar_windows_destroy_state(void *state) {
} }
zdwm_bar_item_type_t bar_windows = { zdwm_bar_item_type_t bar_windows = {
.create_state = bar_windows_create_state, .create_state = bar_windows_create_state,
.update = bar_windows_update, .update = bar_windows_update,
.destroy_state = bar_windows_destroy_state, .destroy_state = bar_windows_destroy_state,
.update_interval_ms = 0, .update_interval_ms = 0,
}; };
@@ -105,14 +105,14 @@ static void bar_windows_workspace_active(
state->workspace_id = workspace_id; state->workspace_id = workspace_id;
state->workspace_inited = true; state->workspace_inited = true;
state->dirty = true; state->dirty = true;
} }
static void static void
bar_windows_add_window(const zdwm_window_t *window, void *user_data) { bar_windows_add_window(const zdwm_window_t *window, void *user_data) {
bar_windows_state_t *state = user_data; bar_windows_state_t *state = user_data;
auto win = array_push(state->windows, state->count, state->capacity); auto win = array_push(state->windows, state->count, state->capacity);
*win = *window; *win = *window;
state->dirty = true; state->dirty = true;
} }
@@ -134,7 +134,7 @@ bar_windows_update_window(const zdwm_window_t *window, void *user_data) {
bar_windows_state_t *state = user_data; bar_windows_state_t *state = user_data;
auto old_window = state_get_window(state, window->id); auto old_window = state_get_window(state, window->id);
*old_window = *window; *old_window = *window;
state->dirty = true; state->dirty = true;
} }
@@ -143,7 +143,7 @@ static void
bar_windows_remove_window(zdwm_window_id_t window_id, void *user_data) { bar_windows_remove_window(zdwm_window_id_t window_id, void *user_data) {
bar_windows_state_t *state = user_data; bar_windows_state_t *state = user_data;
bool found = false; bool found = false;
size_t index = 0; size_t index = 0;
for (size_t i = 0; i < state->count; ++i) { for (size_t i = 0; i < state->count; ++i) {

View File

@@ -3,7 +3,7 @@
#include <stdint.h> #include <stdint.h>
#include <zdwm/bar.h> #include <zdwm/bar.h>
#include "core/listeners.h" #include "common/listeners.h"
typedef struct bar_windows_config_t { typedef struct bar_windows_config_t {
uint32_t cell_padding; uint32_t cell_padding;

View File

@@ -10,7 +10,7 @@
#include "base/array.h" #include "base/array.h"
#include "base/memory.h" #include "base/memory.h"
#include "core/listeners.h" #include "common/listeners.h"
typedef struct bar_workspace_t { typedef struct bar_workspace_t {
zdwm_workspace_t info; zdwm_workspace_t info;
@@ -86,10 +86,10 @@ bar_workspaces_create_state(zdwm_output_id_t output_id, void *config) {
const bar_workspace_config_t *workspace_config = config; const bar_workspace_config_t *workspace_config = config;
assert(workspace_config); assert(workspace_config);
auto state = p_new(bar_workspace_state_t, 1); auto state = p_new(bar_workspace_state_t, 1);
state->output_id = output_id; state->output_id = output_id;
state->workspace_id = ZDWM_WORKSPACE_ID_INVALID; state->workspace_id = ZDWM_WORKSPACE_ID_INVALID;
state->config = *workspace_config; state->config = *workspace_config;
return state; return state;
} }
@@ -109,7 +109,7 @@ static void bar_workspaces_update(
auto config = &data->config; auto config = &data->config;
for (size_t i = 0; i < data->count; ++i) { for (size_t i = 0; i < data->count; ++i) {
auto workspace = &data->workspaces[i]; auto workspace = &data->workspaces[i];
auto info = &workspace->info; auto info = &workspace->info;
workspace->window_count = state_workspace_get_window_count(state, info->id); workspace->window_count = state_workspace_get_window_count(state, info->id);
workspace->urgent_window_count = workspace->urgent_window_count =
@@ -145,11 +145,11 @@ static void bar_workspaces_update(
static zdwm_action_t bar_workspace_on_click(zdwm_bar_click_params_t *params) { static zdwm_action_t bar_workspace_on_click(zdwm_bar_click_params_t *params) {
auto cell_index = params->cell_index; auto cell_index = params->cell_index;
auto data = (bar_workspace_state_t *)params->state; auto data = (bar_workspace_state_t *)params->state;
if (cell_index == data->count) { if (cell_index == data->count) {
return (zdwm_action_t){ return (zdwm_action_t){
.type = ZDWM_ACTION_LAYOUT_CYCLE, .type = ZDWM_ACTION_LAYOUT_CYCLE,
.as.layout_cycle = {.delta = 1}, .as.layout_cycle = {.delta = 1},
}; };
} }
@@ -160,7 +160,7 @@ static zdwm_action_t bar_workspace_on_click(zdwm_bar_click_params_t *params) {
} }
return (zdwm_action_t){ return (zdwm_action_t){
.type = ZDWM_ACTION_WORKSPACE_SWITCH, .type = ZDWM_ACTION_WORKSPACE_SWITCH,
.as.switch_workspace.workspace = workspace->info.id, .as.switch_workspace.workspace = workspace->info.id,
}; };
} }
@@ -175,10 +175,10 @@ static void bar_workspace_destroy_state(void *state) {
} }
zdwm_bar_item_type_t bar_workspace = { zdwm_bar_item_type_t bar_workspace = {
.create_state = bar_workspaces_create_state, .create_state = bar_workspaces_create_state,
.update = bar_workspaces_update, .update = bar_workspaces_update,
.on_click = bar_workspace_on_click, .on_click = bar_workspace_on_click,
.destroy_state = bar_workspace_destroy_state, .destroy_state = bar_workspace_destroy_state,
.update_interval_ms = 0, .update_interval_ms = 0,
}; };
@@ -204,7 +204,7 @@ static void bar_workspace_list_filter(
} }
state->list_inited = true; state->list_inited = true;
state->dirty = true; state->dirty = true;
} }
static void bar_workspace_active_updated( static void bar_workspace_active_updated(
@@ -219,7 +219,7 @@ static void bar_workspace_active_updated(
state->workspace_id = workspace_id; state->workspace_id = workspace_id;
state->active_inited = true; state->active_inited = true;
state->dirty = true; state->dirty = true;
} }
static void static void
@@ -230,7 +230,7 @@ bar_workspace_layout_notify(zdwm_layout_notify_t layout, void *user_data) {
auto workspace = &state->workspaces[i]; auto workspace = &state->workspaces[i];
if (workspace->info.id == layout.workspace) { if (workspace->info.id == layout.workspace) {
workspace->layout = layout; workspace->layout = layout;
state->dirty = true; state->dirty = true;
return; return;
} }
} }
@@ -264,14 +264,14 @@ void bar_workspace_window_updated(
auto state = (bar_workspace_state_t *)user_data; auto state = (bar_workspace_state_t *)user_data;
auto old_window = state_get_window(state, window->id); auto old_window = state_get_window(state, window->id);
*old_window = *window; *old_window = *window;
state->dirty = true; state->dirty = true;
} }
void bar_workspace_window_removed(zdwm_window_id_t window_id, void *user_data) { void bar_workspace_window_removed(zdwm_window_id_t window_id, void *user_data) {
auto state = (bar_workspace_state_t *)user_data; auto state = (bar_workspace_state_t *)user_data;
bool found = false; bool found = false;
size_t index = 0; size_t index = 0;
for (size_t i = 0; i < state->window_count; ++i) { for (size_t i = 0; i < state->window_count; ++i) {

View File

@@ -3,7 +3,7 @@
#include <stdint.h> #include <stdint.h>
#include <zdwm/bar.h> #include <zdwm/bar.h>
#include "core/listeners.h" #include "common/listeners.h"
typedef struct bar_workspace_config_t { typedef struct bar_workspace_config_t {
uint32_t cell_padding; uint32_t cell_padding;

View File

@@ -86,7 +86,7 @@ array_erase_impl(void *items, size_t item_size, size_t *count, size_t index) {
size_t tail_count = *count - index - 1; size_t tail_count = *count - index - 1;
if (tail_count > 0) { if (tail_count > 0) {
char *dest = (char *)items + index * item_size; char *dest = (char *)items + index * item_size;
char *src = dest + item_size; char *src = dest + item_size;
memmove(dest, src, tail_count * item_size); memmove(dest, src, tail_count * item_size);
} }
@@ -98,11 +98,11 @@ array_erase_impl(void *items, size_t item_size, size_t *count, size_t index) {
#define array_reserve(items, capacity, need) \ #define array_reserve(items, capacity, need) \
array_reserve_impl((void **)&(items), sizeof(*(items)), &(capacity), (need)) array_reserve_impl((void **)&(items), sizeof(*(items)), &(capacity), (need))
/* clang-format off */
/** @brief 为具体类型数组追加一个槽位。 */ /** @brief 为具体类型数组追加一个槽位。 */
#define array_push(items, count, capacity) \ #define array_push(items, count, capacity)\
( \ (typeof(items))array_push_impl((void **)&(items), sizeof(*(items)), &(count), &(capacity))
typeof(items) \ /* clang-format on */
)array_push_impl((void **)&(items), sizeof(*(items)), &(count), &(capacity))
/** @brief 删除具体类型数组中指定下标的元素。 */ /** @brief 删除具体类型数组中指定下标的元素。 */
#define array_erase(items, count, index) \ #define array_erase(items, count, index) \

View File

@@ -54,9 +54,9 @@ void color_parse(const char *hex, color_t *const color) {
bool hex_color_to_rgba(const char *hex, uint32_t *rgba) { bool hex_color_to_rgba(const char *hex, uint32_t *rgba) {
if (hex[0] == '#') hex++; if (hex[0] == '#') hex++;
size_t len = strlen(hex); size_t len = strlen(hex);
char extended[9] = {0}; char extended[9] = {0};
uint32_t color = 0x00000000; uint32_t color = 0x00'00'00'00;
if (len == 3 || len == 4) { if (len == 3 || len == 4) {
extended[0] = extended[1] = hex[0]; extended[0] = extended[1] = hex[0];
@@ -76,7 +76,7 @@ bool hex_color_to_rgba(const char *hex, uint32_t *rgba) {
return false; return false;
} }
color = strtoul(extended, nullptr, 16) & 0xffffffff; color = strtoul(extended, nullptr, 16) & 0xff'ff'ff'ff;
*rgba = color; *rgba = color;
return true; return true;
} }
@@ -100,8 +100,8 @@ void extract_color_channel(
double *blue, double *blue,
double *alpha double *alpha
) { ) {
*red = COLOR_SPLIT(rgba, 24); *red = COLOR_SPLIT(rgba, 24);
*green = COLOR_SPLIT(rgba, 16); *green = COLOR_SPLIT(rgba, 16);
*blue = COLOR_SPLIT(rgba, 8); *blue = COLOR_SPLIT(rgba, 8);
*alpha = COLOR_SPLIT(rgba, 0); *alpha = COLOR_SPLIT(rgba, 0);
} }

View File

@@ -1,26 +0,0 @@
#include "base/window_list.h"
#include <zdwm/types.h>
#include "base/array.h"
#include "base/memory.h"
void window_list_push(
window_list_t *window_list,
zdwm_window_id_t window_id
) {
zdwm_window_id_t *window =
array_push(window_list->windows, window_list->count, window_list->capacity);
*window = window_id;
}
void window_list_reset(window_list_t *window_list) {
p_clear(window_list->windows, window_list->capacity);
window_list->count = 0;
}
void window_list_cleanup(window_list_t *window_list) {
p_delete(&window_list->windows);
window_list->count = 0;
window_list->capacity = 0;
}

View File

@@ -1,7 +1,7 @@
#include "core/event.h" #include "interface/event.h"
#include "base/memory.h" #include "base/memory.h"
#include "core/window.h" #include "common/window.h"
void event_cleanup(event_t *event) { void event_cleanup(event_t *event) {
if (!event || event->type == ZDWM_EVENT_NONE) return; if (!event || event->type == ZDWM_EVENT_NONE) return;

6
src/common/event.h Normal file
View File

@@ -0,0 +1,6 @@
#pragma once
#include "interface/event.h"
void event_cleanup(event_t *event);
void event_reset(event_t *event);

107
src/common/listeners.c Normal file
View File

@@ -0,0 +1,107 @@
#include "common/listeners.h"
#include <zdwm/listeners.h>
#include "base/array.h"
#include "base/memory.h"
#define ADD_LISTENER(FIELD) \
auto list = &listeners->FIELD; \
auto item = array_push(list->items, list->count, list->capacity); \
item->fn = fn; \
item->user_data = user_data
void listeners_add_output_listener(
listeners_t *listeners,
zdwm_current_output_id_listener fn,
void *user_data
) {
ADD_LISTENER(output_listeners);
}
void listeners_add_initial_workspace_listener(
listeners_t *listeners,
zdwm_initial_workspace_list fn,
void *user_data
) {
ADD_LISTENER(initial_workspace_listeners);
}
void listeners_add_active_workspace_listener(
listeners_t *listeners,
zdwm_workspace_active_updated fn,
void *user_data
) {
ADD_LISTENER(active_workspace_listeners);
}
void listeners_add_layout_notify(
listeners_t *listeners,
zdwm_layout_notify fn,
void *user_data
) {
ADD_LISTENER(layout_listeners);
}
void listeners_add_binding_mode_notify(
listeners_t *listeners,
zdwm_binding_mode_notify fn,
void *user_data
) {
ADD_LISTENER(binding_mode_listeners);
}
void listeners_add_initial_window_listener(
listeners_t *listeners,
zdwm_initial_window_list fn,
void *user_data
) {
ADD_LISTENER(initial_window_listeners);
}
void listeners_add_window_added_listener(
listeners_t *listeners,
zdwm_window_added fn,
void *user_data
) {
ADD_LISTENER(window_added_listeners);
}
void listeners_add_window_updated_listener(
listeners_t *listeners,
zdwm_window_updated fn,
void *user_data
) {
ADD_LISTENER(window_updated_listeners);
}
void listeners_add_window_removed_listener(
listeners_t *listeners,
zdwm_window_removed fn,
void *user_data
) {
ADD_LISTENER(window_removed_listeners);
}
#undef ADD_LISTENER
#define CLEANUP_LIST(FIELD) \
p_delete(&listeners->FIELD.items); \
listeners->FIELD.count = 0; \
listeners->FIELD.capacity = 0
void listeners_cleanup(listeners_t *listeners) {
if (!listeners) return;
CLEANUP_LIST(output_listeners);
CLEANUP_LIST(initial_workspace_listeners);
CLEANUP_LIST(active_workspace_listeners);
CLEANUP_LIST(layout_listeners);
CLEANUP_LIST(binding_mode_listeners);
CLEANUP_LIST(initial_window_listeners);
CLEANUP_LIST(window_added_listeners);
CLEANUP_LIST(window_updated_listeners);
CLEANUP_LIST(window_removed_listeners);
}
#undef CLEANUP_LIST

94
src/common/listeners.h Normal file
View File

@@ -0,0 +1,94 @@
#pragma once
#include <zdwm/listeners.h>
typedef struct binding_table_t binding_table_t;
typedef struct layout_registry_t layout_registry_t;
typedef struct state_t state_t;
#define ITEM(NAME, FN_TYPE) \
typedef struct NAME##_listener_item_t { \
FN_TYPE *fn; \
void *user_data; \
} NAME##_listener_item_t
#define LISTENERS(NAME, FN_TYPE) \
ITEM(NAME, FN_TYPE); \
typedef struct NAME##_listeners_t { \
NAME##_listener_item_t *items; \
size_t count; \
size_t capacity; \
} NAME##_listeners_t
LISTENERS(output, zdwm_current_output_id_listener);
LISTENERS(initial_workspace_list, zdwm_initial_workspace_list);
LISTENERS(workspace_active, zdwm_workspace_active_updated);
LISTENERS(layout, zdwm_layout_notify);
LISTENERS(binding_mode, zdwm_binding_mode_notify);
LISTENERS(initial_window_list, zdwm_initial_window_list);
LISTENERS(window_added, zdwm_window_added);
LISTENERS(window_updated, zdwm_window_updated);
LISTENERS(window_removed, zdwm_window_removed);
#undef ITEM
#undef LISTENERS
typedef struct listeners_t {
output_listeners_t output_listeners;
initial_workspace_list_listeners_t initial_workspace_listeners;
workspace_active_listeners_t active_workspace_listeners;
layout_listeners_t layout_listeners;
binding_mode_listeners_t binding_mode_listeners;
initial_window_list_listeners_t initial_window_listeners;
window_added_listeners_t window_added_listeners;
window_updated_listeners_t window_updated_listeners;
window_removed_listeners_t window_removed_listeners;
} listeners_t;
void listeners_add_output_listener(
listeners_t *listeners,
zdwm_current_output_id_listener fn,
void *user_data
);
void listeners_add_initial_workspace_listener(
listeners_t *listeners,
zdwm_initial_workspace_list fn,
void *user_data
);
void listeners_add_active_workspace_listener(
listeners_t *listeners,
zdwm_workspace_active_updated fn,
void *user_data
);
void listeners_add_layout_notify(
listeners_t *listeners,
zdwm_layout_notify fn,
void *user_data
);
void listeners_add_binding_mode_notify(
listeners_t *listeners,
zdwm_binding_mode_notify fn,
void *user_data
);
void listeners_add_initial_window_listener(
listeners_t *listeners,
zdwm_initial_window_list fn,
void *user_data
);
void listeners_add_window_added_listener(
listeners_t *listeners,
zdwm_window_added fn,
void *user_data
);
void listeners_add_window_updated_listener(
listeners_t *listeners,
zdwm_window_updated fn,
void *user_data
);
void listeners_add_window_removed_listener(
listeners_t *listeners,
zdwm_window_removed fn,
void *user_data
);
void listeners_cleanup(listeners_t *listeners);

55
src/common/window.c Normal file
View File

@@ -0,0 +1,55 @@
#include "common/window.h"
#include "base/array.h"
#include "base/memory.h"
#include "interface/types.h"
window_layer_type_t window_classify_layer(const window_layer_props_t *props) {
for (size_t i = 0; i < props->type_count; ++i) {
window_type_t type = props->types[i];
if (type == ZDWM_WINDOW_TYPE_NOTIFICATION) return ZDWM_WINDOW_LAYER_OVERLAY;
}
for (size_t i = 0; i < props->state_count; ++i) {
window_state_t state = props->states[i];
if (state == ZDWM_WINDOW_STATE_ABOVE) return ZDWM_WINDOW_LAYER_TOP;
}
return ZDWM_WINDOW_LAYER_NORMAL;
}
void window_layer_props_cleanup(window_layer_props_t *props) {
if (!props) return;
p_delete(&props->types);
props->type_count = 0;
p_delete(&props->states);
props->state_count = 0;
}
void window_metadata_cleanup(window_metadata_t *metadata) {
if (!metadata) return;
p_delete(&metadata->title);
p_delete(&metadata->app_id);
p_delete(&metadata->role);
p_delete(&metadata->class_name);
p_delete(&metadata->instance_name);
}
void window_list_push(window_list_t *window_list, zdwm_window_id_t window_id) {
zdwm_window_id_t *window =
array_push(window_list->windows, window_list->count, window_list->capacity);
*window = window_id;
}
void window_list_reset(window_list_t *window_list) {
p_clear(window_list->windows, window_list->capacity);
window_list->count = 0;
}
void window_list_cleanup(window_list_t *window_list) {
p_delete(&window_list->windows);
window_list->count = 0;
window_list->capacity = 0;
}

View File

@@ -1,7 +1,10 @@
#pragma once #pragma once
#include <stddef.h> #include "interface/types.h"
#include <zdwm/types.h>
window_layer_type_t window_classify_layer(const window_layer_props_t *props);
void window_layer_props_cleanup(window_layer_props_t *props);
void window_metadata_cleanup(window_metadata_t *metadata);
typedef struct window_list_t { typedef struct window_list_t {
zdwm_window_id_t *windows; zdwm_window_id_t *windows;

46
src/common/workspace.c Normal file
View File

@@ -0,0 +1,46 @@
#include "common/workspace.h"
#include "base/memory.h"
void workspace_desc_cleanup(workspace_desc_t *workspace) {
if (!workspace) return;
p_delete(&workspace->name);
p_delete(&workspace->layout_ids);
workspace->output_index = 0;
workspace->layout_count = 0;
workspace->initial_layout_id = ZDWM_LAYOUT_ID_INVALID;
}
void workspace_desc_list_cleanup(workspace_desc_t **list, size_t *count) {
if (!list || !count) return;
for (size_t i = 0; i < *count; i++) {
workspace_desc_cleanup(&(*list)[i]);
}
p_delete(list);
*count = 0;
}
bool workspace_desc_layouts_valid(const workspace_desc_t *workspace) {
if (!workspace || !workspace->layout_count || !workspace->layout_ids) {
return false;
}
for (size_t i = 0; i < workspace->layout_count; i++) {
if (workspace->layout_ids[i] == workspace->initial_layout_id) return true;
}
return false;
}
bool workspace_desc_valid(
const workspace_desc_t *workspace,
size_t output_count
) {
if (!workspace || !workspace->name) return false;
if (workspace->output_index >= output_count) return false;
return workspace_desc_layouts_valid(workspace);
}

21
src/common/workspace.h Normal file
View File

@@ -0,0 +1,21 @@
#pragma once
#include <stddef.h>
#include "interface/types.h"
typedef struct workspace_desc_t {
size_t output_index; /* 对应 state_init() 中 outputs[] 的索引 */
const char *name;
const layout_id_t *layout_ids;
size_t layout_count;
layout_id_t initial_layout_id;
} workspace_desc_t;
void workspace_desc_cleanup(workspace_desc_t *workspace);
void workspace_desc_list_cleanup(workspace_desc_t **list, size_t *count);
bool workspace_desc_layouts_valid(const workspace_desc_t *workspace);
bool workspace_desc_valid(
const workspace_desc_t *workspace,
size_t output_count
);

View File

@@ -9,7 +9,7 @@
#include "base/log.h" #include "base/log.h"
#include "base/macros.h" #include "base/macros.h"
#include "core/types.h" #include "interface/types.h"
static constexpr char launcher[] = static constexpr char launcher[] =
"rofi -show combi -modes combi -combi-modes window,drun,run,ssh,windowcd"; "rofi -show combi -modes combi -combi-modes window,drun,run,ssh,windowcd";
@@ -17,9 +17,9 @@ static constexpr char launcher[] =
typedef struct zdwm_action_data_raise_or_run_t raise_or_run_data_t; typedef struct zdwm_action_data_raise_or_run_t raise_or_run_data_t;
static raise_or_run_data_t terminal = {"XTerm", "xterm"}; static raise_or_run_data_t terminal = {"XTerm", "xterm"};
static raise_or_run_data_t editor = {"Emacs", "emacsclient -a '' -r -n"}; static raise_or_run_data_t editor = {"Emacs", "emacsclient -a '' -r -n"};
static raise_or_run_data_t browser = {"firefox", "firefox-bin"}; static raise_or_run_data_t browser = {"firefox", "firefox-bin"};
static raise_or_run_data_t chrome = {"Google-chrome", "google-chrome-stable"}; static raise_or_run_data_t chrome = {"Google-chrome", "google-chrome-stable"};
bool config_defaults_build( bool config_defaults_build(
const zdwm_api_t *api, const zdwm_api_t *api,
@@ -52,10 +52,12 @@ bool config_defaults_build(
); );
zdwm_layout_id_t floating_id = zdwm_layout_id_t floating_id =
api->register_layout(builder, "floating", "><>", "floating", nullptr); api->register_layout(builder, "floating", "><>", "floating", nullptr);
if (fair_id == ZDWM_LAYOUT_ID_INVALID || if (
maximize_id == ZDWM_LAYOUT_ID_INVALID || fair_id == ZDWM_LAYOUT_ID_INVALID ||
fullscreen_id == ZDWM_LAYOUT_ID_INVALID || maximize_id == ZDWM_LAYOUT_ID_INVALID ||
floating_id == ZDWM_LAYOUT_ID_INVALID) { fullscreen_id == ZDWM_LAYOUT_ID_INVALID ||
floating_id == ZDWM_LAYOUT_ID_INVALID
) {
return false; return false;
} }
@@ -105,7 +107,7 @@ bool config_defaults_build(
MODE, \ MODE, \
KEY, \ KEY, \
{ \ { \
.type = ZDWM_ACTION_RAISE_OR_RUN, \ .type = ZDWM_ACTION_RAISE_OR_RUN, \
.as.raise_or_run = (zdwm_action_data_raise_or_run_t)__VA_ARGS__, \ .as.raise_or_run = (zdwm_action_data_raise_or_run_t)__VA_ARGS__, \
} \ } \
) )
@@ -136,7 +138,7 @@ bool config_defaults_build(
); );
zdwm_action_t window_cycle_output_action = { zdwm_action_t window_cycle_output_action = {
.type = ZDWM_ACTION_WINDOW_CYCLE_OUTPUT, .type = ZDWM_ACTION_WINDOW_CYCLE_OUTPUT,
.as.window_cycle_output = {.delta = 1, .keep_focus = true}, .as.window_cycle_output = {.delta = 1, .keep_focus = true},
}; };
BIND_DEFAULT(Super("o"), window_cycle_output_action); BIND_DEFAULT(Super("o"), window_cycle_output_action);
@@ -154,7 +156,7 @@ bool config_defaults_build(
zdwm_action_t send_window_to_workspace_action = { zdwm_action_t send_window_to_workspace_action = {
.type = ZDWM_ACTION_WINDOW_SEND_TO_WORKSPACE_SAME_OUTPUT_BY_INDEX, .type = ZDWM_ACTION_WINDOW_SEND_TO_WORKSPACE_SAME_OUTPUT_BY_INDEX,
.as.window_send_to_workspace_same_output_by_index = { .as.window_send_to_workspace_same_output_by_index = {
.index = i, .index = i,
.switch_workspace = false, .switch_workspace = false,
}, },
}; };
@@ -170,32 +172,32 @@ bool config_defaults_build(
api->set_interaction_fps(builder, 30); api->set_interaction_fps(builder, 30);
zdwm_bar_config_t bar_config = { zdwm_bar_config_t bar_config = {
.height = 28, .height = 28,
.show_top = true, .show_top = true,
.padding_x = 10, .padding_x = 10,
.fps = 30, .fps = 30,
.font_family = "Terminus, Sarasa Term SC", .font_family = "Terminus, Sarasa Term SC",
.font_size = 10, .font_size = 10,
.dpi = 144, .dpi = 144,
.bg = "#222222", .bg = "#222222",
.fg = "#bbbbbb", .fg = "#bbbbbb",
.tag_cell_padding_x = 10, .tag_cell_padding_x = 10,
.tag_indicator_width = 4, .tag_indicator_width = 4,
.tag_bg = "#222222", .tag_bg = "#222222",
.tag_fg = "#bbbbbb", .tag_fg = "#bbbbbb",
.tag_active_bg = "#005577", .tag_active_bg = "#005577",
.tag_active_fg = "#eeeeee", .tag_active_fg = "#eeeeee",
.tag_urgent_bg = "#222222", .tag_urgent_bg = "#222222",
.tag_urgent_fg = "#ff0000", .tag_urgent_fg = "#ff0000",
.layout_bg = "#222222", .layout_bg = "#222222",
.layout_fg = "#bbbbbb", .layout_fg = "#bbbbbb",
.binding_show_default = true, .binding_show_default = true,
.binding_padding_x = 2, .binding_padding_x = 2,
.binding_mode_bg = "#900000", .binding_mode_bg = "#900000",
.binding_mode_fg = "#ffffff", .binding_mode_fg = "#ffffff",
.window_focused_bg = "#005577", .window_focused_bg = "#005577",
.window_focused_fg = "#eeeeee", .window_focused_fg = "#eeeeee",

View File

@@ -10,9 +10,9 @@
static char *config_loader_join_path(const char *base, const char *suffix) { static char *config_loader_join_path(const char *base, const char *suffix) {
if (!base || !suffix) return nullptr; if (!base || !suffix) return nullptr;
size_t base_len = strlen(base); size_t base_len = strlen(base);
size_t suffix_len = strlen(suffix); size_t suffix_len = strlen(suffix);
char *path = p_new(char, base_len + suffix_len + 1); char *path = p_new(char, base_len + suffix_len + 1);
memcpy(path, base, base_len); memcpy(path, base, base_len);
memcpy(path + base_len, suffix, suffix_len + 1); memcpy(path + base_len, suffix, suffix_len + 1);
return path; return path;
@@ -25,28 +25,28 @@ static bool config_loader_resolve_path(
) { ) {
const char *path = override_path; const char *path = override_path;
if (path && *path) { if (path && *path) {
*out_path = p_strdup(path); *out_path = p_strdup(path);
*out_is_explicit = true; *out_is_explicit = true;
return true; return true;
} }
path = getenv("ZDWM_CONFIG_LIB"); path = getenv("ZDWM_CONFIG_LIB");
if (path && *path) { if (path && *path) {
*out_path = p_strdup(path); *out_path = p_strdup(path);
*out_is_explicit = true; *out_is_explicit = true;
return true; return true;
} }
path = getenv("XDG_CONFIG_HOME"); path = getenv("XDG_CONFIG_HOME");
if (path && *path) { if (path && *path) {
*out_path = config_loader_join_path(path, "/zdwm/config.so"); *out_path = config_loader_join_path(path, "/zdwm/config.so");
*out_is_explicit = false; *out_is_explicit = false;
return *out_path != nullptr; return *out_path != nullptr;
} }
path = getenv("HOME"); path = getenv("HOME");
if (path && *path) { if (path && *path) {
*out_path = config_loader_join_path(path, "/.config/zdwm/config.so"); *out_path = config_loader_join_path(path, "/.config/zdwm/config.so");
*out_is_explicit = false; *out_is_explicit = false;
return *out_path != nullptr; return *out_path != nullptr;
} }
@@ -79,7 +79,7 @@ bool config_loader_load(config_loader_t *loader, const char *override_path) {
} }
dlerror(); dlerror();
loader->setup = (zdwm_config_setup_fn *)dlsym(loader->handle, "setup"); loader->setup = (zdwm_config_setup_fn *)dlsym(loader->handle, "setup");
const char *error = dlerror(); const char *error = dlerror();
if (!error) return true; if (!error) return true;

View File

@@ -5,18 +5,19 @@
#include <stdint.h> #include <stdint.h>
#include <zdwm/bar.h> #include <zdwm/bar.h>
#include <zdwm/config.h> #include <zdwm/config.h>
#include <zdwm/listeners.h>
#include "base/array.h" #include "base/array.h"
#include "base/color.h" #include "base/color.h"
#include "base/memory.h" #include "base/memory.h"
#include "common/listeners.h"
#include "common/workspace.h"
#include "config/defaults.h" #include "config/defaults.h"
#include "config/loader.h" #include "config/loader.h"
#include "core/binding.h" #include "core/binding.h"
#include "core/layout.h" #include "core/layout.h"
#include "core/listeners.h"
#include "core/rules.h" #include "core/rules.h"
#include "core/types.h" #include "interface/types.h"
#include "core/wm_desc.h"
#include "layouts/fair.h" #include "layouts/fair.h"
#include "layouts/fullscreen.h" #include "layouts/fullscreen.h"
#include "layouts/maximize.h" #include "layouts/maximize.h"
@@ -38,8 +39,10 @@ struct zdwm_config_builder_t {
void runtime_config_cleanup(runtime_init_desc_t *desc) { void runtime_config_cleanup(runtime_init_desc_t *desc) {
if (!desc) return; if (!desc) return;
if (desc->layouts.slots || desc->layouts.slot_count || if (
desc->layouts.slot_capacity) { desc->layouts.slots || desc->layouts.slot_count ||
desc->layouts.slot_capacity
) {
layout_registry_cleanup(&desc->layouts); layout_registry_cleanup(&desc->layouts);
} }
binding_table_destroy(desc->binding_table); binding_table_destroy(desc->binding_table);
@@ -53,13 +56,15 @@ void runtime_config_cleanup(runtime_init_desc_t *desc) {
static void config_builder_cleanup(zdwm_config_builder_t *builder) { static void config_builder_cleanup(zdwm_config_builder_t *builder) {
if (!builder) return; if (!builder) return;
if (builder->layouts.slots || builder->layouts.slot_count || if (
builder->layouts.slot_capacity) { builder->layouts.slots || builder->layouts.slot_count ||
builder->layouts.slot_capacity
) {
layout_registry_cleanup(&builder->layouts); layout_registry_cleanup(&builder->layouts);
} }
workspace_desc_list_cleanup(&builder->workspaces, &builder->workspace_count); workspace_desc_list_cleanup(&builder->workspaces, &builder->workspace_count);
builder->workspace_capacity = 0; builder->workspace_capacity = 0;
builder->output_count = 0; builder->output_count = 0;
binding_table_destroy(builder->binding_table); binding_table_destroy(builder->binding_table);
builder->binding_table = nullptr; builder->binding_table = nullptr;
@@ -93,10 +98,10 @@ static workspace_id_t runtime_config_define_workspace(
} }
workspace_desc_t desc = { workspace_desc_t desc = {
.output_index = output_index, .output_index = output_index,
.name = name, .name = name,
.layout_ids = layout_ids, .layout_ids = layout_ids,
.layout_count = layout_count, .layout_count = layout_count,
.initial_layout_id = initial_layout_id, .initial_layout_id = initial_layout_id,
}; };
if (!workspace_desc_valid(&desc, builder->output_count)) { if (!workspace_desc_valid(&desc, builder->output_count)) {
@@ -110,15 +115,15 @@ static workspace_id_t runtime_config_define_workspace(
} }
workspace_id_t workspace_id = (workspace_id_t)builder->workspace_count; workspace_id_t workspace_id = (workspace_id_t)builder->workspace_count;
workspace_desc_t *slot = array_push( workspace_desc_t *slot = array_push(
builder->workspaces, builder->workspaces,
builder->workspace_count, builder->workspace_count,
builder->workspace_capacity builder->workspace_capacity
); );
slot->output_index = output_index; slot->output_index = output_index;
slot->name = p_strdup(name); slot->name = p_strdup(name);
slot->layout_ids = p_copy(layout_ids, layout_count); slot->layout_ids = p_copy(layout_ids, layout_count);
slot->layout_count = layout_count; slot->layout_count = layout_count;
slot->initial_layout_id = initial_layout_id; slot->initial_layout_id = initial_layout_id;
return workspace_id; return workspace_id;
} }
@@ -151,14 +156,14 @@ static bool runtime_config_add_rule(
if (!rule_match_valid(match)) return false; if (!rule_match_valid(match)) return false;
if (!rule_action_valid(action, builder->workspace_count)) return false; if (!rule_action_valid(action, builder->workspace_count)) return false;
rules_t *rules = &builder->rules; rules_t *rules = &builder->rules;
rule_item_t *rule = array_push(rules->items, rules->count, rules->capacity); rule_item_t *rule = array_push(rules->items, rules->count, rules->capacity);
rule->match.app_id = p_strdup_nullable(match->app_id); rule->match.app_id = p_strdup_nullable(match->app_id);
rule->match.role = p_strdup_nullable(match->role); rule->match.role = p_strdup_nullable(match->role);
rule->match.class_name = p_strdup_nullable(match->class_name); rule->match.class_name = p_strdup_nullable(match->class_name);
rule->match.instance_name = p_strdup_nullable(match->instance_name); rule->match.instance_name = p_strdup_nullable(match->instance_name);
rule->action = *action; rule->action = *action;
return true; return true;
} }
@@ -308,18 +313,18 @@ static bool config_builder_finish(
if (!layout_registry_move(&builder->layouts, &out->layouts)) return false; if (!layout_registry_move(&builder->layouts, &out->layouts)) return false;
if (!rules_move(&builder->rules, &out->rules)) return false; if (!rules_move(&builder->rules, &out->rules)) return false;
out->border = builder->border; out->border = builder->border;
out->fps = builder->fps; out->fps = builder->fps;
out->binding_table = builder->binding_table; out->binding_table = builder->binding_table;
out->workspaces = builder->workspaces; out->workspaces = builder->workspaces;
out->workspace_count = builder->workspace_count; out->workspace_count = builder->workspace_count;
out->listeners = builder->listeners; out->listeners = builder->listeners;
out->bar = builder->bar; out->bar = builder->bar;
builder->binding_table = nullptr; builder->binding_table = nullptr;
builder->workspaces = nullptr; builder->workspaces = nullptr;
builder->workspace_count = 0; builder->workspace_count = 0;
builder->workspace_capacity = 0; builder->workspace_capacity = 0;
builder->output_count = 0; builder->output_count = 0;
p_clear(&builder->listeners, 1); p_clear(&builder->listeners, 1);
p_clear(&builder->bar, 1); p_clear(&builder->bar, 1);
return true; return true;
@@ -333,17 +338,17 @@ static bool runtime_config_build(
) { ) {
if (!setup || !out) return false; if (!setup || !out) return false;
zdwm_config_builder_t builder = {0}; zdwm_config_builder_t builder = {0};
builder.output_count = output_count; builder.output_count = output_count;
builder.binding_table = binding_table_create(); builder.binding_table = binding_table_create();
/* clang-format off */
zdwm_api_t api = { zdwm_api_t api = {
.abi_version = ZDWM_CONFIG_ABI_VERSION, .abi_version = ZDWM_CONFIG_ABI_VERSION,
.builtin_layouts = .builtin_layouts = {
{ .fair = fair,
.fair = fair, .fullscreen = fullscreen,
.fullscreen = fullscreen, .maximize = maximize,
.maximize = maximize, },
},
.register_layout = runtime_config_register_layout, .register_layout = runtime_config_register_layout,
.define_workspace = runtime_config_define_workspace, .define_workspace = runtime_config_define_workspace,
.add_rule = runtime_config_add_rule, .add_rule = runtime_config_add_rule,
@@ -355,20 +360,19 @@ static bool runtime_config_build(
.set_interaction_fps = runtime_config_set_interaction_fps, .set_interaction_fps = runtime_config_set_interaction_fps,
.subscribe_current_output = runtime_config_subscribe_current_output, .subscribe_current_output = runtime_config_subscribe_current_output,
.subscribe_initial_workspace_list = .subscribe_initial_workspace_list = runtime_config_subscribe_initial_workspace_list,
runtime_config_subscribe_initial_workspace_list, .subscribe_workspace_active = runtime_config_subscribe_workspace_active,
.subscribe_workspace_active = runtime_config_subscribe_workspace_active, .subscribe_layout = runtime_config_subscribe_layout,
.subscribe_layout = runtime_config_subscribe_layout, .subscribe_binding_mode = runtime_config_subscribe_binding_mode,
.subscribe_binding_mode = runtime_config_subscribe_binding_mode, .subscribe_initial_window_list = runtime_config_subscribe_initial_window_list,
.subscribe_initial_window_list = .subscribe_window_added = runtime_config_subscribe_window_added,
runtime_config_subscribe_initial_window_list, .subscribe_window_updated = runtime_config_subscribe_window_updated,
.subscribe_window_added = runtime_config_subscribe_window_added, .subscribe_window_removed = runtime_config_subscribe_window_removed,
.subscribe_window_updated = runtime_config_subscribe_window_updated,
.subscribe_window_removed = runtime_config_subscribe_window_removed,
.set_bar_config = runtime_config_set_bar_config, .set_bar_config = runtime_config_set_bar_config,
}; };
/* clang-format on */
bool ok = setup(&api, &builder, outputs, output_count) && bool ok = setup(&api, &builder, outputs, output_count) &&
config_builder_finish(&builder, out); config_builder_finish(&builder, out);
config_builder_cleanup(&builder); config_builder_cleanup(&builder);
@@ -390,7 +394,7 @@ bool runtime_config_load(const char *override_path, runtime_init_desc_t *out) {
bool ok = runtime_config_build(setup, out->outputs, out->output_count, out); bool ok = runtime_config_build(setup, out->outputs, out->output_count, out);
if (ok) { if (ok) {
out->config_module_handle = loader.handle; out->config_module_handle = loader.handle;
loader.handle = nullptr; loader.handle = nullptr;
} }
config_loader_cleanup(&loader); config_loader_cleanup(&loader);

View File

@@ -5,13 +5,12 @@
#include <zdwm/bar.h> #include <zdwm/bar.h>
#include <zdwm/types.h> #include <zdwm/types.h>
#include "core/backend.h" #include "common/listeners.h"
#include "common/workspace.h"
#include "core/binding.h" #include "core/binding.h"
#include "core/layout.h" #include "core/layout.h"
#include "core/listeners.h"
#include "core/rules.h" #include "core/rules.h"
#include "core/types.h" #include "interface/backend.h"
#include "core/wm_desc.h"
typedef struct runtime_init_desc_t { typedef struct runtime_init_desc_t {
backend_t *backend; backend_t *backend;

View File

@@ -12,7 +12,7 @@
#include "base/array.h" #include "base/array.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/memory.h" #include "base/memory.h"
#include "core/types.h" #include "interface/types.h"
typedef struct binding_mode_t { typedef struct binding_mode_t {
zdwm_binding_mode_id_t id; zdwm_binding_mode_id_t id;
@@ -43,9 +43,9 @@ binding_table_add_mode(binding_table_t *table, const char *mode_name) {
} }
zdwm_binding_mode_id_t id = (zdwm_binding_mode_id_t)table->count; zdwm_binding_mode_id_t id = (zdwm_binding_mode_id_t)table->count;
auto new_mode = array_push(table->modes, table->count, table->capacity); auto new_mode = array_push(table->modes, table->count, table->capacity);
new_mode->name = mode_name; new_mode->name = mode_name;
new_mode->id = id; new_mode->id = id;
return id; return id;
} }
@@ -82,8 +82,10 @@ static const mod_entry_t mod_table[] = {
static modifier_mask_t lookup_modifier(const char *name, size_t len) { static modifier_mask_t lookup_modifier(const char *name, size_t len) {
for (size_t i = 0; i < countof(mod_table); ++i) { for (size_t i = 0; i < countof(mod_table); ++i) {
if (strlen(mod_table[i].name) == len && if (
strncmp(name, mod_table[i].name, len) == 0) { strlen(mod_table[i].name) == len &&
strncmp(name, mod_table[i].name, len) == 0
) {
return mod_table[i].mask; return mod_table[i].mask;
} }
} }
@@ -118,13 +120,13 @@ static bool parse_key_sequence(
if (!key_sequence || !modifiers || !keysym) return false; if (!key_sequence || !modifiers || !keysym) return false;
modifier_mask_t mods = ZDWM_MOD_NONE; modifier_mask_t mods = ZDWM_MOD_NONE;
xkb_keysym_t key = XKB_KEY_NoSymbol; xkb_keysym_t key = XKB_KEY_NoSymbol;
const char *p = key_sequence; const char *p = key_sequence;
const char *end = key_sequence + strlen(key_sequence); const char *end = key_sequence + strlen(key_sequence);
while (p < end) { while (p < end) {
const char *plus = strchr(p, '+'); const char *plus = strchr(p, '+');
const char *seg_end = plus ? plus : end; const char *seg_end = plus ? plus : end;
const char *s = p; const char *s = p;
@@ -139,7 +141,7 @@ static bool parse_key_sequence(
modifier_mask_t mod = lookup_modifier(s, (size_t)(e - s)); modifier_mask_t mod = lookup_modifier(s, (size_t)(e - s));
if (mod == ZDWM_MOD_NONE) return false; if (mod == ZDWM_MOD_NONE) return false;
mods |= mod; mods |= mod;
p = plus + 1; p = plus + 1;
} else { } else {
char key_buf[64]; char key_buf[64];
size_t key_len = (size_t)(e - s); size_t key_len = (size_t)(e - s);
@@ -152,7 +154,7 @@ static bool parse_key_sequence(
return false; return false;
} else { } else {
*modifiers = mods; *modifiers = mods;
*keysym = key; *keysym = key;
return true; return true;
} }
} }
@@ -171,13 +173,13 @@ bool binding_table_add_bind(
if (!mode) return false; if (!mode) return false;
modifier_mask_t modifiers = 0; modifier_mask_t modifiers = 0;
xkb_keysym_t keysym = XKB_KEY_NoSymbol; xkb_keysym_t keysym = XKB_KEY_NoSymbol;
if (!parse_key_sequence(key_sequence, &modifiers, &keysym)) return false; if (!parse_key_sequence(key_sequence, &modifiers, &keysym)) return false;
auto item = array_push(mode->items, mode->count, mode->capacity); auto item = array_push(mode->items, mode->count, mode->capacity);
item->modifiers = modifiers; item->modifiers = modifiers;
item->keysym = keysym; item->keysym = keysym;
item->action = action; item->action = action;
return true; return true;
} }
@@ -188,13 +190,13 @@ void binding_table_destroy(binding_table_t *table) {
for (size_t i = 0; i < table->count; ++i) { for (size_t i = 0; i < table->count; ++i) {
binding_mode_t *mode = &table->modes[i]; binding_mode_t *mode = &table->modes[i];
p_delete(&mode->items); p_delete(&mode->items);
mode->count = 0; mode->count = 0;
mode->capacity = 0; mode->capacity = 0;
} }
p_delete(&table->modes); p_delete(&table->modes);
table->count = 0; table->count = 0;
table->capacity = 0; table->capacity = 0;
table->default_mode = ZDWM_BINDING_MODE_ID_INVALID; table->default_mode = ZDWM_BINDING_MODE_ID_INVALID;
p_delete(&table); p_delete(&table);
@@ -243,7 +245,7 @@ binding_table_cycle_mode(const binding_table_t *table, int32_t delta) {
} else { } else {
for (size_t i = 0; i < table->count; ++i) { for (size_t i = 0; i < table->count; ++i) {
if (table->modes[i].id == table->current_mode) { if (table->modes[i].id == table->current_mode) {
index = i; index = i;
matched = true; matched = true;
break; break;
} }
@@ -252,7 +254,7 @@ binding_table_cycle_mode(const binding_table_t *table, int32_t delta) {
if (!matched) return ZDWM_BINDING_MODE_ID_INVALID; if (!matched) return ZDWM_BINDING_MODE_ID_INVALID;
int64_t count = (int64_t)table->count; int64_t count = (int64_t)table->count;
int64_t next_index = ((int64_t)index + (int64_t)delta) % count; int64_t next_index = ((int64_t)index + (int64_t)delta) % count;
if (next_index < 0) next_index += count; if (next_index < 0) next_index += count;

View File

@@ -5,7 +5,7 @@
#include <zdwm/action.h> #include <zdwm/action.h>
#include <zdwm/types.h> #include <zdwm/types.h>
#include "core/types.h" #include "interface/types.h"
typedef struct binding_table_t binding_table_t; typedef struct binding_table_t binding_table_t;

View File

@@ -1,7 +1,7 @@
#pragma once #pragma once
#include "core/types.h" #include "core/window_info.h"
#include "core/wm_desc.h" #include "interface/types.h"
typedef enum command_type_t { typedef enum command_type_t {
ZDWM_COMMAND_MANAGE_WINDOW, ZDWM_COMMAND_MANAGE_WINDOW,

View File

@@ -13,11 +13,11 @@ void command_buffer_reset(command_buffer_t *buffer) {
void command_buffer_cleanup(command_buffer_t *buffer) { void command_buffer_cleanup(command_buffer_t *buffer) {
p_delete(&buffer->items); p_delete(&buffer->items);
buffer->count = 0; buffer->count = 0;
buffer->capacity = 0; buffer->capacity = 0;
} }
void command_buffer_push(command_buffer_t *buffer, const command_t *command) { void command_buffer_push(command_buffer_t *buffer, const command_t *command) {
command_t *cmd = array_push(buffer->items, buffer->count, buffer->capacity); command_t *cmd = array_push(buffer->items, buffer->count, buffer->capacity);
*cmd = *command; *cmd = *command;
} }

View File

@@ -4,11 +4,11 @@
#include "base/array.h" #include "base/array.h"
#include "base/memory.h" #include "base/memory.h"
#include "core/types.h" #include "interface/types.h"
void layer_stack_cleanup(layer_stack_t *layer) { void layer_stack_cleanup(layer_stack_t *layer) {
p_delete(&layer->order); p_delete(&layer->order);
layer->count = 0; layer->count = 0;
layer->capacity = 0; layer->capacity = 0;
} }
@@ -19,7 +19,7 @@ void layer_stack_append(layer_stack_t *layer, window_id_t window) {
} }
bool layer_stack_remove(layer_stack_t *layer, window_id_t window) { bool layer_stack_remove(layer_stack_t *layer, window_id_t window) {
bool found = false; bool found = false;
size_t index = 0; size_t index = 0;
for (size_t i = 0; i < layer->count; ++i) { for (size_t i = 0; i < layer->count; ++i) {
if (layer->order[i] != window) continue; if (layer->order[i] != window) continue;
@@ -40,7 +40,7 @@ bool layer_stack_remove(layer_stack_t *layer, window_id_t window) {
} }
bool layer_stack_raise(layer_stack_t *layer, window_id_t window) { bool layer_stack_raise(layer_stack_t *layer, window_id_t window) {
bool found = false; bool found = false;
size_t index = 0; size_t index = 0;
for (size_t i = 0; i < layer->count; ++i) { for (size_t i = 0; i < layer->count; ++i) {
if (layer->order[i] != window) continue; if (layer->order[i] != window) continue;
@@ -64,7 +64,7 @@ bool layer_stack_raise(layer_stack_t *layer, window_id_t window) {
} }
bool layer_stack_lower(layer_stack_t *layer, window_id_t window) { bool layer_stack_lower(layer_stack_t *layer, window_id_t window) {
bool found = false; bool found = false;
size_t index = 0; size_t index = 0;
for (size_t i = 0; i < layer->count; ++i) { for (size_t i = 0; i < layer->count; ++i) {
if (layer->order[i] != window) continue; if (layer->order[i] != window) continue;

View File

@@ -2,7 +2,7 @@
#include <stddef.h> #include <stddef.h>
#include "core/types.h" #include "interface/types.h"
typedef struct layer_stack_t { typedef struct layer_stack_t {
window_id_t *order; window_id_t *order;

View File

@@ -6,11 +6,11 @@
#include "base/array.h" #include "base/array.h"
#include "base/memory.h" #include "base/memory.h"
#include "core/types.h" #include "interface/types.h"
void layout_result_cleanup(layout_result_t *result) { void layout_result_cleanup(layout_result_t *result) {
p_delete(&result->items); p_delete(&result->items);
result->item_count = 0; result->item_count = 0;
result->item_capacity = 0; result->item_capacity = 0;
} }
@@ -31,19 +31,19 @@ void layout_registry_cleanup(layout_registry_t *registry) {
} }
p_delete(&registry->slots); p_delete(&registry->slots);
registry->slot_count = 0; registry->slot_count = 0;
registry->slot_capacity = 0; registry->slot_capacity = 0;
} }
bool layout_registry_move(layout_registry_t *src, layout_registry_t *dest) { bool layout_registry_move(layout_registry_t *src, layout_registry_t *dest) {
if (!src || !dest) return false; if (!src || !dest) return false;
dest->slots = src->slots; dest->slots = src->slots;
dest->slot_count = src->slot_count; dest->slot_count = src->slot_count;
dest->slot_capacity = src->slot_capacity; dest->slot_capacity = src->slot_capacity;
src->slots = nullptr; src->slots = nullptr;
src->slot_count = 0; src->slot_count = 0;
src->slot_capacity = 0; src->slot_capacity = 0;
return true; return true;
@@ -71,11 +71,11 @@ layout_id_t layout_register(
layout_id_t id = (layout_id_t)registry->slot_count; layout_id_t id = (layout_id_t)registry->slot_count;
layout_slot_t *r = layout_slot_t *r =
array_push(registry->slots, registry->slot_count, registry->slot_capacity); array_push(registry->slots, registry->slot_count, registry->slot_capacity);
r->id = id; r->id = id;
r->name = p_strdup(name); r->name = p_strdup(name);
r->symbol = p_strdup(symbol); r->symbol = p_strdup(symbol);
r->description = p_strdup_nullable(description); r->description = p_strdup_nullable(description);
r->fn = fn; r->fn = fn;
return r->id; return r->id;
} }

View File

@@ -3,7 +3,7 @@
#include <stddef.h> #include <stddef.h>
#include <zdwm/layout.h> #include <zdwm/layout.h>
#include "core/types.h" #include "interface/types.h"
typedef zdwm_layout_ctx_t layout_ctx_t; typedef zdwm_layout_ctx_t layout_ctx_t;
typedef zdwm_layout_item_t layout_item_t; typedef zdwm_layout_item_t layout_item_t;

View File

@@ -1,112 +1,11 @@
#include "core/listeners.h" #include "core/listeners.h"
#include "base/array.h"
#include "base/memory.h" #include "base/memory.h"
#include "common/listeners.h"
#include "core/binding.h" #include "core/binding.h"
#include "core/layout.h" #include "core/layout.h"
#include "core/state.h" #include "core/state.h"
#define ADD_LISTENER(FIELD) \
auto list = &listeners->FIELD; \
auto item = array_push(list->items, list->count, list->capacity); \
item->fn = fn; \
item->user_data = user_data
void listeners_add_output_listener(
listeners_t *listeners,
zdwm_current_output_id_listener fn,
void *user_data
) {
ADD_LISTENER(output_listeners);
}
void listeners_add_initial_workspace_listener(
listeners_t *listeners,
zdwm_initial_workspace_list fn,
void *user_data
) {
ADD_LISTENER(initial_workspace_listeners);
}
void listeners_add_active_workspace_listener(
listeners_t *listeners,
zdwm_workspace_active_updated fn,
void *user_data
) {
ADD_LISTENER(active_workspace_listeners);
}
void listeners_add_layout_notify(
listeners_t *listeners,
zdwm_layout_notify fn,
void *user_data
) {
ADD_LISTENER(layout_listeners);
}
void listeners_add_binding_mode_notify(
listeners_t *listeners,
zdwm_binding_mode_notify fn,
void *user_data
) {
ADD_LISTENER(binding_mode_listeners);
}
void listeners_add_initial_window_listener(
listeners_t *listeners,
zdwm_initial_window_list fn,
void *user_data
) {
ADD_LISTENER(initial_window_listeners);
}
void listeners_add_window_added_listener(
listeners_t *listeners,
zdwm_window_added fn,
void *user_data
) {
ADD_LISTENER(window_added_listeners);
}
void listeners_add_window_updated_listener(
listeners_t *listeners,
zdwm_window_updated fn,
void *user_data
) {
ADD_LISTENER(window_updated_listeners);
}
void listeners_add_window_removed_listener(
listeners_t *listeners,
zdwm_window_removed fn,
void *user_data
) {
ADD_LISTENER(window_removed_listeners);
}
#undef ADD_LISTENER
#define CLEANUP_LIST(FIELD) \
p_delete(&listeners->FIELD.items); \
listeners->FIELD.count = 0; \
listeners->FIELD.capacity = 0
void listeners_cleanup(listeners_t *listeners) {
if (!listeners) return;
CLEANUP_LIST(output_listeners);
CLEANUP_LIST(initial_workspace_listeners);
CLEANUP_LIST(active_workspace_listeners);
CLEANUP_LIST(layout_listeners);
CLEANUP_LIST(binding_mode_listeners);
CLEANUP_LIST(initial_window_listeners);
CLEANUP_LIST(window_added_listeners);
CLEANUP_LIST(window_updated_listeners);
CLEANUP_LIST(window_removed_listeners);
}
#undef CLEANUP_LIST
#define FOR_EACH_LISTENER(FIELD, BODY) \ #define FOR_EACH_LISTENER(FIELD, BODY) \
do { \ do { \
if (!(listeners)) return; \ if (!(listeners)) return; \
@@ -131,14 +30,14 @@ void listeners_notify_initial_workspaces(
if (!listeners || !state) return; if (!listeners || !state) return;
size_t count = state_workspace_count(state); size_t count = state_workspace_count(state);
auto items = count ? p_new(zdwm_workspace_t, count) : nullptr; auto items = count ? p_new(zdwm_workspace_t, count) : nullptr;
for (size_t i = 0; i < count; ++i) { for (size_t i = 0; i < count; ++i) {
auto workspace = state_workspace_at(state, i); auto workspace = state_workspace_at(state, i);
items[i] = (zdwm_workspace_t){ items[i] = (zdwm_workspace_t){
.output_id = workspace->output_id, .output_id = workspace->output_id,
.id = workspace->id, .id = workspace->id,
.name = workspace->name, .name = workspace->name,
}; };
} }
@@ -173,10 +72,10 @@ void listeners_notify_layout(
if (!slot) return; if (!slot) return;
zdwm_layout_notify_t notify = { zdwm_layout_notify_t notify = {
.workspace = workspace_id, .workspace = workspace_id,
.id = layout_id, .id = layout_id,
.name = slot->name, .name = slot->name,
.symbol = slot->symbol, .symbol = slot->symbol,
.description = slot->description, .description = slot->description,
}; };
@@ -191,12 +90,12 @@ void listeners_notify_binding_mode(
auto default_mode = binding_table_get_default_mode(binding_table); auto default_mode = binding_table_get_default_mode(binding_table);
auto current_mode = binding_table_get_current_mode(binding_table); auto current_mode = binding_table_get_current_mode(binding_table);
auto name = binding_table_get_mode_name(binding_table, current_mode); auto name = binding_table_get_mode_name(binding_table, current_mode);
zdwm_binding_mode_notify_t notify = { zdwm_binding_mode_notify_t notify = {
.is_default_mode = default_mode == current_mode, .is_default_mode = default_mode == current_mode,
.id = current_mode, .id = current_mode,
.name = name, .name = name,
}; };
FOR_EACH_LISTENER(binding_mode_listeners, item->fn(notify, item->user_data)); FOR_EACH_LISTENER(binding_mode_listeners, item->fn(notify, item->user_data));
@@ -216,11 +115,11 @@ static bool listeners_window_snapshot(
if (!workspace) return false; if (!workspace) return false;
*out = (zdwm_window_t){ *out = (zdwm_window_t){
.workspace = window->workspace_id, .workspace = window->workspace_id,
.id = window->id, .id = window->id,
.title = window->title, .title = window->title,
.focused = workspace->focused_window_id == window->id, .focused = workspace->focused_window_id == window->id,
.urgent = window->urgent, .urgent = window->urgent,
.skip_taskbar = window->skip_taskbar, .skip_taskbar = window->skip_taskbar,
}; };
return true; return true;
@@ -232,7 +131,7 @@ void listeners_notify_initial_windows(
) { ) {
if (!listeners || !state) return; if (!listeners || !state) return;
size_t count = state_window_count(state); size_t count = state_window_count(state);
zdwm_window_t *items = count ? p_new(zdwm_window_t, count) : nullptr; zdwm_window_t *items = count ? p_new(zdwm_window_t, count) : nullptr;
for (size_t i = 0; i < count; ++i) { for (size_t i = 0; i < count; ++i) {
auto window = state_window_at(state, i); auto window = state_window_at(state, i);

View File

@@ -3,98 +3,8 @@
#include <stddef.h> #include <stddef.h>
#include <zdwm/listeners.h> #include <zdwm/listeners.h>
#include "core/types.h" #include "common/listeners.h"
#include "interface/types.h"
typedef struct binding_table_t binding_table_t;
typedef struct layout_registry_t layout_registry_t;
typedef struct state_t state_t;
#define ITEM(NAME, FN_TYPE) \
typedef struct NAME##_listener_item_t { \
FN_TYPE *fn; \
void *user_data; \
} NAME##_listener_item_t
#define LISTENERS(NAME, FN_TYPE) \
ITEM(NAME, FN_TYPE); \
typedef struct NAME##_listeners_t { \
NAME##_listener_item_t *items; \
size_t count; \
size_t capacity; \
} NAME##_listeners_t
LISTENERS(output, zdwm_current_output_id_listener);
LISTENERS(initial_workspace_list, zdwm_initial_workspace_list);
LISTENERS(workspace_active, zdwm_workspace_active_updated);
LISTENERS(layout, zdwm_layout_notify);
LISTENERS(binding_mode, zdwm_binding_mode_notify);
LISTENERS(initial_window_list, zdwm_initial_window_list);
LISTENERS(window_added, zdwm_window_added);
LISTENERS(window_updated, zdwm_window_updated);
LISTENERS(window_removed, zdwm_window_removed);
#undef ITEM
#undef LISTENERS
typedef struct listeners_t {
output_listeners_t output_listeners;
initial_workspace_list_listeners_t initial_workspace_listeners;
workspace_active_listeners_t active_workspace_listeners;
layout_listeners_t layout_listeners;
binding_mode_listeners_t binding_mode_listeners;
initial_window_list_listeners_t initial_window_listeners;
window_added_listeners_t window_added_listeners;
window_updated_listeners_t window_updated_listeners;
window_removed_listeners_t window_removed_listeners;
} listeners_t;
void listeners_add_output_listener(
listeners_t *listeners,
zdwm_current_output_id_listener fn,
void *user_data
);
void listeners_add_initial_workspace_listener(
listeners_t *listeners,
zdwm_initial_workspace_list fn,
void *user_data
);
void listeners_add_active_workspace_listener(
listeners_t *listeners,
zdwm_workspace_active_updated fn,
void *user_data
);
void listeners_add_layout_notify(
listeners_t *listeners,
zdwm_layout_notify fn,
void *user_data
);
void listeners_add_binding_mode_notify(
listeners_t *listeners,
zdwm_binding_mode_notify fn,
void *user_data
);
void listeners_add_initial_window_listener(
listeners_t *listeners,
zdwm_initial_window_list fn,
void *user_data
);
void listeners_add_window_added_listener(
listeners_t *listeners,
zdwm_window_added fn,
void *user_data
);
void listeners_add_window_updated_listener(
listeners_t *listeners,
zdwm_window_updated fn,
void *user_data
);
void listeners_add_window_removed_listener(
listeners_t *listeners,
zdwm_window_removed fn,
void *user_data
);
void listeners_cleanup(listeners_t *listeners);
/** /**
* @brief 通知当前 output 信息 * @brief 通知当前 output 信息

View File

@@ -4,7 +4,8 @@
#include "base/array.h" #include "base/array.h"
#include "base/memory.h" #include "base/memory.h"
#include "core/types.h" #include "interface/effect.h"
#include "interface/types.h"
static void free_memory_hold_by_effects(effect_t *effects, size_t count) { static void free_memory_hold_by_effects(effect_t *effects, size_t count) {
for (size_t i = 0; i < count; ++i) { for (size_t i = 0; i < count; ++i) {
@@ -38,23 +39,23 @@ void plan_reset(plan_t *plan) {
void plan_cleanup(plan_t *plan) { void plan_cleanup(plan_t *plan) {
free_memory_hold_by_effects(plan->effects, plan->count); free_memory_hold_by_effects(plan->effects, plan->count);
p_delete(&plan->effects); p_delete(&plan->effects);
plan->count = 0; plan->count = 0;
plan->capacity = 0; plan->capacity = 0;
plan->need_relayout = false; plan->need_relayout = false;
plan->quit = false; plan->quit = false;
plan->will_restart = false; plan->will_restart = false;
} }
void plan_push_effect(plan_t *plan, const effect_t *effect) { void plan_push_effect(plan_t *plan, const effect_t *effect) {
effect_t *eft = array_push(plan->effects, plan->count, plan->capacity); effect_t *eft = array_push(plan->effects, plan->count, plan->capacity);
*eft = *effect; *eft = *effect;
} }
void plan_push_map_effect(plan_t *plan, window_id_t window_id) { void plan_push_map_effect(plan_t *plan, window_id_t window_id) {
if (window_id_invalid(window_id)) return; if (window_id_invalid(window_id)) return;
effect_t effect = { effect_t effect = {
.type = ZDWM_EFFECT_MAP_WINDOW, .type = ZDWM_EFFECT_MAP_WINDOW,
.as.map.window = window_id, .as.map.window = window_id,
}; };
plan_push_effect(plan, &effect); plan_push_effect(plan, &effect);
@@ -64,7 +65,7 @@ void plan_push_unmap_effect(plan_t *plan, window_id_t window_id) {
if (window_id_invalid(window_id)) return; if (window_id_invalid(window_id)) return;
effect_t effect = { effect_t effect = {
.type = ZDWM_EFFECT_UNMAP_WINDOW, .type = ZDWM_EFFECT_UNMAP_WINDOW,
.as.unmap.window = window_id, .as.unmap.window = window_id,
}; };
plan_push_effect(plan, &effect); plan_push_effect(plan, &effect);
@@ -74,7 +75,7 @@ void plan_push_focus_effect(plan_t *plan, window_id_t window_id) {
if (window_id_invalid(window_id)) return; if (window_id_invalid(window_id)) return;
effect_t effect = { effect_t effect = {
.type = ZDWM_EFFECT_FOCUS_WINDOW, .type = ZDWM_EFFECT_FOCUS_WINDOW,
.as.focus.window = window_id, .as.focus.window = window_id,
}; };
plan_push_effect(plan, &effect); plan_push_effect(plan, &effect);
@@ -84,7 +85,7 @@ void plan_push_kill_effect(plan_t *plan, window_id_t window_id) {
if (window_id_invalid(window_id)) return; if (window_id_invalid(window_id)) return;
effect_t effect = { effect_t effect = {
.type = ZDWM_EFFECT_KILL_WINDOW, .type = ZDWM_EFFECT_KILL_WINDOW,
.as.kill.window = window_id, .as.kill.window = window_id,
}; };
plan_push_effect(plan, &effect); plan_push_effect(plan, &effect);
@@ -94,7 +95,7 @@ void plan_push_withdraw_effect(plan_t *plan, window_id_t window_id) {
if (window_id_invalid(window_id)) return; if (window_id_invalid(window_id)) return;
effect_t effect = { effect_t effect = {
.type = ZDWM_EFFECT_WITHDRAW_WINDOW, .type = ZDWM_EFFECT_WITHDRAW_WINDOW,
.as.withdraw.window = window_id, .as.withdraw.window = window_id,
}; };
plan_push_effect(plan, &effect); plan_push_effect(plan, &effect);
@@ -104,7 +105,7 @@ void plan_push_move_effect(plan_t *plan, window_id_t window_id) {
if (window_id_invalid(window_id)) return; if (window_id_invalid(window_id)) return;
effect_t effect = { effect_t effect = {
.type = ZDWM_EFFECT_START_MOVE_WINDOW, .type = ZDWM_EFFECT_START_MOVE_WINDOW,
.as.move.window = window_id, .as.move.window = window_id,
}; };
plan_push_effect(plan, &effect); plan_push_effect(plan, &effect);
@@ -114,7 +115,7 @@ void plan_push_resize_effect(plan_t *plan, window_id_t window_id) {
if (window_id_invalid(window_id)) return; if (window_id_invalid(window_id)) return;
effect_t effect = { effect_t effect = {
.type = ZDWM_EFFECT_START_RESIZE_WINDOW, .type = ZDWM_EFFECT_START_RESIZE_WINDOW,
.as.resize.window = window_id, .as.resize.window = window_id,
}; };
plan_push_effect(plan, &effect); plan_push_effect(plan, &effect);
@@ -128,10 +129,10 @@ void plan_push_fullscreen_effect(
if (window_id_invalid(window_id)) return; if (window_id_invalid(window_id)) return;
effect_t effect = { effect_t effect = {
.type = ZDWM_EFFECT_FULLSCREEN_WINDOW, .type = ZDWM_EFFECT_FULLSCREEN_WINDOW,
.as.fullscreen = { .as.fullscreen = {
.window = window_id, .window = window_id,
.value = value, .value = value,
}, },
}; };
plan_push_effect(plan, &effect); plan_push_effect(plan, &effect);
@@ -145,10 +146,10 @@ void plan_push_maximize_effect(
if (window_id_invalid(window_id)) return; if (window_id_invalid(window_id)) return;
effect_t effect = { effect_t effect = {
.type = ZDWM_EFFECT_MAXIMIZE_WINDOW, .type = ZDWM_EFFECT_MAXIMIZE_WINDOW,
.as.maximize = { .as.maximize = {
.window = window_id, .window = window_id,
.value = value, .value = value,
}, },
}; };
plan_push_effect(plan, &effect); plan_push_effect(plan, &effect);
@@ -162,10 +163,10 @@ void plan_push_minimize_effect(
if (window_id_invalid(window_id)) return; if (window_id_invalid(window_id)) return;
effect_t effect = { effect_t effect = {
.type = ZDWM_EFFECT_MINIMIZE_WINDOW, .type = ZDWM_EFFECT_MINIMIZE_WINDOW,
.as.minimize = { .as.minimize = {
.window = window_id, .window = window_id,
.value = value, .value = value,
}, },
}; };
plan_push_effect(plan, &effect); plan_push_effect(plan, &effect);
@@ -179,10 +180,10 @@ void plan_push_change_border_color_effect(
if (window_id_invalid(window_id) || color == nullptr) return; if (window_id_invalid(window_id) || color == nullptr) return;
effect_t effect = { effect_t effect = {
.type = ZDWM_EFFECT_CHANGE_BORDER_COLOR, .type = ZDWM_EFFECT_CHANGE_BORDER_COLOR,
.as.change_border_color = { .as.change_border_color = {
.window = window_id, .window = window_id,
.color = color, .color = color,
}, },
}; };
plan_push_effect(plan, &effect); plan_push_effect(plan, &effect);

View File

@@ -1,89 +1,10 @@
#pragma once #pragma once
#include <stddef.h> #include <stddef.h>
#include <stdint.h>
#include "base/color.h" #include "base/color.h"
#include "core/types.h" #include "interface/effect.h"
#include "interface/types.h"
typedef enum effect_type_t {
ZDWM_EFFECT_MAP_WINDOW = 1,
ZDWM_EFFECT_UNMAP_WINDOW,
ZDWM_EFFECT_FOCUS_WINDOW,
ZDWM_EFFECT_KILL_WINDOW,
ZDWM_EFFECT_WITHDRAW_WINDOW,
ZDWM_EFFECT_START_MOVE_WINDOW,
ZDWM_EFFECT_START_RESIZE_WINDOW,
ZDWM_EFFECT_MINIMIZE_WINDOW,
ZDWM_EFFECT_MAXIMIZE_WINDOW,
ZDWM_EFFECT_FULLSCREEN_WINDOW,
ZDWM_EFFECT_CONFIGURE_WINDOW,
ZDWM_EFFECT_CHANGE_BORDER_COLOR,
ZDWM_EFFECT_CHANGE_WINDOW_LIST,
ZDWM_EFFECT_RESTACK_WINDOWS,
ZDWM_EFFECT_BIND_KEY,
ZDWM_EFFECT_GRAB_BUTTON,
ZDWM_EFFECT_UNGRAB_POINTER,
} effect_type_t;
typedef struct effect_move_window_t {
window_id_t window;
point_t left_top_point;
} effect_move_window_t;
typedef struct effect_resize_window_t {
window_id_t window;
int32_t width;
int32_t height;
} effect_resize_window_t;
typedef struct effect_change_border_color_t {
window_id_t window;
const color_t *color;
} effect_change_border_color_t;
typedef struct effect_window_list_t {
const window_id_t *windows;
size_t count;
} effect_window_list_t;
typedef struct effect_bind_key_t {
const key_bind_t *keys;
size_t count;
} effect_bind_key_t;
typedef struct effect_grab_button_t {
window_id_t window;
const grab_button_t *buttons;
size_t count;
} effect_grab_button_t;
typedef struct effect_bool_window_t {
window_id_t window;
bool value;
} effect_bool_window_t;
typedef struct effect_t {
effect_type_t type;
union {
only_window_data_t map;
only_window_data_t unmap;
only_window_data_t focus;
only_window_data_t kill;
only_window_data_t withdraw;
only_window_data_t move;
only_window_data_t resize;
effect_bool_window_t minimize;
effect_bool_window_t maximize;
effect_bool_window_t fullscreen;
configure_data_t configure;
effect_change_border_color_t change_border_color;
effect_window_list_t change_window_list;
effect_window_list_t restack_windows;
effect_bind_key_t bind_key;
effect_grab_button_t grab_button;
} as;
} effect_t;
typedef struct plan_t { typedef struct plan_t {
effect_t *effects; effect_t *effects;

View File

@@ -10,23 +10,23 @@
#include "base/memory.h" #include "base/memory.h"
#include "base/process.h" #include "base/process.h"
#include "base/time.h" #include "base/time.h"
#include "base/window_list.h" #include "common/listeners.h"
#include "common/window.h"
#include "core/binding.h" #include "core/binding.h"
#include "core/command.h" #include "core/command.h"
#include "core/command_buffer.h" #include "core/command_buffer.h"
#include "core/event.h"
#include "core/layout.h" #include "core/layout.h"
#include "core/listeners.h" #include "core/listeners.h"
#include "core/plan.h" #include "core/plan.h"
#include "core/rules.h" #include "core/rules.h"
#include "core/state.h" #include "core/state.h"
#include "core/types.h"
#include "core/window.h" #include "core/window.h"
#include "core/wm_desc.h" #include "interface/event.h"
#include "interface/types.h"
static void quit(bool restart, command_buffer_t *command_buffer) { static void quit(bool restart, command_buffer_t *command_buffer) {
command_t quit_command = { command_t quit_command = {
.type = ZDWM_COMMAND_QUIT, .type = ZDWM_COMMAND_QUIT,
.as.quit.will_restart = restart .as.quit.will_restart = restart
}; };
command_buffer_push(command_buffer, &quit_command); command_buffer_push(command_buffer, &quit_command);
@@ -34,7 +34,7 @@ static void quit(bool restart, command_buffer_t *command_buffer) {
static const window_t * static const window_t *
get_next_window_by_class(const state_t *state, const char *class_name) { get_next_window_by_class(const state_t *state, const char *class_name) {
auto output = state_output_at(state, state->current_output_index); auto output = state_output_at(state, state->current_output_index);
auto workspace = state_workspace_get(state, output->current_workspace_id); auto workspace = state_workspace_get(state, output->current_workspace_id);
size_t start_index = 0; size_t start_index = 0;
@@ -68,7 +68,7 @@ static void add_switch_workspace_command(
workspace_id_t workspace workspace_id_t workspace
) { ) {
command_t switch_workspace_cmd = { command_t switch_workspace_cmd = {
.type = ZDWM_COMMAND_SWITCH_WORKSPACE, .type = ZDWM_COMMAND_SWITCH_WORKSPACE,
.as.switch_workspace.workspace = workspace, .as.switch_workspace.workspace = workspace,
}; };
command_buffer_push(command_buffer, &switch_workspace_cmd); command_buffer_push(command_buffer, &switch_workspace_cmd);
@@ -77,7 +77,7 @@ static void add_switch_workspace_command(
static void static void
add_focus_window_command(command_buffer_t *command_buffer, window_id_t window) { add_focus_window_command(command_buffer_t *command_buffer, window_id_t window) {
command_t focus_command = { command_t focus_command = {
.type = ZDWM_COMMAND_FOCUS_WINDOW, .type = ZDWM_COMMAND_FOCUS_WINDOW,
.as.focus.window = window, .as.focus.window = window,
}; };
command_buffer_push(command_buffer, &focus_command); command_buffer_push(command_buffer, &focus_command);
@@ -101,9 +101,9 @@ static void raise_or_run(
static output_id_t get_cycled_output(const state_t *state, int32_t delta) { static output_id_t get_cycled_output(const state_t *state, int32_t delta) {
if (state->output_count <= 1) return ZDWM_OUTPUT_ID_INVALID; if (state->output_count <= 1) return ZDWM_OUTPUT_ID_INVALID;
int64_t count = (int64_t)state->output_count; int64_t count = (int64_t)state->output_count;
int64_t current = (int64_t)state->current_output_index; int64_t current = (int64_t)state->current_output_index;
int64_t next = (current + (int64_t)delta) % count; int64_t next = (current + (int64_t)delta) % count;
if (next < 0) next += count; if (next < 0) next += count;
auto output = state_output_at(state, (size_t)next); auto output = state_output_at(state, (size_t)next);
@@ -119,7 +119,7 @@ static void cycle_current_output(
if (output_id == ZDWM_OUTPUT_ID_INVALID) return; if (output_id == ZDWM_OUTPUT_ID_INVALID) return;
command_t cmd = { command_t cmd = {
.type = ZDWM_COMMAND_SET_CURRENT_OUTPUT, .type = ZDWM_COMMAND_SET_CURRENT_OUTPUT,
.as.current_output.output = output_id, .as.current_output.output = output_id,
}; };
command_buffer_push(command_buffer, &cmd); command_buffer_push(command_buffer, &cmd);
@@ -130,7 +130,7 @@ static void switch_workspace_same_output_by_index(
uint32_t index, uint32_t index,
command_buffer_t *command_buffer command_buffer_t *command_buffer
) { ) {
auto output = state_output_at(state, state->current_output_index); auto output = state_output_at(state, state->current_output_index);
uint32_t count = 0; uint32_t count = 0;
for (size_t i = 0; i < state_workspace_count(state); ++i) { for (size_t i = 0; i < state_workspace_count(state); ++i) {
auto workspace = state_workspace_at(state, i); auto workspace = state_workspace_at(state, i);
@@ -149,17 +149,17 @@ static void cycle_layout(
int32_t delta, int32_t delta,
command_buffer_t *command_buffer command_buffer_t *command_buffer
) { ) {
auto output = state_output_at(state, state->current_output_index); auto output = state_output_at(state, state->current_output_index);
auto workspace = state_workspace_get(state, output->current_workspace_id); auto workspace = state_workspace_get(state, output->current_workspace_id);
int32_t index = 0; int32_t index = 0;
bool matched = false; bool matched = false;
auto layout_count = (int32_t)workspace->layout_count; auto layout_count = (int32_t)workspace->layout_count;
if (layout_count <= 1) return; if (layout_count <= 1) return;
for (int32_t i = 0; i < layout_count; ++i) { for (int32_t i = 0; i < layout_count; ++i) {
if (workspace->layout_id == workspace->available_layouts[i]) { if (workspace->layout_id == workspace->available_layouts[i]) {
index = i; index = i;
matched = true; matched = true;
break; break;
} }
@@ -167,15 +167,15 @@ static void cycle_layout(
if (!matched) return; if (!matched) return;
auto new_index = index + delta; auto new_index = index + delta;
new_index %= layout_count; new_index %= layout_count;
if (new_index < 0) new_index += layout_count; if (new_index < 0) new_index += layout_count;
if (new_index == index) return; if (new_index == index) return;
auto next_layout_id = workspace->available_layouts[new_index]; auto next_layout_id = workspace->available_layouts[new_index];
command_t set_layout_command = { command_t set_layout_command = {
.type = ZDWM_COMMAND_SET_LAYOUT, .type = ZDWM_COMMAND_SET_LAYOUT,
.as.layout = {.workspace = workspace->id, .layout = next_layout_id}, .as.layout = {.workspace = workspace->id, .layout = next_layout_id},
}; };
command_buffer_push(command_buffer, &set_layout_command); command_buffer_push(command_buffer, &set_layout_command);
@@ -191,14 +191,14 @@ static void cycle_binding_mode(
if (next_mode_id == ZDWM_BINDING_MODE_ID_INVALID) return; if (next_mode_id == ZDWM_BINDING_MODE_ID_INVALID) return;
command_t set_binding_mode_command = { command_t set_binding_mode_command = {
.type = ZDWM_COMMAND_SET_BINDING_MODE, .type = ZDWM_COMMAND_SET_BINDING_MODE,
.as.binding_mode.mode = next_mode_id, .as.binding_mode.mode = next_mode_id,
}; };
command_buffer_push(command_buffer, &set_binding_mode_command); command_buffer_push(command_buffer, &set_binding_mode_command);
} }
static const window_t *get_current_focused_window(const state_t *state) { static const window_t *get_current_focused_window(const state_t *state) {
auto output = state_output_at(state, state->current_output_index); auto output = state_output_at(state, state->current_output_index);
auto workspace = state_workspace_get(state, output->current_workspace_id); auto workspace = state_workspace_get(state, output->current_workspace_id);
return state_window_get(state, workspace->focused_window_id); return state_window_get(state, workspace->focused_window_id);
} }
@@ -209,7 +209,7 @@ static const window_t *get_current_focused_window(const state_t *state) {
if (!window) return; \ if (!window) return; \
\ \
command_t command = { \ command_t command = { \
.type = (TYPE), \ .type = (TYPE), \
.as.DATA_FIELD = {.window = window->id, .state = !window->WINDOW_FIELD}, \ .as.DATA_FIELD = {.window = window->id, .state = !window->WINDOW_FIELD}, \
}; \ }; \
command_buffer_push(command_buffer, &command); \ command_buffer_push(command_buffer, &command); \
@@ -247,7 +247,7 @@ static void cycle_focused_window(
int32_t delta, int32_t delta,
command_buffer_t *command_buffer command_buffer_t *command_buffer
) { ) {
auto output = state_output_at(state, state->current_output_index); auto output = state_output_at(state, state->current_output_index);
auto workspace = state_workspace_get(state, output->current_workspace_id); auto workspace = state_workspace_get(state, output->current_workspace_id);
size_t count = state_window_count(state); size_t count = state_window_count(state);
@@ -282,7 +282,7 @@ static void cycle_focused_window(
add_focus_window_command(command_buffer, target->id); add_focus_window_command(command_buffer, target->id);
command_t raise_cmd = { command_t raise_cmd = {
.type = ZDWM_COMMAND_RAISE_WINDOW, .type = ZDWM_COMMAND_RAISE_WINDOW,
.as.raise.window = target->id, .as.raise.window = target->id,
}; };
command_buffer_push(command_buffer, &raise_cmd); command_buffer_push(command_buffer, &raise_cmd);
@@ -294,7 +294,7 @@ kill_window_action(const state_t *state, command_buffer_t *command_buffer) {
if (!window) return; if (!window) return;
command_t kill_window_command = { command_t kill_window_command = {
.type = ZDWM_COMMAND_KILL_WINDOW, .type = ZDWM_COMMAND_KILL_WINDOW,
.as.kill.window = window->id, .as.kill.window = window->id,
}; };
command_buffer_push(command_buffer, &kill_window_command); command_buffer_push(command_buffer, &kill_window_command);
@@ -313,18 +313,18 @@ static void cycle_window_output(
if (data->keep_focus) { if (data->keep_focus) {
command_t set_current_output_command = { command_t set_current_output_command = {
.type = ZDWM_COMMAND_SET_CURRENT_OUTPUT, .type = ZDWM_COMMAND_SET_CURRENT_OUTPUT,
.as.current_output.output = output_id, .as.current_output.output = output_id,
}; };
command_buffer_push(command_buffer, &set_current_output_command); command_buffer_push(command_buffer, &set_current_output_command);
} }
auto output = state_output_get(state, output_id); auto output = state_output_get(state, output_id);
auto workspace = state_workspace_get(state, output->current_workspace_id); auto workspace = state_workspace_get(state, output->current_workspace_id);
command_t send_window_to_workspace_command = { command_t send_window_to_workspace_command = {
.type = ZDWM_COMMAND_WINDOW_SEND_TO_WORKSPACE, .type = ZDWM_COMMAND_WINDOW_SEND_TO_WORKSPACE,
.as.send_to_workspace = { .as.send_to_workspace = {
.window = window->id, .window = window->id,
.workspace = workspace->id, .workspace = workspace->id,
}, },
}; };
@@ -349,9 +349,9 @@ static void send_window_to_workspace_same_output_by_index(
} }
command_t send_window_to_workspace_command = { command_t send_window_to_workspace_command = {
.type = ZDWM_COMMAND_WINDOW_SEND_TO_WORKSPACE, .type = ZDWM_COMMAND_WINDOW_SEND_TO_WORKSPACE,
.as.send_to_workspace = { .as.send_to_workspace = {
.window = current_workspace->focused_window_id, .window = current_workspace->focused_window_id,
.workspace = target_workspace->id, .workspace = target_workspace->id,
}, },
}; };
@@ -363,7 +363,7 @@ static void toggle_bar_visibility(
command_buffer_t *command_buffer command_buffer_t *command_buffer
) { ) {
command_t set_bar_visibility_command = { command_t set_bar_visibility_command = {
.type = ZDWM_COMMAND_SET_BAR_VISIBILITY, .type = ZDWM_COMMAND_SET_BAR_VISIBILITY,
.as.bar_visibility = { .as.bar_visibility = {
.visible = !*bar->visible, .visible = !*bar->visible,
}, },
@@ -449,7 +449,7 @@ static void route_key_press(
) { ) {
auto binding_table = ctx->bind_table; auto binding_table = ctx->bind_table;
size_t count = 0; size_t count = 0;
auto bindings = binding_table_get_current_bindings(binding_table, &count); auto bindings = binding_table_get_current_bindings(binding_table, &count);
if (!bindings) return; if (!bindings) return;
@@ -467,15 +467,15 @@ static void route_pointer_press(
command_buffer_t *out command_buffer_t *out
) { ) {
auto window_id = data->window; auto window_id = data->window;
auto window = state_window_get(ctx->state, window_id); auto window = state_window_get(ctx->state, window_id);
if (!window) return; if (!window) return;
/* TODO: 后续改为配置 */ /* TODO: 后续改为配置 */
if (data->button == ZDWM_BUTTON_LEFT && data->modifiers == ZDWM_MOD_4) { if (data->button == ZDWM_BUTTON_LEFT && data->modifiers == ZDWM_MOD_4) {
command_t start_move_cmd = { command_t start_move_cmd = {
.type = ZDWM_COMMAND_START_MOVE_WINDOW, .type = ZDWM_COMMAND_START_MOVE_WINDOW,
.as.move = { .as.move = {
.window = window_id, .window = window_id,
.pointer_coordinate = data->root, .pointer_coordinate = data->root,
}, },
}; };
@@ -483,9 +483,9 @@ static void route_pointer_press(
} }
if (data->button == ZDWM_BUTTON_RIGHT && data->modifiers == ZDWM_MOD_4) { if (data->button == ZDWM_BUTTON_RIGHT && data->modifiers == ZDWM_MOD_4) {
command_t start_resize_cmd = { command_t start_resize_cmd = {
.type = ZDWM_COMMAND_START_RESIZE_WINDOW, .type = ZDWM_COMMAND_START_RESIZE_WINDOW,
.as.resize = { .as.resize = {
.window = window_id, .window = window_id,
.pointer_coordinate = data->root, .pointer_coordinate = data->root,
} }
}; };
@@ -518,27 +518,27 @@ static void route_pointer_motion(
command_buffer_t *out command_buffer_t *out
) { ) {
auto interaction = ctx->interaction; auto interaction = ctx->interaction;
auto window_id = interaction->window; auto window_id = interaction->window;
switch (interaction->mode) { switch (interaction->mode) {
case ZDWM_WINDOW_INTERACTION_NONE: case ZDWM_WINDOW_INTERACTION_NONE:
break; break;
case ZDWM_WINDOW_INTERACTION_MOVE: { case ZDWM_WINDOW_INTERACTION_MOVE: {
auto time = interaction->last_change_time; auto time = interaction->last_change_time;
auto now = time_monotonic_ms(); auto now = time_monotonic_ms();
if (now - time < 1000 / ctx->fps) break; if (now - time < 1000 / ctx->fps) break;
auto rect = interaction->origin_rect; auto rect = interaction->origin_rect;
auto start = interaction->start_coordinate; auto start = interaction->start_coordinate;
auto end = data->root; auto end = data->root;
command_t configure = { command_t configure = {
.type = ZDWM_COMMAND_CONFIGURE_WINDOW, .type = ZDWM_COMMAND_CONFIGURE_WINDOW,
.as.configure = { .as.configure = {
.window = interaction->window, .window = interaction->window,
.changed_fields = ZDWM_CONFIGURE_FIELD_X | ZDWM_CONFIGURE_FIELD_Y, .changed_fields = ZDWM_CONFIGURE_FIELD_X | ZDWM_CONFIGURE_FIELD_Y,
.x = rect.x + (end.x - start.x), .x = rect.x + (end.x - start.x),
.y = rect.y + (end.y - start.y), .y = rect.y + (end.y - start.y),
}, },
}; };
command_buffer_push(out, &configure); command_buffer_push(out, &configure);
@@ -547,35 +547,35 @@ static void route_pointer_motion(
} break; } break;
case ZDWM_WINDOW_INTERACTION_RESIZE: { case ZDWM_WINDOW_INTERACTION_RESIZE: {
auto time = interaction->last_change_time; auto time = interaction->last_change_time;
auto now = time_monotonic_ms(); auto now = time_monotonic_ms();
if (now - time < 1000 / ctx->fps) break; if (now - time < 1000 / ctx->fps) break;
auto window = state_window_get(ctx->state, window_id); auto window = state_window_get(ctx->state, window_id);
if (!window_can_resize(window)) break; if (!window_can_resize(window)) break;
auto rect = interaction->origin_rect; auto rect = interaction->origin_rect;
auto start = interaction->start_coordinate; auto start = interaction->start_coordinate;
auto end = data->root; auto end = data->root;
auto min_size = window->min_size; auto min_size = window->min_size;
auto max_size = window->max_size; auto max_size = window->max_size;
auto width = rect.width + (end.x - start.x); auto width = rect.width + (end.x - start.x);
auto height = rect.height + (end.y - start.y); auto height = rect.height + (end.y - start.y);
width = MAX(width, min_size.width); width = MAX(width, min_size.width);
height = MAX(height, min_size.height); height = MAX(height, min_size.height);
width = MIN(width, max_size.width); width = MIN(width, max_size.width);
height = MIN(height, max_size.height); height = MIN(height, max_size.height);
if (!window_need_resize(window, width, height)) break; if (!window_need_resize(window, width, height)) break;
command_t configure_cmd = { command_t configure_cmd = {
.type = ZDWM_COMMAND_CONFIGURE_WINDOW, .type = ZDWM_COMMAND_CONFIGURE_WINDOW,
.as.configure = { .as.configure = {
.window = interaction->window, .window = interaction->window,
.changed_fields = .changed_fields =
ZDWM_CONFIGURE_FIELD_WIDTH | ZDWM_CONFIGURE_FIELD_HEIGHT, ZDWM_CONFIGURE_FIELD_WIDTH | ZDWM_CONFIGURE_FIELD_HEIGHT,
.width = width, .width = width,
.height = height, .height = height,
} }
}; };
@@ -609,32 +609,34 @@ static void route_map_request(
if (window) layer_type = MAX(window->layer, layer_type); if (window) layer_type = MAX(window->layer, layer_type);
} }
/* clang-format off */
command_t manage_window_cmd = { command_t manage_window_cmd = {
.type = ZDWM_COMMAND_MANAGE_WINDOW, .type = ZDWM_COMMAND_MANAGE_WINDOW,
.as.manage_window = { .as.manage_window = {
.workspace = derive_window_workspace(state), .workspace = derive_window_workspace(state),
.info = { .info = {
.id = e->window, .id = e->window,
.transient_for = e->transient_for, .transient_for = e->transient_for,
.frame_rect = e->rect, .frame_rect = e->rect,
.title = e->metadata.title, .title = e->metadata.title,
.app_id = e->metadata.app_id, .app_id = e->metadata.app_id,
.role = e->metadata.role, .role = e->metadata.role,
.class_name = e->metadata.class_name, .class_name = e->metadata.class_name,
.instance_name = e->metadata.instance_name, .instance_name = e->metadata.instance_name,
.layer_type = layer_type, .layer_type = layer_type,
.fullscreen = e->fullscreen, .fullscreen = e->fullscreen,
.maximized = e->maximized, .maximized = e->maximized,
.minimized = e->minimized, .minimized = e->minimized,
.urgent = e->urgent, .urgent = e->urgent,
.skip_taskbar = e->skip_taskbar, .skip_taskbar = e->skip_taskbar,
.min_size = e->min_size, .min_size = e->min_size,
.max_size = e->max_size, .max_size = e->max_size,
}, },
}, },
}; };
/* clang-format on */
rule_action_t action = {.workspace = ZDWM_WORKSPACE_ID_INVALID}; rule_action_t action = {.workspace = ZDWM_WORKSPACE_ID_INVALID};
bool have_rule_match = rules_resolve(rules, &e->metadata, &action); bool have_rule_match = rules_resolve(rules, &e->metadata, &action);
@@ -651,7 +653,7 @@ static void route_map_request(
command_buffer_push(out, &manage_window_cmd); command_buffer_push(out, &manage_window_cmd);
if (!have_rule_match || !action.switch_to_workspace) return; if (!have_rule_match || !action.switch_to_workspace) return;
workspace_id_t workspace_id = manage_window_cmd.as.manage_window.workspace; workspace_id_t workspace_id = manage_window_cmd.as.manage_window.workspace;
const workspace_t *workspace = state_workspace_get(state, workspace_id); const workspace_t *workspace = state_workspace_get(state, workspace_id);
if (!workspace) return; if (!workspace) return;
@@ -669,14 +671,14 @@ static void route_window_remove(
switch (e->reason) { switch (e->reason) {
case ZDWM_WINDOW_REMOVE_WITHDRAWN: case ZDWM_WINDOW_REMOVE_WITHDRAWN:
command_t withdrawn_window_cmd = { command_t withdrawn_window_cmd = {
.type = ZDWM_COMMAND_WITHDRAW_WINDOW, .type = ZDWM_COMMAND_WITHDRAW_WINDOW,
.as.withdraw.window = e->window, .as.withdraw.window = e->window,
}; };
command_buffer_push(out, &withdrawn_window_cmd); command_buffer_push(out, &withdrawn_window_cmd);
break; break;
case ZDWM_WINDOW_REMOVE_DESTROY: case ZDWM_WINDOW_REMOVE_DESTROY:
command_t unmanage_window_cmd = { command_t unmanage_window_cmd = {
.type = ZDWM_COMMAND_UNMANAGE_WINDOW, .type = ZDWM_COMMAND_UNMANAGE_WINDOW,
.as.unmanage.window = e->window, .as.unmanage.window = e->window,
}; };
command_buffer_push(out, &unmanage_window_cmd); command_buffer_push(out, &unmanage_window_cmd);
@@ -694,7 +696,7 @@ static void route_window_metadata_changed(
if (!window) return; if (!window) return;
auto window_id = e->window; auto window_id = e->window;
auto metadata = &e->metadata; auto metadata = &e->metadata;
if (e->changed_fields & ZDWM_WINDOW_METADATA_CHANGE_TITLE) { if (e->changed_fields & ZDWM_WINDOW_METADATA_CHANGE_TITLE) {
state_window_set_title(state, window_id, metadata->title); state_window_set_title(state, window_id, metadata->title);
@@ -723,7 +725,7 @@ static void route_window_hints_changed(
if (!window) return; if (!window) return;
command_t change_hints_cmd = { command_t change_hints_cmd = {
.type = ZDWM_COMMAND_CHANGE_HINTS, .type = ZDWM_COMMAND_CHANGE_HINTS,
.as.hints = *data, .as.hints = *data,
}; };
command_buffer_push(out, &change_hints_cmd); command_buffer_push(out, &change_hints_cmd);
@@ -759,9 +761,9 @@ static void route_window_state_request(
if (!window) return; if (!window) return;
command_t change_window_state_cmd = { command_t change_window_state_cmd = {
.type = ZDWM_COMMAND_CHANGE_WINDOW_STATE, .type = ZDWM_COMMAND_CHANGE_WINDOW_STATE,
.as.state_change = { .as.state_change = {
.type = e->type, .type = e->type,
.window = e->window, .window = e->window,
.action = e->action, .action = e->action,
} }
@@ -778,7 +780,7 @@ static void route_configure_request(
auto window = state_window_get(state, data->window); auto window = state_window_get(state, data->window);
if (!window) { if (!window) {
command_t configure_cmd = { command_t configure_cmd = {
.type = ZDWM_COMMAND_CONFIGURE_WINDOW, .type = ZDWM_COMMAND_CONFIGURE_WINDOW,
.as.configure = *data .as.configure = *data
}; };
command_buffer_push(out, &configure_cmd); command_buffer_push(out, &configure_cmd);
@@ -791,7 +793,7 @@ static void route_configure_request(
if (layout_get(layouts, workspace->layout_id)) return; if (layout_get(layouts, workspace->layout_id)) return;
command_t configure_rect_cmd = { command_t configure_rect_cmd = {
.type = ZDWM_COMMAND_CONFIGURE_WINDOW, .type = ZDWM_COMMAND_CONFIGURE_WINDOW,
.as.configure = *data, .as.configure = *data,
}; };
configure_rect_cmd.as.configure.changed_fields &= configure_rect_cmd.as.configure.changed_fields &=
@@ -871,7 +873,7 @@ static void set_foucs_window(
window_id_t window_id, window_id_t window_id,
plan_t *plan plan_t *plan
) { ) {
auto state = ctx->state; auto state = ctx->state;
auto border = ctx->border; auto border = ctx->border;
auto workspace = state_workspace_get(state, workspace_id); auto workspace = state_workspace_get(state, workspace_id);
@@ -900,10 +902,10 @@ static void push_window_list_effect(const state_t *state, plan_t *plan) {
window_list_push(&list, window->id); window_list_push(&list, window->id);
} }
effect_t effect = { effect_t effect = {
.type = ZDWM_EFFECT_CHANGE_WINDOW_LIST, .type = ZDWM_EFFECT_CHANGE_WINDOW_LIST,
.as.change_window_list = { .as.change_window_list = {
.windows = list.windows, .windows = list.windows,
.count = list.count, .count = list.count,
}, },
}; };
plan_push_effect(plan, &effect); plan_push_effect(plan, &effect);
@@ -917,11 +919,11 @@ static void plan_push_grab_button_effect(plan_t *plan, window_id_t window) {
}; };
constexpr const size_t count = countof(buttons); constexpr const size_t count = countof(buttons);
auto btns = p_new(grab_button_t, count); auto btns = p_new(grab_button_t, count);
memcpy(btns, buttons, sizeof(buttons)); memcpy(btns, buttons, sizeof(buttons));
effect_t grab_button_effect = { effect_t grab_button_effect = {
.type = ZDWM_EFFECT_GRAB_BUTTON, .type = ZDWM_EFFECT_GRAB_BUTTON,
.as.grab_button = {.window = window, .buttons = btns, .count = count}, .as.grab_button = {.window = window, .buttons = btns, .count = count},
}; };
plan_push_effect(plan, &grab_button_effect); plan_push_effect(plan, &grab_button_effect);
@@ -932,9 +934,9 @@ static void manage_window(
const manage_window_command_t *command, const manage_window_command_t *command,
plan_t *plan plan_t *plan
) { ) {
auto state = ctx->state; auto state = ctx->state;
auto window = state_window_add(state, &command->info); auto window = state_window_add(state, &command->info);
auto window_id = window->id; auto window_id = window->id;
auto workspace_id = command->workspace; auto workspace_id = command->workspace;
state_window_set_workspace(state, window_id, workspace_id); state_window_set_workspace(state, window_id, workspace_id);
set_foucs_window(ctx, workspace_id, window_id, plan); set_foucs_window(ctx, workspace_id, window_id, plan);
@@ -948,7 +950,7 @@ static void manage_window(
state_window_set_floating(state, window_id, command->floating); state_window_set_floating(state, window_id, command->floating);
} }
auto workspace = state_workspace_get(state, workspace_id); auto workspace = state_workspace_get(state, workspace_id);
auto need_layout = window_need_layout(window); auto need_layout = window_need_layout(window);
auto layout_func = layout_get(ctx->layouts, workspace->layout_id); auto layout_func = layout_get(ctx->layouts, workspace->layout_id);
@@ -966,14 +968,14 @@ static void manage_window(
plan->need_relayout = true; plan->need_relayout = true;
effect_t configure_effect = { effect_t configure_effect = {
.type = ZDWM_EFFECT_CONFIGURE_WINDOW, .type = ZDWM_EFFECT_CONFIGURE_WINDOW,
.as.configure = { .as.configure = {
.window = window_id, .window = window_id,
.x = window->frame_rect.x, .x = window->frame_rect.x,
.y = window->frame_rect.y, .y = window->frame_rect.y,
.width = window->frame_rect.width - 2 * (int32_t)window->border_width, .width = window->frame_rect.width - 2 * (int32_t)window->border_width,
.height = window->frame_rect.height - 2 * (int32_t)window->border_width, .height = window->frame_rect.height - 2 * (int32_t)window->border_width,
.border_width = window->border_width, .border_width = window->border_width,
.changed_fields = ZDWM_CONFIGURE_FIELD_X | ZDWM_CONFIGURE_FIELD_Y | .changed_fields = ZDWM_CONFIGURE_FIELD_X | ZDWM_CONFIGURE_FIELD_Y |
ZDWM_CONFIGURE_FIELD_WIDTH | ZDWM_CONFIGURE_FIELD_WIDTH |
ZDWM_CONFIGURE_FIELD_HEIGHT | ZDWM_CONFIGURE_FIELD_HEIGHT |
@@ -1008,14 +1010,14 @@ static void add_switch_workspace_effects(
static void static void
unmanage_window(const policy_context_t *ctx, window_id_t window, plan_t *plan) { unmanage_window(const policy_context_t *ctx, window_id_t window, plan_t *plan) {
auto state = ctx->state; auto state = ctx->state;
const window_t *win = state_window_get(state, window); const window_t *win = state_window_get(state, window);
if (!win) return; if (!win) return;
auto workspace_id = win->workspace_id; auto workspace_id = win->workspace_id;
auto workspace = state_workspace_get(state, workspace_id); auto workspace = state_workspace_get(state, workspace_id);
auto output = state_output_get(state, workspace->output_id); auto output = state_output_get(state, workspace->output_id);
auto need_layout = window_need_layout(win); auto need_layout = window_need_layout(win);
auto old_focused_window = workspace->focused_window_id; auto old_focused_window = workspace->focused_window_id;
state_window_remove(state, window); state_window_remove(state, window);
@@ -1040,11 +1042,11 @@ unmanage_window(const policy_context_t *ctx, window_id_t window, plan_t *plan) {
static void static void
focus_window(const policy_context_t *ctx, window_id_t window, plan_t *plan) { focus_window(const policy_context_t *ctx, window_id_t window, plan_t *plan) {
auto state = ctx->state; auto state = ctx->state;
auto win = state_window_get(state, window); auto win = state_window_get(state, window);
if (!win) return; if (!win) return;
auto workspace_id = win->workspace_id; auto workspace_id = win->workspace_id;
auto workspace = state_workspace_get(state, workspace_id); auto workspace = state_workspace_get(state, workspace_id);
auto old_focused_window = workspace->focused_window_id; auto old_focused_window = workspace->focused_window_id;
set_foucs_window(ctx, workspace_id, window, plan); set_foucs_window(ctx, workspace_id, window, plan);
@@ -1073,10 +1075,10 @@ static void raise_window(state_t *state, window_id_t window, plan_t *plan) {
} }
} }
effect_t restack_windows_effect = { effect_t restack_windows_effect = {
.type = ZDWM_EFFECT_RESTACK_WINDOWS, .type = ZDWM_EFFECT_RESTACK_WINDOWS,
.as.restack_windows = { .as.restack_windows = {
.windows = list.windows, .windows = list.windows,
.count = list.count, .count = list.count,
}, },
}; };
plan_push_effect(plan, &restack_windows_effect); plan_push_effect(plan, &restack_windows_effect);
@@ -1098,7 +1100,7 @@ configure_window(state_t *state, const configure_data_t *data, plan_t *plan) {
auto window = state_window_get(state, data->window); auto window = state_window_get(state, data->window);
if (!window) { if (!window) {
effect_t configure_effect = { effect_t configure_effect = {
.type = ZDWM_EFFECT_CONFIGURE_WINDOW, .type = ZDWM_EFFECT_CONFIGURE_WINDOW,
.as.configure = *data, .as.configure = *data,
}; };
plan_push_effect(plan, &configure_effect); plan_push_effect(plan, &configure_effect);
@@ -1116,19 +1118,19 @@ configure_window(state_t *state, const configure_data_t *data, plan_t *plan) {
#undef PICK_FIELD #undef PICK_FIELD
auto need_move = window_need_move(window, rect.x, rect.y); auto need_move = window_need_move(window, rect.x, rect.y);
auto need_resize = window_need_resize(window, rect.width, rect.height); auto need_resize = window_need_resize(window, rect.width, rect.height);
if (!need_move && !need_resize) return; if (!need_move && !need_resize) return;
state_window_set_frame_rect(state, window->id, rect); state_window_set_frame_rect(state, window->id, rect);
effect_t configure_effect = { effect_t configure_effect = {
.type = ZDWM_EFFECT_CONFIGURE_WINDOW, .type = ZDWM_EFFECT_CONFIGURE_WINDOW,
.as.configure = { .as.configure = {
.window = window->id, .window = window->id,
.x = rect.x, .x = rect.x,
.y = rect.y, .y = rect.y,
.width = rect.width, .width = rect.width,
.height = rect.height, .height = rect.height,
} }
}; };
@@ -1162,13 +1164,13 @@ static void add_window_floating_effect(
plan_t *plan plan_t *plan
) { ) {
effect_t configure_effect = { effect_t configure_effect = {
.type = ZDWM_EFFECT_CONFIGURE_WINDOW, .type = ZDWM_EFFECT_CONFIGURE_WINDOW,
.as.configure = { .as.configure = {
.window = window->id, .window = window->id,
.border_width = ctx->border->width, .border_width = ctx->border->width,
.x = window->frame_rect.x, .x = window->frame_rect.x,
.y = window->frame_rect.y, .y = window->frame_rect.y,
.width = window->frame_rect.width - 2 * (int32_t)ctx->border->width, .width = window->frame_rect.width - 2 * (int32_t)ctx->border->width,
.height = window->frame_rect.height - 2 * (int32_t)ctx->border->width, .height = window->frame_rect.height - 2 * (int32_t)ctx->border->width,
.changed_fields = ZDWM_CONFIGURE_FIELD_X | ZDWM_CONFIGURE_FIELD_Y | .changed_fields = ZDWM_CONFIGURE_FIELD_X | ZDWM_CONFIGURE_FIELD_Y |
ZDWM_CONFIGURE_FIELD_WIDTH | ZDWM_CONFIGURE_FIELD_WIDTH |
@@ -1203,7 +1205,7 @@ static void fullscreen_window(
bool value, bool value,
plan_t *plan plan_t *plan
) { ) {
auto state = ctx->state; auto state = ctx->state;
auto window = state_window_get(state, window_id); auto window = state_window_get(state, window_id);
if (!window) return; if (!window) return;
@@ -1272,7 +1274,7 @@ static void minimize_window(
bool value, bool value,
plan_t *plan plan_t *plan
) { ) {
auto state = ctx->state; auto state = ctx->state;
auto window = state_window_get(state, window_id); auto window = state_window_get(state, window_id);
if (!window) return; if (!window) return;
@@ -1364,16 +1366,16 @@ static void start_window_move(
plan_t *plan plan_t *plan
) { ) {
auto window_id = command->window; auto window_id = command->window;
auto window = state_window_get(ctx->state, window_id); auto window = state_window_get(ctx->state, window_id);
if (!window) return; if (!window) return;
plan_push_move_effect(plan, window_id); plan_push_move_effect(plan, window_id);
*ctx->interaction = (window_interaction_state_t){ *ctx->interaction = (window_interaction_state_t){
.mode = ZDWM_WINDOW_INTERACTION_MOVE, .mode = ZDWM_WINDOW_INTERACTION_MOVE,
.window = window_id, .window = window_id,
.start_coordinate = command->pointer_coordinate, .start_coordinate = command->pointer_coordinate,
.origin_rect = window->frame_rect, .origin_rect = window->frame_rect,
}; };
} }
@@ -1383,7 +1385,7 @@ static void start_window_resize(
plan_t *plan plan_t *plan
) { ) {
auto window_id = command->window; auto window_id = command->window;
auto window = state_window_get(ctx->state, window_id); auto window = state_window_get(ctx->state, window_id);
if (!window) return; if (!window) return;
auto frame_rect = window->frame_rect; auto frame_rect = window->frame_rect;
@@ -1396,10 +1398,10 @@ static void start_window_resize(
plan_push_resize_effect(plan, window_id); plan_push_resize_effect(plan, window_id);
*ctx->interaction = (window_interaction_state_t){ *ctx->interaction = (window_interaction_state_t){
.mode = ZDWM_WINDOW_INTERACTION_RESIZE, .mode = ZDWM_WINDOW_INTERACTION_RESIZE,
.window = window_id, .window = window_id,
.start_coordinate = pointer_position, .start_coordinate = pointer_position,
.origin_rect = frame_rect, .origin_rect = frame_rect,
}; };
} }
@@ -1408,7 +1410,7 @@ static void send_window_to_workspace(
const window_send_to_workspace_command_t *command, const window_send_to_workspace_command_t *command,
plan_t *plan plan_t *plan
) { ) {
auto state = ctx->state; auto state = ctx->state;
auto window = state_window_get(state, command->window); auto window = state_window_get(state, command->window);
if (!window) return; if (!window) return;
if (!state_workspace_valid(state, command->workspace)) return; if (!state_workspace_valid(state, command->workspace)) return;
@@ -1431,16 +1433,20 @@ static void send_window_to_workspace(
if (src_visible) { if (src_visible) {
if (src_ws && src_ws->focused_window_id != src_old_focused) { if (src_ws && src_ws->focused_window_id != src_old_focused) {
if (!window_id_invalid(src_old_focused) && if (
state_window_get(state, src_old_focused)) { !window_id_invalid(src_old_focused) &&
state_window_get(state, src_old_focused)
) {
plan_push_change_border_color_effect( plan_push_change_border_color_effect(
plan, plan,
src_old_focused, src_old_focused,
&ctx->border->normal_color &ctx->border->normal_color
); );
} }
if (!window_id_invalid(src_ws->focused_window_id) && if (
state_window_get(state, src_ws->focused_window_id)) { !window_id_invalid(src_ws->focused_window_id) &&
state_window_get(state, src_ws->focused_window_id)
) {
plan_push_focus_effect(plan, src_ws->focused_window_id); plan_push_focus_effect(plan, src_ws->focused_window_id);
plan_push_change_border_color_effect( plan_push_change_border_color_effect(
plan, plan,
@@ -1469,8 +1475,10 @@ static void send_window_to_workspace(
auto listeners = ctx->listeners; auto listeners = ctx->listeners;
listeners_notify_window_updated(listeners, state, command->window); listeners_notify_window_updated(listeners, state, command->window);
if (src_ws && src_ws->focused_window_id != src_old_focused && if (
!window_id_invalid(src_ws->focused_window_id)) { src_ws && src_ws->focused_window_id != src_old_focused &&
!window_id_invalid(src_ws->focused_window_id)
) {
listeners_notify_window_updated( listeners_notify_window_updated(
listeners, listeners,
state, state,
@@ -1547,20 +1555,22 @@ static void switch_workspace(
workspace_id_t workspace_id, workspace_id_t workspace_id,
plan_t *plan plan_t *plan
) { ) {
auto state = ctx->state; auto state = ctx->state;
auto workspace = state_workspace_get(state, workspace_id); auto workspace = state_workspace_get(state, workspace_id);
if (!workspace) return; if (!workspace) return;
auto listeners = ctx->listeners; auto listeners = ctx->listeners;
auto output_id = workspace->output_id; auto output_id = workspace->output_id;
workspace_id_t old_workspace = ZDWM_WORKSPACE_ID_INVALID; workspace_id_t old_workspace = ZDWM_WORKSPACE_ID_INVALID;
if (state_output_set_current_workspace( if (
state, state_output_set_current_workspace(
output_id, state,
workspace_id, output_id,
&old_workspace workspace_id,
)) { &old_workspace
)
) {
plan->need_relayout = true; plan->need_relayout = true;
add_switch_workspace_effects(state, old_workspace, workspace_id, plan); add_switch_workspace_effects(state, old_workspace, workspace_id, plan);
listeners_notify_workspace_active(listeners, output_id, workspace_id); listeners_notify_workspace_active(listeners, output_id, workspace_id);
@@ -1581,9 +1591,9 @@ static void set_layout(
const set_layout_command_t *command, const set_layout_command_t *command,
plan_t *plan plan_t *plan
) { ) {
auto state = ctx->state; auto state = ctx->state;
auto workspace_id = command->workspace; auto workspace_id = command->workspace;
auto layout_id = command->layout; auto layout_id = command->layout;
if (!state_workspace_set_layout_by_id(state, workspace_id, layout_id)) return; if (!state_workspace_set_layout_by_id(state, workspace_id, layout_id)) return;
@@ -1603,17 +1613,17 @@ static void set_binding_mode(
) { ) {
if (!binding_table_set_current_mode(ctx->bind_table, binding_mode)) return; if (!binding_table_set_current_mode(ctx->bind_table, binding_mode)) return;
size_t count = 0; size_t count = 0;
auto bindings = binding_table_get_current_bindings(ctx->bind_table, &count); auto bindings = binding_table_get_current_bindings(ctx->bind_table, &count);
if (bindings && count > 0) { if (bindings && count > 0) {
auto keys = p_new(key_bind_t, count); auto keys = p_new(key_bind_t, count);
for (size_t i = 0; i < count; ++i) { for (size_t i = 0; i < count; ++i) {
keys[i].keysym = bindings[i].keysym; keys[i].keysym = bindings[i].keysym;
keys[i].modifiers = bindings[i].modifiers; keys[i].modifiers = bindings[i].modifiers;
} }
effect_t effect = { effect_t effect = {
.type = ZDWM_EFFECT_BIND_KEY, .type = ZDWM_EFFECT_BIND_KEY,
.as.bind_key = {.count = count, .keys = keys}, .as.bind_key = {.count = count, .keys = keys},
}; };
plan_push_effect(plan, &effect); plan_push_effect(plan, &effect);
@@ -1711,7 +1721,7 @@ void policy_apply_command(
break; break;
case ZDWM_COMMAND_WINDOW_SET_FULLSCREEN: { case ZDWM_COMMAND_WINDOW_SET_FULLSCREEN: {
auto window = cmd->as.fullscreen.window; auto window = cmd->as.fullscreen.window;
auto state = cmd->as.fullscreen.state; auto state = cmd->as.fullscreen.state;
fullscreen_window(ctx, window, state, plan); fullscreen_window(ctx, window, state, plan);
} break; } break;
case ZDWM_COMMAND_CHANGE_HINTS: case ZDWM_COMMAND_CHANGE_HINTS:
@@ -1733,7 +1743,7 @@ void policy_apply_command(
set_bar_visibility(ctx, cmd->as.bar_visibility.visible, plan); set_bar_visibility(ctx, cmd->as.bar_visibility.visible, plan);
break; break;
case ZDWM_COMMAND_QUIT: case ZDWM_COMMAND_QUIT:
plan->quit = true; plan->quit = true;
plan->will_restart = cmd->as.quit.will_restart; plan->will_restart = cmd->as.quit.will_restart;
break; break;
} }

View File

@@ -3,16 +3,29 @@
#include <stdint.h> #include <stdint.h>
#include <zdwm/action.h> #include <zdwm/action.h>
#include "base/window_list.h" #include "common/listeners.h"
#include "common/window.h"
#include "core/binding.h" #include "core/binding.h"
#include "core/command_buffer.h" #include "core/command_buffer.h"
#include "core/event.h"
#include "core/layout.h" #include "core/layout.h"
#include "core/listeners.h"
#include "core/plan.h" #include "core/plan.h"
#include "core/rules.h" #include "core/rules.h"
#include "core/state.h" #include "core/state.h"
#include "core/types.h" #include "interface/event.h"
typedef enum window_interaction_mode_t {
ZDWM_WINDOW_INTERACTION_NONE,
ZDWM_WINDOW_INTERACTION_MOVE,
ZDWM_WINDOW_INTERACTION_RESIZE,
} window_interaction_mode_t;
typedef struct window_interaction_state_t {
window_interaction_mode_t mode;
window_id_t window;
point_t start_coordinate;
rect_t origin_rect;
uint64_t last_change_time;
} window_interaction_state_t;
typedef struct policy_bar_t { typedef struct policy_bar_t {
bool *visible; bool *visible;

View File

@@ -5,17 +5,17 @@
#include <zdwm/types.h> #include <zdwm/types.h>
#include "base/memory.h" #include "base/memory.h"
#include "core/types.h" #include "interface/types.h"
bool rules_move(rules_t *src, rules_t *dest) { bool rules_move(rules_t *src, rules_t *dest) {
if (!dest || !src) return false; if (!dest || !src) return false;
dest->items = src->items; dest->items = src->items;
dest->count = src->count; dest->count = src->count;
dest->capacity = src->capacity; dest->capacity = src->capacity;
src->items = nullptr; src->items = nullptr;
src->count = 0; src->count = 0;
src->capacity = 0; src->capacity = 0;
return true; return true;
@@ -23,7 +23,7 @@ bool rules_move(rules_t *src, rules_t *dest) {
void rules_cleanup(rules_t *rules) { void rules_cleanup(rules_t *rules) {
for (size_t i = 0; i < rules->count; ++i) { for (size_t i = 0; i < rules->count; ++i) {
rule_match_t *match = &rules->items[i].match; rule_match_t *match = &rules->items[i].match;
rule_action_t *action = &rules->items[i].action; rule_action_t *action = &rules->items[i].action;
p_delete(&match->app_id); p_delete(&match->app_id);
@@ -37,7 +37,7 @@ void rules_cleanup(rules_t *rules) {
p_delete(&rules->items); p_delete(&rules->items);
rules->capacity = 0; rules->capacity = 0;
rules->count = 0; rules->count = 0;
} }
static inline bool str_match(const char *pattern, const char *value) { static inline bool str_match(const char *pattern, const char *value) {
@@ -59,9 +59,9 @@ static void rule_action_merge(const rule_action_t *src, rule_action_t *dest) {
dest->workspace = src->workspace; dest->workspace = src->workspace;
} }
dest->switch_to_workspace |= src->switch_to_workspace; dest->switch_to_workspace |= src->switch_to_workspace;
dest->fullscreen |= src->fullscreen; dest->fullscreen |= src->fullscreen;
dest->maximize |= src->maximize; dest->maximize |= src->maximize;
dest->floating |= src->floating; dest->floating |= src->floating;
} }
bool rules_resolve( bool rules_resolve(

View File

@@ -2,8 +2,7 @@
#include <stddef.h> #include <stddef.h>
#include "core/types.h" #include "interface/types.h"
#include "core/window.h"
typedef struct rule_item_t { typedef struct rule_item_t {
rule_match_t match; rule_match_t match;

View File

@@ -8,11 +8,12 @@
#include "base/array.h" #include "base/array.h"
#include "base/log.h" #include "base/log.h"
#include "base/memory.h" #include "base/memory.h"
#include "base/window_list.h" #include "common/window.h"
#include "common/workspace.h"
#include "core/layer.h" #include "core/layer.h"
#include "core/types.h"
#include "core/window.h" #include "core/window.h"
#include "core/wm_desc.h" #include "core/window_info.h"
#include "interface/types.h"
void state_init( void state_init(
state_t *state, state_t *state,
@@ -26,13 +27,13 @@ void state_init(
state->outputs = p_new(output_t, output_count); state->outputs = p_new(output_t, output_count);
for (size_t i = 0; i < output_count; i++) { for (size_t i = 0; i < output_count; i++) {
const output_info_t *output_info = &outputs[i]; const output_info_t *output_info = &outputs[i];
output_t *output = &state->outputs[i]; output_t *output = &state->outputs[i];
output->id = (output_id_t)i; output->id = (output_id_t)i;
output->current_workspace_id = ZDWM_WORKSPACE_ID_INVALID; output->current_workspace_id = ZDWM_WORKSPACE_ID_INVALID;
output->name = p_strdup_nullable(output_info->name); output->name = p_strdup_nullable(output_info->name);
output->geometry = output_info->geometry; output->geometry = output_info->geometry;
output->workarea = output_info->geometry; output->workarea = output_info->geometry;
} }
state->output_count = output_count; state->output_count = output_count;
@@ -43,16 +44,16 @@ void state_init(
fatal("workspace desc at index %zu invalid", i); fatal("workspace desc at index %zu invalid", i);
} }
output_t *output = &state->outputs[workspace_desc->output_index]; output_t *output = &state->outputs[workspace_desc->output_index];
workspace_t *workspace = &state->workspaces[i]; workspace_t *workspace = &state->workspaces[i];
workspace->id = (workspace_id_t)i; workspace->id = (workspace_id_t)i;
workspace->output_id = output->id; workspace->output_id = output->id;
workspace->focused_window_id = ZDWM_WINDOW_ID_INVALID; workspace->focused_window_id = ZDWM_WINDOW_ID_INVALID;
workspace->available_layouts = workspace->available_layouts =
p_copy(workspace_desc->layout_ids, workspace_desc->layout_count); p_copy(workspace_desc->layout_ids, workspace_desc->layout_count);
workspace->layout_id = workspace_desc->initial_layout_id; workspace->layout_id = workspace_desc->initial_layout_id;
workspace->layout_count = workspace_desc->layout_count; workspace->layout_count = workspace_desc->layout_count;
workspace->name = p_strdup(workspace_desc->name); workspace->name = p_strdup(workspace_desc->name);
if (workspace_id_invalid(output->current_workspace_id)) { if (workspace_id_invalid(output->current_workspace_id)) {
output->current_workspace_id = workspace->id; output->current_workspace_id = workspace->id;
@@ -84,7 +85,7 @@ void state_cleanup(state_t *state) {
for (size_t i = 0; i < ZDWM_WINDOW_LAYER_COUNT; ++i) { for (size_t i = 0; i < ZDWM_WINDOW_LAYER_COUNT; ++i) {
layer_stack_t *layer = &state->stacks[i]; layer_stack_t *layer = &state->stacks[i];
p_delete(&layer->order); p_delete(&layer->order);
layer->order = 0; layer->order = 0;
layer->capacity = 0; layer->capacity = 0;
} }
@@ -134,7 +135,7 @@ static void state_workspace_adjust_focused_window(
const layer_stack_t *layer = &state->stacks[i]; const layer_stack_t *layer = &state->stacks[i];
for (size_t i = layer->count; i > 0; --i) { for (size_t i = layer->count; i > 0; --i) {
window_id_t window_id = layer->order[i - 1]; window_id_t window_id = layer->order[i - 1];
window = state_window_get(state, window_id); window = state_window_get(state, window_id);
if (window && window->workspace_id == workspace_id) { if (window && window->workspace_id == workspace_id) {
workspace->focused_window_id = window_id; workspace->focused_window_id = window_id;
return; return;
@@ -218,7 +219,7 @@ bool state_workspace_valid(const state_t *state, workspace_id_t id) {
bool state_workspace_show(const state_t *state, workspace_id_t workspace_id) { bool state_workspace_show(const state_t *state, workspace_id_t workspace_id) {
auto workspace = state_workspace_get(state, workspace_id); auto workspace = state_workspace_get(state, workspace_id);
auto output = state_output_get(state, workspace->output_id); auto output = state_output_get(state, workspace->output_id);
return output->current_workspace_id == workspace_id; return output->current_workspace_id == workspace_id;
} }
@@ -240,12 +241,12 @@ void state_output_inset_workarea(
auto output = (output_t *)state_output_get(state, output_id); auto output = (output_t *)state_output_get(state, output_id);
if (!output) return; if (!output) return;
auto workarea = output->geometry; auto workarea = output->geometry;
workarea.y += inset.top; workarea.y += inset.top;
workarea.x += inset.left; workarea.x += inset.left;
workarea.width -= inset.left + inset.right; workarea.width -= inset.left + inset.right;
workarea.height -= inset.top + inset.bottom; workarea.height -= inset.top + inset.bottom;
output->workarea = workarea; output->workarea = workarea;
} }
void state_output_set_workarea( void state_output_set_workarea(
@@ -308,7 +309,7 @@ bool state_set_current_output(state_t *state, output_id_t output_id) {
} }
const window_t *state_window_add(state_t *state, const window_info_t *info) { const window_t *state_window_add(state_t *state, const window_info_t *info) {
window_id_t id = info->id; window_id_t id = info->id;
window_t *window = (window_t *)state_window_get(state, id); window_t *window = (window_t *)state_window_get(state, id);
if (!window) { if (!window) {
window = window =
@@ -318,10 +319,10 @@ const window_t *state_window_add(state_t *state, const window_info_t *info) {
layer_stack_append(layer, id); layer_stack_append(layer, id);
p_clear(window, 1); p_clear(window, 1);
window->id = id; window->id = id;
window->transient_for = info->transient_for; window->transient_for = info->transient_for;
window->workspace_id = ZDWM_WORKSPACE_ID_INVALID; window->workspace_id = ZDWM_WORKSPACE_ID_INVALID;
window->layer = info->layer_type; window->layer = info->layer_type;
} }
window_set_fullscreen(window, info->fullscreen); window_set_fullscreen(window, info->fullscreen);
@@ -361,15 +362,15 @@ void state_window_remove(state_t *state, window_id_t id) {
for (size_t i = 0; i < state->window_count; i++) { for (size_t i = 0; i < state->window_count; i++) {
if (state->windows[i].id == id) { if (state->windows[i].id == id) {
matched = true; matched = true;
index = i; index = i;
break; break;
} }
} }
if (!matched) return; if (!matched) return;
window_t *window = &state->windows[index]; window_t *window = &state->windows[index];
window_layer_type_t layer_type = window->layer; window_layer_type_t layer_type = window->layer;
workspace_id_t workspace_id = window->workspace_id; workspace_id_t workspace_id = window->workspace_id;
p_delete(&window->title); p_delete(&window->title);
p_delete(&window->app_id); p_delete(&window->app_id);
p_delete(&window->role); p_delete(&window->role);
@@ -379,9 +380,9 @@ void state_window_remove(state_t *state, window_id_t id) {
if (array_erase(state->windows, state->window_count, index)) { if (array_erase(state->windows, state->window_count, index)) {
window = &state->windows[state->window_count]; window = &state->windows[state->window_count];
p_clear(window, 1); p_clear(window, 1);
window->id = ZDWM_WINDOW_ID_INVALID; window->id = ZDWM_WINDOW_ID_INVALID;
window->transient_for = ZDWM_WINDOW_ID_INVALID; window->transient_for = ZDWM_WINDOW_ID_INVALID;
window->workspace_id = ZDWM_WORKSPACE_ID_INVALID; window->workspace_id = ZDWM_WORKSPACE_ID_INVALID;
for (size_t i = 0; i < state->window_count; ++i) { for (size_t i = 0; i < state->window_count; ++i) {
window = &state->windows[i]; window = &state->windows[i];
@@ -411,10 +412,10 @@ void state_window_set_workspace(
workspace_id_t workspace_id workspace_id_t workspace_id
) { ) {
const workspace_t *workspace = state_workspace_get(state, workspace_id); const workspace_t *workspace = state_workspace_get(state, workspace_id);
window_t *window = (window_t *)state_window_get(state, window_id); window_t *window = (window_t *)state_window_get(state, window_id);
if (!workspace || !window || window->workspace_id == workspace_id) return; if (!workspace || !window || window->workspace_id == workspace_id) return;
workspace = state_workspace_get(state, window->workspace_id); workspace = state_workspace_get(state, window->workspace_id);
window->workspace_id = workspace_id; window->workspace_id = workspace_id;
if (workspace && workspace->focused_window_id == window_id) { if (workspace && workspace->focused_window_id == window_id) {

View File

@@ -3,11 +3,12 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include "base/window_list.h" #include "common/window.h"
#include "common/workspace.h"
#include "core/layer.h" #include "core/layer.h"
#include "core/types.h"
#include "core/window.h" #include "core/window.h"
#include "core/wm_desc.h" #include "core/window_info.h"
#include "interface/types.h"
typedef struct workspace_t { typedef struct workspace_t {
workspace_id_t id; workspace_id_t id;

View File

@@ -1,40 +1,7 @@
#include "core/window.h" #include "core/window.h"
#include "base/memory.h" #include "base/memory.h"
#include "core/types.h" #include "interface/types.h"
window_layer_type_t window_classify_layer(const window_layer_props_t *props) {
for (size_t i = 0; i < props->type_count; ++i) {
window_type_t type = props->types[i];
if (type == ZDWM_WINDOW_TYPE_NOTIFICATION) return ZDWM_WINDOW_LAYER_OVERLAY;
}
for (size_t i = 0; i < props->state_count; ++i) {
window_state_t state = props->states[i];
if (state == ZDWM_WINDOW_STATE_ABOVE) return ZDWM_WINDOW_LAYER_TOP;
}
return ZDWM_WINDOW_LAYER_NORMAL;
}
void window_layer_props_cleanup(window_layer_props_t *props) {
if (!props) return;
p_delete(&props->types);
props->type_count = 0;
p_delete(&props->states);
props->state_count = 0;
}
void window_metadata_cleanup(window_metadata_t *metadata) {
if (!metadata) return;
p_delete(&metadata->title);
p_delete(&metadata->app_id);
p_delete(&metadata->role);
p_delete(&metadata->class_name);
p_delete(&metadata->instance_name);
}
void window_set_fullscreen(window_t *window, bool fullscreen) { void window_set_fullscreen(window_t *window, bool fullscreen) {
window->fullscreen = fullscreen; window->fullscreen = fullscreen;
@@ -84,8 +51,8 @@ void window_set_size_hint(window_t *window, zdwm_size_t min, zdwm_size_t max) {
window->max_size = max; window->max_size = max;
if (!window_should_fix_size(window)) return; if (!window_should_fix_size(window)) return;
auto rect = window->frame_rect; auto rect = window->frame_rect;
rect.width = min.width; rect.width = min.width;
rect.height = min.height; rect.height = min.height;
window_set_frame_rect(window, rect); window_set_frame_rect(window, rect);
window_set_floating(window, true); window_set_floating(window, true);

View File

@@ -3,66 +3,7 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include "core/types.h" #include "interface/types.h"
/* Internal semantic window types mapped from backend-specific protocols. */
typedef enum window_type_t {
ZDWM_WINDOW_TYPE_NORMAL = 0,
ZDWM_WINDOW_TYPE_DESKTOP,
ZDWM_WINDOW_TYPE_DOCK,
ZDWM_WINDOW_TYPE_TOOLBAR,
ZDWM_WINDOW_TYPE_DIALOG,
ZDWM_WINDOW_TYPE_UTILITY,
ZDWM_WINDOW_TYPE_SPLASH,
ZDWM_WINDOW_TYPE_MENU,
ZDWM_WINDOW_TYPE_DROPDOWN_MENU,
ZDWM_WINDOW_TYPE_POPUP_MENU,
ZDWM_WINDOW_TYPE_TOOLTIP,
ZDWM_WINDOW_TYPE_COMBO,
ZDWM_WINDOW_TYPE_DND,
ZDWM_WINDOW_TYPE_NOTIFICATION,
} window_type_t;
/* Internal semantic window states mapped from backend-specific protocols. */
typedef enum window_state_t {
ZDWM_WINDOW_STATE_ABOVE = 0,
ZDWM_WINDOW_STATE_FULLSCREEN,
ZDWM_WINDOW_STATE_MODAL,
ZDWM_WINDOW_STATE_STICKY,
} window_state_t;
/* 层级从低到高 */
typedef enum window_layer_type_t {
ZDWM_WINDOW_LAYER_DESKTOP = 0,
ZDWM_WINDOW_LAYER_NORMAL,
ZDWM_WINDOW_LAYER_TOP,
ZDWM_WINDOW_LAYER_OVERLAY,
ZDWM_WINDOW_LAYER_COUNT,
} window_layer_type_t;
typedef enum window_metadata_change_flags_t {
ZDWM_WINDOW_METADATA_CHANGE_TITLE = 1u << 0,
ZDWM_WINDOW_METADATA_CHANGE_APP_ID = 1u << 1,
ZDWM_WINDOW_METADATA_CHANGE_ROLE = 1u << 2,
ZDWM_WINDOW_METADATA_CHANGE_CLASS = 1u << 3,
ZDWM_WINDOW_METADATA_CHANGE_INSTANCE = 1u << 4,
} window_metadata_change_flags_t;
typedef struct window_layer_props_t {
window_type_t *types;
size_t type_count;
window_state_t *states;
size_t state_count;
} window_layer_props_t;
typedef struct window_metadata_t {
char *title;
char *app_id;
char *role;
char *class_name;
char *instance_name;
} window_metadata_t;
typedef struct window_t { typedef struct window_t {
window_id_t id; window_id_t id;
@@ -95,11 +36,6 @@ typedef struct window_t {
uint32_t border_width; uint32_t border_width;
} window_t; } window_t;
window_layer_type_t window_classify_layer(const window_layer_props_t *props);
void window_layer_props_cleanup(window_layer_props_t *props);
void window_metadata_cleanup(window_metadata_t *metadata);
void window_set_fullscreen(window_t *window, bool fullscreen); void window_set_fullscreen(window_t *window, bool fullscreen);
void window_set_maximized(window_t *window, bool maximized); void window_set_maximized(window_t *window, bool maximized);
void window_set_minimized(window_t *window, bool minimized); void window_set_minimized(window_t *window, bool minimized);

30
src/core/window_info.h Normal file
View File

@@ -0,0 +1,30 @@
#pragma once
#include "interface/types.h"
/*
* 由 backend 提供的窗口基础信息。
*
* 这些字符串由调用方提供state 如需长期持有,应自行复制。
*/
typedef struct window_info_t {
window_id_t id;
window_id_t transient_for;
rect_t frame_rect;
const char *title;
const char *app_id;
const char *role;
const char *class_name;
const char *instance_name;
window_layer_type_t layer_type;
bool fullscreen;
bool maximized;
bool minimized;
bool urgent;
bool skip_taskbar;
zdwm_size_t min_size;
zdwm_size_t max_size;
} window_info_t;

View File

@@ -1,91 +0,0 @@
#pragma once
#include <stddef.h>
#include "base/memory.h"
#include "core/types.h"
#include "core/window.h"
/*
* 由 backend 提供的窗口基础信息。
*
* 这些字符串由调用方提供state 如需长期持有,应自行复制。
*/
typedef struct window_info_t {
window_id_t id;
window_id_t transient_for;
rect_t frame_rect;
const char *title;
const char *app_id;
const char *role;
const char *class_name;
const char *instance_name;
window_layer_type_t layer_type;
bool fullscreen;
bool maximized;
bool minimized;
bool urgent;
bool skip_taskbar;
zdwm_size_t min_size;
zdwm_size_t max_size;
} window_info_t;
typedef struct workspace_desc_t {
size_t output_index; /* 对应 state_init() 中 outputs[] 的索引 */
const char *name;
const layout_id_t *layout_ids;
size_t layout_count;
layout_id_t initial_layout_id;
} workspace_desc_t;
static inline void workspace_desc_cleanup(workspace_desc_t *workspace) {
if (!workspace) return;
p_delete(&workspace->name);
p_delete(&workspace->layout_ids);
workspace->output_index = 0;
workspace->layout_count = 0;
workspace->initial_layout_id = ZDWM_LAYOUT_ID_INVALID;
}
static inline void
workspace_desc_list_cleanup(workspace_desc_t **list, size_t *count) {
if (!list || !count) return;
for (size_t i = 0; i < *count; i++) {
workspace_desc_cleanup(&(*list)[i]);
}
p_delete(list);
*count = 0;
}
/*
* workspace 描述校验接口。
*
* 这组接口只校验描述表自身的一致性,不访问 state。
*/
static inline bool workspace_desc_layouts_valid(
const workspace_desc_t *workspace
) {
if (!workspace || !workspace->layout_count || !workspace->layout_ids) {
return false;
}
for (size_t i = 0; i < workspace->layout_count; i++) {
if (workspace->layout_ids[i] == workspace->initial_layout_id) return true;
}
return false;
}
static inline bool
workspace_desc_valid(const workspace_desc_t *workspace, size_t output_count) {
if (!workspace || !workspace->name) return false;
if (workspace->output_index >= output_count) return false;
return workspace_desc_layouts_valid(workspace);
}

View File

@@ -3,9 +3,9 @@
#include <cairo.h> #include <cairo.h>
#include <stddef.h> #include <stddef.h>
#include "core/event.h" #include "interface/effect.h"
#include "core/plan.h" #include "interface/event.h"
#include "core/types.h" #include "interface/types.h"
typedef struct backend_t backend_t; typedef struct backend_t backend_t;

95
src/interface/effect.h Normal file
View File

@@ -0,0 +1,95 @@
#pragma once
#include <stddef.h>
#include "base/color.h"
#include "interface/types.h"
typedef enum effect_type_t {
ZDWM_EFFECT_MAP_WINDOW = 1,
ZDWM_EFFECT_UNMAP_WINDOW,
ZDWM_EFFECT_FOCUS_WINDOW,
ZDWM_EFFECT_KILL_WINDOW,
ZDWM_EFFECT_WITHDRAW_WINDOW,
ZDWM_EFFECT_START_MOVE_WINDOW,
ZDWM_EFFECT_START_RESIZE_WINDOW,
ZDWM_EFFECT_MINIMIZE_WINDOW,
ZDWM_EFFECT_MAXIMIZE_WINDOW,
ZDWM_EFFECT_FULLSCREEN_WINDOW,
ZDWM_EFFECT_CONFIGURE_WINDOW,
ZDWM_EFFECT_CHANGE_BORDER_COLOR,
ZDWM_EFFECT_CHANGE_WINDOW_LIST,
ZDWM_EFFECT_RESTACK_WINDOWS,
ZDWM_EFFECT_BIND_KEY,
ZDWM_EFFECT_GRAB_BUTTON,
ZDWM_EFFECT_UNGRAB_POINTER,
} effect_type_t;
typedef struct effect_move_window_t {
window_id_t window;
point_t left_top_point;
} effect_move_window_t;
typedef struct effect_resize_window_t {
window_id_t window;
int32_t width;
int32_t height;
} effect_resize_window_t;
typedef struct effect_change_border_color_t {
window_id_t window;
const color_t *color;
} effect_change_border_color_t;
typedef struct effect_window_list_t {
const window_id_t *windows;
size_t count;
} effect_window_list_t;
typedef struct key_bind_t {
modifier_mask_t modifiers;
keysym_t keysym;
} key_bind_t;
typedef struct effect_bind_key_t {
const key_bind_t *keys;
size_t count;
} effect_bind_key_t;
typedef struct grab_button_t {
modifier_mask_t modifiers;
button_t button;
} grab_button_t;
typedef struct effect_grab_button_t {
window_id_t window;
const grab_button_t *buttons;
size_t count;
} effect_grab_button_t;
typedef struct effect_bool_window_t {
window_id_t window;
bool value;
} effect_bool_window_t;
typedef struct effect_t {
effect_type_t type;
union {
only_window_data_t map;
only_window_data_t unmap;
only_window_data_t focus;
only_window_data_t kill;
only_window_data_t withdraw;
only_window_data_t move;
only_window_data_t resize;
effect_bool_window_t minimize;
effect_bool_window_t maximize;
effect_bool_window_t fullscreen;
configure_data_t configure;
effect_change_border_color_t change_border_color;
effect_window_list_t change_window_list;
effect_window_list_t restack_windows;
effect_bind_key_t bind_key;
effect_grab_button_t grab_button;
} as;
} effect_t;

View File

@@ -2,8 +2,7 @@
#include <stdint.h> #include <stdint.h>
#include "core/types.h" #include "interface/types.h"
#include "core/window.h"
typedef enum event_type_t { typedef enum event_type_t {
ZDWM_EVENT_NONE, ZDWM_EVENT_NONE,
@@ -75,11 +74,13 @@ typedef struct window_metadata_change_event_t {
window_metadata_t metadata; window_metadata_t metadata;
} window_metadata_change_event_t; } window_metadata_change_event_t;
/* clang-format off */
typedef enum window_activation_source_t { typedef enum window_activation_source_t {
ZDWM_WINDOW_ACTIVATION_SOURCE_LEGACY = 0, ZDWM_WINDOW_ACTIVATION_SOURCE_LEGACY = 0,
ZDWM_WINDOW_ACTIVATION_SOURCE_APPLICATION = 1, ZDWM_WINDOW_ACTIVATION_SOURCE_APPLICATION = 1,
ZDWM_WINDOW_ACTIVATION_SOURCE_PAGER = 2, ZDWM_WINDOW_ACTIVATION_SOURCE_PAGER = 2,
} window_activation_source_t; } window_activation_source_t;
/* clang-format on */
typedef struct window_activate_request_event_t { typedef struct window_activate_request_event_t {
window_id_t window; window_id_t window;
@@ -109,6 +110,3 @@ typedef struct event_t {
configure_data_t configure_request; configure_data_t configure_request;
} as; } as;
} event_t; } event_t;
void event_cleanup(event_t *event);
void event_reset(event_t *event);

View File

@@ -1,5 +1,6 @@
#pragma once #pragma once
#include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <zdwm/rules.h> #include <zdwm/rules.h>
#include <zdwm/types.h> #include <zdwm/types.h>
@@ -32,25 +33,64 @@ typedef struct point_t {
int32_t y; int32_t y;
} point_t; } point_t;
typedef enum focus_direction_t { typedef struct zdwm_size_t {
ZDWM_FOCUS_PREV, int32_t width;
ZDWM_FOCUS_NEXT, int32_t height;
} focus_direction_t; } zdwm_size_t;
typedef enum cross_output_policy_t { typedef struct only_window_data_t {
ZDWM_CROSS_OUTPUT_KEEP_WORKSPACE, window_id_t window;
ZDWM_CROSS_OUTPUT_MOVE_TO_TARGET_WORKSPACE, } only_window_data_t;
} cross_output_policy_t;
typedef struct key_bind_t { /* clang-format off */
modifier_mask_t modifiers; typedef enum configure_field_t {
keysym_t keysym; ZDWM_CONFIGURE_FIELD_X = 1u << 0,
} key_bind_t; ZDWM_CONFIGURE_FIELD_Y = 1u << 1,
ZDWM_CONFIGURE_FIELD_WIDTH = 1u << 2,
ZDWM_CONFIGURE_FIELD_HEIGHT = 1u << 3,
ZDWM_CONFIGURE_FIELD_BORDER_WIDTH = 1u << 4,
ZDWM_CONFIGURE_FIELD_SIBLING = 1u << 5,
ZDWM_CONFIGURE_FIELD_STACK_MODE = 1u << 6,
} configure_field_t;
/* clang-format on */
typedef struct grab_button_t { typedef struct configure_data_t {
modifier_mask_t modifiers; window_id_t window;
button_t button; uint32_t changed_fields;
} grab_button_t; int32_t x;
int32_t y;
int32_t width;
int32_t height;
uint32_t border_width;
window_id_t sibling;
uint32_t stack_mode;
} configure_data_t;
/* Internal semantic window types mapped from backend-specific protocols. */
typedef enum window_type_t {
ZDWM_WINDOW_TYPE_NORMAL = 0,
ZDWM_WINDOW_TYPE_DESKTOP,
ZDWM_WINDOW_TYPE_DOCK,
ZDWM_WINDOW_TYPE_TOOLBAR,
ZDWM_WINDOW_TYPE_DIALOG,
ZDWM_WINDOW_TYPE_UTILITY,
ZDWM_WINDOW_TYPE_SPLASH,
ZDWM_WINDOW_TYPE_MENU,
ZDWM_WINDOW_TYPE_DROPDOWN_MENU,
ZDWM_WINDOW_TYPE_POPUP_MENU,
ZDWM_WINDOW_TYPE_TOOLTIP,
ZDWM_WINDOW_TYPE_COMBO,
ZDWM_WINDOW_TYPE_DND,
ZDWM_WINDOW_TYPE_NOTIFICATION,
} window_type_t;
/* Internal semantic window states mapped from backend-specific protocols. */
typedef enum window_state_t {
ZDWM_WINDOW_STATE_ABOVE = 0,
ZDWM_WINDOW_STATE_FULLSCREEN,
ZDWM_WINDOW_STATE_MODAL,
ZDWM_WINDOW_STATE_STICKY,
} window_state_t;
typedef enum window_state_request_type_t { typedef enum window_state_request_type_t {
ZDWM_WINDOW_STATE_REQUEST_FULLSCREEN, ZDWM_WINDOW_STATE_REQUEST_FULLSCREEN,
@@ -65,48 +105,46 @@ typedef enum window_state_request_action_t {
ZDWM_WINDOW_STATE_ACTION_TOGGLE, ZDWM_WINDOW_STATE_ACTION_TOGGLE,
} window_state_request_action_t; } window_state_request_action_t;
typedef enum configure_field_t { /* 层级从低到高 */
ZDWM_CONFIGURE_FIELD_X = 1u << 0, typedef enum window_layer_type_t {
ZDWM_CONFIGURE_FIELD_Y = 1u << 1, ZDWM_WINDOW_LAYER_DESKTOP = 0,
ZDWM_CONFIGURE_FIELD_WIDTH = 1u << 2, ZDWM_WINDOW_LAYER_NORMAL,
ZDWM_CONFIGURE_FIELD_HEIGHT = 1u << 3, ZDWM_WINDOW_LAYER_TOP,
ZDWM_CONFIGURE_FIELD_BORDER_WIDTH = 1u << 4, ZDWM_WINDOW_LAYER_OVERLAY,
ZDWM_CONFIGURE_FIELD_SIBLING = 1u << 5, ZDWM_WINDOW_LAYER_COUNT,
ZDWM_CONFIGURE_FIELD_STACK_MODE = 1u << 6, } window_layer_type_t;
} configure_field_t;
typedef struct configure_data_t { typedef struct window_layer_props_t {
window_id_t window; window_type_t *types;
uint32_t changed_fields; size_t type_count;
int32_t x;
int32_t y;
int32_t width;
int32_t height;
uint32_t border_width;
window_id_t sibling;
uint32_t stack_mode;
} configure_data_t;
typedef struct border_config_t { window_state_t *states;
uint32_t width; size_t state_count;
color_t normal_color; } window_layer_props_t;
color_t focused_color;
} border_config_t;
typedef struct only_window_data_t { /* clang-format off */
window_id_t window; typedef enum window_metadata_change_flags_t {
} only_window_data_t; ZDWM_WINDOW_METADATA_CHANGE_TITLE = 1u << 0,
ZDWM_WINDOW_METADATA_CHANGE_APP_ID = 1u << 1,
ZDWM_WINDOW_METADATA_CHANGE_ROLE = 1u << 2,
ZDWM_WINDOW_METADATA_CHANGE_CLASS = 1u << 3,
ZDWM_WINDOW_METADATA_CHANGE_INSTANCE = 1u << 4,
} window_metadata_change_flags_t;
/* clang-format on */
typedef struct window_metadata_t {
char *title;
char *app_id;
char *role;
char *class_name;
char *instance_name;
} window_metadata_t;
typedef enum hint_field_t { typedef enum hint_field_t {
ZDWM_HINT_FIELD_URGENT, ZDWM_HINT_FIELD_URGENT,
ZDWM_HINT_FIELD_SIZE, ZDWM_HINT_FIELD_SIZE,
} hint_field_t; } hint_field_t;
typedef struct zdwm_size_t {
int32_t width;
int32_t height;
} zdwm_size_t;
typedef struct hints_data_t { typedef struct hints_data_t {
window_id_t window; window_id_t window;
uint32_t changed_fields; uint32_t changed_fields;
@@ -115,19 +153,11 @@ typedef struct hints_data_t {
zdwm_size_t max_size; zdwm_size_t max_size;
} hints_data_t; } hints_data_t;
typedef enum window_interaction_mode_t { typedef struct border_config_t {
ZDWM_WINDOW_INTERACTION_NONE, uint32_t width;
ZDWM_WINDOW_INTERACTION_MOVE, color_t normal_color;
ZDWM_WINDOW_INTERACTION_RESIZE, color_t focused_color;
} window_interaction_mode_t; } border_config_t;
typedef struct window_interaction_state_t {
window_interaction_mode_t mode;
window_id_t window;
point_t start_coordinate;
rect_t origin_rect;
uint64_t last_change_time;
} window_interaction_state_t;
static inline bool window_id_invalid(window_id_t window_id) { static inline bool window_id_invalid(window_id_t window_id) {
return window_id == ZDWM_WINDOW_ID_INVALID; return window_id == ZDWM_WINDOW_ID_INVALID;

View File

@@ -7,22 +7,22 @@
bool fair(const zdwm_layout_ctx_t *ctx, zdwm_layout_result_t *out) { bool fair(const zdwm_layout_ctx_t *ctx, zdwm_layout_result_t *out) {
auto windows = ctx->window_ids; auto windows = ctx->window_ids;
auto count = (int32_t)ctx->window_count; auto count = (int32_t)ctx->window_count;
if (!windows || !count) return false; if (!windows || !count) return false;
auto columns = (int32_t)floor(sqrt(count)); auto columns = (int32_t)floor(sqrt(count));
if (columns * (columns + 1) <= count) ++columns; if (columns * (columns + 1) <= count) ++columns;
auto rows_in_other_cols = count / columns; auto rows_in_other_cols = count / columns;
auto rows_in_main_col = count - (columns - 1) * rows_in_other_cols; auto rows_in_main_col = count - (columns - 1) * rows_in_other_cols;
while (rows_in_main_col > rows_in_other_cols) { while (rows_in_main_col > rows_in_other_cols) {
++rows_in_other_cols; ++rows_in_other_cols;
rows_in_main_col = count - (columns - 1) * rows_in_other_cols; rows_in_main_col = count - (columns - 1) * rows_in_other_cols;
} }
auto workarea = &ctx->workarea; auto workarea = &ctx->workarea;
auto width_avg = workarea->width / columns; auto width_avg = workarea->width / columns;
auto width_for_main_col = workarea->width - (columns - 1) * width_avg; auto width_for_main_col = workarea->width - (columns - 1) * width_avg;
auto width_for_other_col = width_avg; auto width_for_other_col = width_avg;
int32_t row = 0, col = 0, row_count; int32_t row = 0, col = 0, row_count;
@@ -31,26 +31,26 @@ bool fair(const zdwm_layout_ctx_t *ctx, zdwm_layout_result_t *out) {
int32_t width; int32_t width;
if (i < rows_in_main_col) { if (i < rows_in_main_col) {
row = i; row = i;
width = width_for_main_col; width = width_for_main_col;
row_count = rows_in_main_col; row_count = rows_in_main_col;
} else { } else {
width = width_for_other_col; width = width_for_other_col;
row_count = rows_in_other_cols; row_count = rows_in_other_cols;
if (((i - rows_in_main_col) % row_count) == 0) { if (((i - rows_in_main_col) % row_count) == 0) {
col++; col++;
row = 0; row = 0;
x += col == 1 ? width_for_main_col : width_for_other_col; x += col == 1 ? width_for_main_col : width_for_other_col;
y = workarea->y; y = workarea->y;
} }
} }
auto h_avg = workarea->height / row_count; auto h_avg = workarea->height / row_count;
auto h_main = workarea->height - h_avg * (row_count - 1); auto h_main = workarea->height - h_avg * (row_count - 1);
auto height = row == 0 ? h_main : h_avg; auto height = row == 0 ? h_main : h_avg;
zdwm_layout_item_t item = { zdwm_layout_item_t item = {
.window_id = windows[i], .window_id = windows[i],
.rect = {.x = x, .y = y, .width = width, .height = height} .rect = {.x = x, .y = y, .width = width, .height = height}
}; };
zdwm_layout_result_push(out, item); zdwm_layout_result_push(out, item);

View File

@@ -2,13 +2,13 @@
bool fullscreen(const zdwm_layout_ctx_t *ctx, zdwm_layout_result_t *out) { bool fullscreen(const zdwm_layout_ctx_t *ctx, zdwm_layout_result_t *out) {
auto windows = ctx->window_ids; auto windows = ctx->window_ids;
auto count = ctx->window_count; auto count = ctx->window_count;
if (!windows || !count) return false; if (!windows || !count) return false;
for (size_t i = 0; i < count; ++i) { for (size_t i = 0; i < count; ++i) {
zdwm_layout_item_t item = { zdwm_layout_item_t item = {
.window_id = windows[i], .window_id = windows[i],
.rect = ctx->output_geometry, .rect = ctx->output_geometry,
}; };
zdwm_layout_result_push(out, item); zdwm_layout_result_push(out, item);
} }

View File

@@ -4,13 +4,13 @@
bool maximize(const zdwm_layout_ctx_t *ctx, zdwm_layout_result_t *out) { bool maximize(const zdwm_layout_ctx_t *ctx, zdwm_layout_result_t *out) {
auto windows = ctx->window_ids; auto windows = ctx->window_ids;
auto count = ctx->window_count; auto count = ctx->window_count;
if (!windows || !count) return false; if (!windows || !count) return false;
for (size_t i = 0; i < count; ++i) { for (size_t i = 0; i < count; ++i) {
zdwm_layout_item_t item = { zdwm_layout_item_t item = {
.window_id = windows[i], .window_id = windows[i],
.rect = ctx->workarea, .rect = ctx->workarea,
}; };
zdwm_layout_result_push(out, item); zdwm_layout_result_push(out, item);
} }

View File

@@ -17,21 +17,23 @@
#include "base/log.h" #include "base/log.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/memory.h" #include "base/memory.h"
#include "base/window_list.h" #include "common/event.h"
#include "common/listeners.h"
#include "common/window.h"
#include "common/workspace.h"
#include "config/runtime_config.h" #include "config/runtime_config.h"
#include "core/backend.h"
#include "core/binding.h" #include "core/binding.h"
#include "core/command_buffer.h" #include "core/command_buffer.h"
#include "core/event.h"
#include "core/layout.h" #include "core/layout.h"
#include "core/listeners.h" #include "core/listeners.h"
#include "core/plan.h" #include "core/plan.h"
#include "core/policy.h" #include "core/policy.h"
#include "core/rules.h" #include "core/rules.h"
#include "core/state.h" #include "core/state.h"
#include "core/types.h"
#include "core/window.h" #include "core/window.h"
#include "core/wm_desc.h" #include "interface/backend.h"
#include "interface/event.h"
#include "interface/types.h"
typedef struct runtime_t { typedef struct runtime_t {
bool running; bool running;
@@ -93,16 +95,16 @@ static void runtime_init_bar(runtime_t *runtime) {
auto show_top = runtime->bar.config.show_top; auto show_top = runtime->bar.config.show_top;
inset_t inset = { inset_t inset = {
.top = show_top ? bar_height : 0, .top = show_top ? bar_height : 0,
.bottom = show_top ? 0 : bar_height, .bottom = show_top ? 0 : bar_height,
}; };
auto state = &runtime->state; auto state = &runtime->state;
auto count = state_output_count(state); auto count = state_output_count(state);
auto bar = &runtime->bar; auto bar = &runtime->bar;
bar->bars = p_new(bar_output_t, count); bar->bars = p_new(bar_output_t, count);
bar->count = count; bar->count = count;
bar->visible = true; bar->visible = true;
color_parse(bar->config.bg, &bar->palette.bg); color_parse(bar->config.bg, &bar->palette.bg);
@@ -111,21 +113,21 @@ static void runtime_init_bar(runtime_t *runtime) {
for (size_t i = 0; i < count; ++i) { for (size_t i = 0; i < count; ++i) {
auto output = state_output_at(state, i); auto output = state_output_at(state, i);
state_output_inset_workarea(state, output->id, inset); state_output_inset_workarea(state, output->id, inset);
auto geometry = output->geometry; auto geometry = output->geometry;
rect_t bar_rect = { rect_t bar_rect = {
.x = geometry.x, .x = geometry.x,
.y = show_top ? 0 : geometry.y + geometry.height - bar_height, .y = show_top ? 0 : geometry.y + geometry.height - bar_height,
.width = geometry.width, .width = geometry.width,
.height = bar_height, .height = bar_height,
}; };
auto color = bar->palette.bg.argb; auto color = bar->palette.bg.argb;
auto bar_window = backend_create_bar_window(backend, bar_rect, color); auto bar_window = backend_create_bar_window(backend, bar_rect, color);
auto bar_output = &bar->bars[i]; auto bar_output = &bar->bars[i];
bar_output->cr = bar_window.cr; bar_output->cr = bar_window.cr;
bar_output->window_id = bar_window.window_id; bar_output->window_id = bar_window.window_id;
bar_output->output_id = output->id; bar_output->output_id = output->id;
bar_output->width = bar_rect.width; bar_output->width = bar_rect.width;
bar_output->height = bar_rect.height; bar_output->height = bar_rect.height;
} }
bar_init(&runtime->bar, &runtime->listeners); bar_init(&runtime->bar, &runtime->listeners);
@@ -138,16 +140,16 @@ static bool runtime_init(runtime_t *runtime, runtime_init_desc_t *desc) {
runtime->backend = desc->backend; runtime->backend = desc->backend;
layout_registry_move(&desc->layouts, &runtime->layouts); layout_registry_move(&desc->layouts, &runtime->layouts);
rules_move(&desc->rules, &runtime->rules); rules_move(&desc->rules, &runtime->rules);
runtime->signal_fd = -1; runtime->signal_fd = -1;
runtime->border = desc->border; runtime->border = desc->border;
runtime->fps = MAX(desc->fps, 10); runtime->fps = MAX(desc->fps, 10);
runtime->config_module_handle = desc->config_module_handle; runtime->config_module_handle = desc->config_module_handle;
runtime->binding_table = desc->binding_table; runtime->binding_table = desc->binding_table;
runtime->listeners = desc->listeners; runtime->listeners = desc->listeners;
runtime->bar.config = desc->bar; runtime->bar.config = desc->bar;
desc->backend = nullptr; desc->backend = nullptr;
desc->config_module_handle = nullptr; desc->config_module_handle = nullptr;
desc->binding_table = nullptr; desc->binding_table = nullptr;
p_clear(&desc->listeners, 1); p_clear(&desc->listeners, 1);
p_clear(&desc->bar, 1); p_clear(&desc->bar, 1);
@@ -160,7 +162,7 @@ static bool runtime_init(runtime_t *runtime, runtime_init_desc_t *desc) {
); );
workspace_desc_list_cleanup(&desc->workspaces, &desc->workspace_count); workspace_desc_list_cleanup(&desc->workspaces, &desc->workspace_count);
desc->outputs = nullptr; desc->outputs = nullptr;
desc->output_count = 0; desc->output_count = 0;
return true; return true;
@@ -178,13 +180,15 @@ static void runtime_init_desc_cleanup(runtime_init_desc_t *desc) {
desc->backend = nullptr; desc->backend = nullptr;
} }
if (desc->layouts.slots || desc->layouts.slot_count || if (
desc->layouts.slot_capacity) { desc->layouts.slots || desc->layouts.slot_count ||
desc->layouts.slot_capacity
) {
layout_registry_cleanup(&desc->layouts); layout_registry_cleanup(&desc->layouts);
} }
workspace_desc_list_cleanup(&desc->workspaces, &desc->workspace_count); workspace_desc_list_cleanup(&desc->workspaces, &desc->workspace_count);
desc->outputs = nullptr; desc->outputs = nullptr;
desc->output_count = 0; desc->output_count = 0;
if (desc->config_module_handle) dlclose(desc->config_module_handle); if (desc->config_module_handle) dlclose(desc->config_module_handle);
desc->config_module_handle = nullptr; desc->config_module_handle = nullptr;
@@ -216,7 +220,7 @@ static void runtime_shutdown(runtime_t *runtime) {
static void runtime_notify_initial_state(runtime_t *runtime) { static void runtime_notify_initial_state(runtime_t *runtime) {
auto listeners = &runtime->listeners; auto listeners = &runtime->listeners;
auto state = &runtime->state; auto state = &runtime->state;
auto output = state_output_at(state, state->current_output_index); auto output = state_output_at(state, state->current_output_index);
if (output) listeners_notify_current_output(listeners, output->id); if (output) listeners_notify_current_output(listeners, output->id);
@@ -256,17 +260,17 @@ static void runtime_setup_bindings(runtime_t *runtime) {
if (!bindings) return; if (!bindings) return;
auto backend = runtime->backend; auto backend = runtime->backend;
auto plan = &runtime->plan; auto plan = &runtime->plan;
plan_reset(plan); plan_reset(plan);
auto keys = p_new(key_bind_t, bind_count); auto keys = p_new(key_bind_t, bind_count);
for (size_t i = 0; i < bind_count; ++i) { for (size_t i = 0; i < bind_count; ++i) {
keys[i].keysym = bindings[i].keysym; keys[i].keysym = bindings[i].keysym;
keys[i].modifiers = bindings[i].modifiers; keys[i].modifiers = bindings[i].modifiers;
} }
effect_t effect_bind_key = { effect_t effect_bind_key = {
.type = ZDWM_EFFECT_BIND_KEY, .type = ZDWM_EFFECT_BIND_KEY,
.as.bind_key = {.count = bind_count, .keys = keys}, .as.bind_key = {.count = bind_count, .keys = keys},
}; };
plan_push_effect(plan, &effect_bind_key); plan_push_effect(plan, &effect_bind_key);
@@ -306,9 +310,9 @@ static const layout_result_t *runtime_layout_calc(runtime_t *runtime) {
auto workspace = state_workspace_get(state, output->current_workspace_id); auto workspace = state_workspace_get(state, output->current_workspace_id);
if (!workspace) continue; if (!workspace) continue;
size_t window_count = 0; size_t window_count = 0;
size_t window_list_capacity = 0; size_t window_list_capacity = 0;
window_id_t *window_ids = nullptr; window_id_t *window_ids = nullptr;
for (size_t j = 0; j < state_window_count(state); j++) { for (size_t j = 0; j < state_window_count(state); j++) {
auto window = state_window_at(state, j); auto window = state_window_at(state, j);
@@ -321,13 +325,13 @@ static const layout_result_t *runtime_layout_calc(runtime_t *runtime) {
} else if (window->fullscreen) { } else if (window->fullscreen) {
layout_item_t item = { layout_item_t item = {
.window_id = window->id, .window_id = window->id,
.rect = output->geometry, .rect = output->geometry,
}; };
layout_result_push(result, item); layout_result_push(result, item);
} else if (window->maximized) { } else if (window->maximized) {
layout_item_t item = { layout_item_t item = {
.window_id = window->id, .window_id = window->id,
.rect = output->workarea, .rect = output->workarea,
}; };
layout_result_push(result, item); layout_result_push(result, item);
} }
@@ -336,12 +340,12 @@ static const layout_result_t *runtime_layout_calc(runtime_t *runtime) {
auto layout_func = layout_get(&runtime->layouts, workspace->layout_id); auto layout_func = layout_get(&runtime->layouts, workspace->layout_id);
if (window_count && layout_func) { if (window_count && layout_func) {
zdwm_layout_ctx_t ctx = { zdwm_layout_ctx_t ctx = {
.workspace_id = workspace->id, .workspace_id = workspace->id,
.focused_window_id = workspace->focused_window_id, .focused_window_id = workspace->focused_window_id,
.output_geometry = output->geometry, .output_geometry = output->geometry,
.workarea = output->workarea, .workarea = output->workarea,
.window_ids = window_ids, .window_ids = window_ids,
.window_count = window_count, .window_count = window_count,
}; };
layout_func(&ctx, result); layout_func(&ctx, result);
} }
@@ -361,7 +365,7 @@ static void runtime_apply_window_rect(
auto window = state_window_get(state, window_id); auto window = state_window_get(state, window_id);
if (!window) return; if (!window) return;
auto need_move = window_need_move(window, rect.x, rect.y); auto need_move = window_need_move(window, rect.x, rect.y);
auto need_resize = window_need_resize(window, rect.width, rect.height); auto need_resize = window_need_resize(window, rect.width, rect.height);
uint32_t changed_fields = 0u; uint32_t changed_fields = 0u;
@@ -373,14 +377,14 @@ static void runtime_apply_window_rect(
changed_fields |= ZDWM_CONFIGURE_FIELD_BORDER_WIDTH; changed_fields |= ZDWM_CONFIGURE_FIELD_BORDER_WIDTH;
} }
effect_t configure_effect = { effect_t configure_effect = {
.type = ZDWM_EFFECT_CONFIGURE_WINDOW, .type = ZDWM_EFFECT_CONFIGURE_WINDOW,
.as.configure = { .as.configure = {
.window = window_id, .window = window_id,
.x = rect.x, .x = rect.x,
.y = rect.y, .y = rect.y,
.width = rect.width - 2 * (int32_t)window->border_width, .width = rect.width - 2 * (int32_t)window->border_width,
.height = rect.height - 2 * (int32_t)window->border_width, .height = rect.height - 2 * (int32_t)window->border_width,
.border_width = window->border_width, .border_width = window->border_width,
.changed_fields = changed_fields, .changed_fields = changed_fields,
} }
}; };
@@ -396,7 +400,7 @@ static void runtime_arrange(runtime_t *runtime) {
if (!result) return; if (!result) return;
auto state = &runtime->state; auto state = &runtime->state;
auto plan = &runtime->plan; auto plan = &runtime->plan;
for (size_t i = 0; i < result->item_count; ++i) { for (size_t i = 0; i < result->item_count; ++i) {
auto item = &result->items[i]; auto item = &result->items[i];
runtime_apply_window_rect(state, item->window_id, item->rect, plan); runtime_apply_window_rect(state, item->window_id, item->rect, plan);
@@ -405,20 +409,20 @@ static void runtime_arrange(runtime_t *runtime) {
static policy_context_t policy_context_init(runtime_t *runtime) { static policy_context_t policy_context_init(runtime_t *runtime) {
policy_context_t ctx = { policy_context_t ctx = {
.fps = runtime->fps, .fps = runtime->fps,
.interaction = &runtime->interaction, .interaction = &runtime->interaction,
.bind_table = runtime->binding_table, .bind_table = runtime->binding_table,
.state = &runtime->state, .state = &runtime->state,
.rules = &runtime->rules, .rules = &runtime->rules,
.listeners = &runtime->listeners, .listeners = &runtime->listeners,
.border = &runtime->border, .border = &runtime->border,
.layouts = &runtime->layouts, .layouts = &runtime->layouts,
.bar = { .bar = {
.visible = &runtime->bar.visible, .visible = &runtime->bar.visible,
.windows = &runtime->bar_windows, .windows = &runtime->bar_windows,
.height = runtime->bar.config.height, .height = runtime->bar.config.height,
.show_top = runtime->bar.config.show_top, .show_top = runtime->bar.config.show_top,
}, },
}; };
@@ -430,18 +434,18 @@ static void runtime_scan(runtime_t *runtime) {
if (!result) return; if (!result) return;
policy_context_t ctx = policy_context_init(runtime); policy_context_t ctx = policy_context_init(runtime);
ctx.listeners = nullptr; ctx.listeners = nullptr;
auto backend = runtime->backend; auto backend = runtime->backend;
auto command_buffer = &runtime->command_buffer; auto command_buffer = &runtime->command_buffer;
auto plan = &runtime->plan; auto plan = &runtime->plan;
command_buffer_reset(command_buffer); command_buffer_reset(command_buffer);
plan_reset(plan); plan_reset(plan);
for (size_t i = 0; i < result->count; i++) { for (size_t i = 0; i < result->count; i++) {
event_t event = { event_t event = {
.type = ZDWM_EVENT_WINDOW_MAP_REQUEST, .type = ZDWM_EVENT_WINDOW_MAP_REQUEST,
.as.window_map_request = result->windows[i], .as.window_map_request = result->windows[i],
}; };
policy_route_event(&ctx, &event, command_buffer); policy_route_event(&ctx, &event, command_buffer);
@@ -467,12 +471,12 @@ static bool runtime_handle_bar_click(
auto data = &event->as.pointer_button_press; auto data = &event->as.pointer_button_press;
zdwm_action_t action = {.type = ZDWM_ACTION_NONE}; zdwm_action_t action = {.type = ZDWM_ACTION_NONE};
bar_click_info_t info = { bar_click_info_t info = {
.window = data->window, .window = data->window,
.x = data->local.x, .x = data->local.x,
.modifiers = data->modifiers, .modifiers = data->modifiers,
.button = data->button, .button = data->button,
}; };
if (bar_click(bar, info, &action)) { if (bar_click(bar, info, &action)) {
policy_resolve_action(ctx, &action, command_buffer); policy_resolve_action(ctx, &action, command_buffer);
@@ -483,11 +487,11 @@ static bool runtime_handle_bar_click(
} }
static void runtime_handle_event(runtime_t *runtime, short int revents) { static void runtime_handle_event(runtime_t *runtime, short int revents) {
auto backend = runtime->backend; auto backend = runtime->backend;
auto command_buffer = &runtime->command_buffer; auto command_buffer = &runtime->command_buffer;
auto plan = &runtime->plan; auto plan = &runtime->plan;
auto bar = &runtime->bar; auto bar = &runtime->bar;
auto ctx = policy_context_init(runtime); auto ctx = policy_context_init(runtime);
if (revents & POLLHUP) { if (revents & POLLHUP) {
runtime->running = false; runtime->running = false;
@@ -509,7 +513,7 @@ static void runtime_handle_event(runtime_t *runtime, short int revents) {
if (plan->count) backend_apply_effect(backend, plan->effects, plan->count); if (plan->count) backend_apply_effect(backend, plan->effects, plan->count);
if (plan->quit) { if (plan->quit) {
runtime->running = false; runtime->running = false;
runtime->will_restart = plan->will_restart; runtime->will_restart = plan->will_restart;
} }
@@ -566,14 +570,14 @@ static void runtime_run_event_loop(runtime_t *runtime) {
bool runtime_run(const char *config_so_path, const char *display_name) { bool runtime_run(const char *config_so_path, const char *display_name) {
auto backend = backend_create(nullptr); auto backend = backend_create(nullptr);
auto detect = backend_detect(backend); auto detect = backend_detect(backend);
if (!backend || !detect || detect->output_count == 0) { if (!backend || !detect || detect->output_count == 0) {
fatal("backend detect failed"); fatal("backend detect failed");
} }
runtime_init_desc_t desc = { runtime_init_desc_t desc = {
.backend = backend, .backend = backend,
.outputs = detect->outputs, .outputs = detect->outputs,
.output_count = detect->output_count, .output_count = detect->output_count,
}; };
if (!runtime_config_load(nullptr, &desc)) { if (!runtime_config_load(nullptr, &desc)) {
@@ -583,7 +587,7 @@ bool runtime_run(const char *config_so_path, const char *display_name) {
backend = nullptr; backend = nullptr;
auto runtime = p_new(runtime_t, 1); auto runtime = p_new(runtime_t, 1);
bool inited = runtime_init(runtime, &desc); bool inited = runtime_init(runtime, &desc);
runtime_init_desc_cleanup(&desc); runtime_init_desc_cleanup(&desc);
backend_detect_destroy(detect); backend_detect_destroy(detect);