项目地址
该项目AI含量80%,做这个的原因是因为,我在用wayland的CAPI写玩具窗口的时候,看到了令人震惊的繁琐程度,于是决定包装一下。
这个是针对客户端cAPI的薄封装。尽可能保留c的功能,并用c++方式增强。
采用多阶段生成,一次性解析全部xml,按功能聚合成声明,枚举,方法实现,等。
使用了c++23标准,暂时不支持更早版本编译器。需要安装wayland-scanner和wayland-protocols,libwayland-dev。需要在wayland环境下才能够完整生成。
命名风格,把协议的名称的 _,第一个 _前的前缀作为命名空间,wl::display。尽可能不重新额外命名除非冲突。
_
wl::display
生成了两种监听器,一个是通过lambda设置回调方法,一个是通过模板设置回调方法。
第一次做这种项目,欢迎提意见。
不多说,下方是ai写的简单窗口示例。
#include "mayland/mayland-all.hpp" #include #include #include #include #include #include constexpr int WIN_WIDTH = 800; constexpr int WIN_HEIGHT = 600; struct pixel { uint8_t b, g, r, a; }; struct shm_buffer { int fd = -1; uint8_t* data = nullptr; size_t size = 0; size_t stride = 0; int width = 0, height = 0; wl::buffer buf; void init(wl::shm& shm, int w, int h) { width = w; height = h; stride = w * 4; size = stride * h; fd = memfd_create("wayland-shm", MFD_CLOEXEC | MFD_ALLOW_SEALING); ftruncate(fd, size); data = (uint8_t*)mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_SEAL); auto pool = shm.create_pool(fd, size); buf = pool.create_buffer(0, width, height, stride, wl::shm::format::argb8888); pool.destroy(); } ~shm_buffer() { buf.destroy(); if (data) munmap(data, size); if (fd >= 0) close(fd); } shm_buffer() = default; shm_buffer(const shm_buffer&) = delete; shm_buffer& operator=(const shm_buffer&) = delete; shm_buffer(shm_buffer&& o) noexcept : fd(std::exchange(o.fd, -1)) , data(std::exchange(o.data, nullptr)) , size(std::exchange(o.size, 0)) , stride(std::exchange(o.stride, 0)) , width(std::exchange(o.width, 0)) , height(std::exchange(o.height, 0)) , buf(std::move(o.buf)) {} shm_buffer& operator=(shm_buffer&& o) noexcept { if (this != &o) { this->~shm_buffer(); fd = std::exchange(o.fd, -1); data = std::exchange(o.data, nullptr); size = std::exchange(o.size, 0); stride = std::exchange(o.stride, 0); width = std::exchange(o.width, 0); height = std::exchange(o.height, 0); buf = std::move(o.buf); } return *this; } }; class triangle_renderer { float cx = 400, cy = 250, radius = 200; float angle = 0; uint64_t frame_count = 0; public: void set_size(int w, int h) { cx = w / 2.0f; cy = h / 2.0f - 20; radius = std::min(w, h) * 0.35f; } void draw(uint8_t* data, int width, int height, size_t stride, wl::time) { angle += 0.01f; frame_count++; float ax = cx + radius * std::cos(angle); float ay = cy + radius * std::sin(angle); float bx = cx + radius * std::cos(angle + 2.0943951f); float by = cy + radius * std::sin(angle + 2.0943951f); float cx2 = cx + radius * std::cos(angle + 4.1887902f); float cy2 = cy + radius * std::sin(angle + 4.1887902f); float v0x = bx - ax, v0y = by - ay; float v1x = cx2 - ax, v1y = cy2 - ay; float denom = v0x * v1y - v1x * v0y; int min_x = std::max(0, (int)(std::min({ax, bx, cx2}) - 1)); int min_y = std::max(0, (int)(std::min({ay, by, cy2}) - 1)); int max_x = std::min(width - 1, (int)(std::max({ax, bx, cx2}) + 1)); int max_y = std::min(height - 1, (int)(std::max({ay, by, cy2}) + 1)); float hue_base = std::fmod(frame_count * 0.002f, 1.0f); for (int y = min_y; y <= max_y; y++) { auto* row = (pixel*)(data + y * stride); for (int x = min_x; x <= max_x; x++) { float px = (float)x - ax, py = (float)y - ay; float u = (px * v1y - py * v1x) / denom; float v = (v0x * py - v0y * px) / denom; float w = 1.0f - u - v; if (u >= 0 && v >= 0 && w >= 0) { float hue_a = std::fmod(hue_base + 0.0f, 1.0f); float hue_b = std::fmod(hue_base + 0.33f, 1.0f); float hue_c = std::fmod(hue_base + 0.66f, 1.0f); float rh = hue_a * u + hue_b * v + hue_c * w; rh = std::fmod(rh, 1.0f); float c = 1.0f, xv = c * (1 - std::abs(std::fmod(rh * 6, 2) - 1)); float rr, gg, bb; if (rh < 1.0f/6) { rr = c; gg = xv; bb = 0; } else if (rh < 2.0f/6) { rr = xv; gg = c; bb = 0; } else if (rh < 3.0f/6) { rr = 0; gg = c; bb = xv; } else if (rh < 4.0f/6) { rr = 0; gg = xv; bb = c; } else if (rh < 5.0f/6) { rr = xv; gg = 0; bb = c; } else { rr = c; gg = 0; bb = xv; } row[x].r = (uint8_t)(rr * 255); row[x].g = (uint8_t)(gg * 255); row[x].b = (uint8_t)(bb * 255); row[x].a = 255; } } } } void draw_background(uint8_t* data, int width, int height, size_t stride) { for (int y = 0; y < height; y++) { auto* row = (pixel*)(data + y * stride); uint8_t g = (uint8_t)(30 + (y * 30 / height)); for (int x = 0; x < width; x++) { row[x].r = 10; row[x].g = g; row[x].b = 20 + (uint8_t)(x * 20 / width); row[x].a = 255; } } } }; class window { wl::display display; raii compositor; raii wm_base; raii xdg_surface; raii toplevel; raii callback; raii registry; raii shm; xdg::surface::fn_listener surface_listener{this}; wl::registry::listener registry_listener; wl::callback::fn_listener callback_listener{this}; xdg::toplevel::listener toplevel_listener; xdg::wm_base::fn_listener wm_base_listener{wm_base.data()}; int win_w = WIN_WIDTH, win_h = WIN_HEIGHT; bool close_requested = false; wl::surface surface; triangle_renderer renderer; shm_buffer buffer; public: window() { callback_listener.done<&window::frame_callback_done>(); registry_listener .global([this](uint32_t name, const char* iface, uint32_t) { if (iface == wl::compositor::interface::name) compositor = registry->bind(name); else if (iface == xdg::wm_base::interface::name) { wm_base = registry->bind(name); wm_base->add_listener(wm_base_listener); } else if (iface == wl::shm::interface::name) shm = registry->bind(name); }); toplevel_listener .configure([this](int32_t w, int32_t h, wl::array) { if (w > 0 && h > 0) { win_w = w; win_h = h; renderer.set_size(w, h); xdg_surface->set_window_geometry(0, 0, w, h); } }) .close([this] { close_requested = true; }); wm_base_listener.ping<&xdg::wm_base::pong>(); surface_listener.configure<&window::xdg_surface_configure>(); } void xdg_surface_configure(uint32_t serial) { xdg_surface->ack_configure(serial); if (!callback) { buffer.init(*shm.data(), win_w, win_h); renderer.set_size(win_w, win_h); renderer.draw_background(buffer.data, win_w, win_h, buffer.stride); renderer.draw(buffer.data, win_w, win_h, buffer.stride, wl::time{}); surface.attach(buffer.buf, 0, 0); surface.damage(0, 0, win_w, win_h); surface.commit(); callback = surface.frame(); callback->add_listener(callback_listener); } } void frame_callback_done(wl::time t) { if (win_w != buffer.width || win_h != buffer.height) { buffer = shm_buffer{}; buffer.init(*shm.data(), win_w, win_h); renderer.set_size(win_w, win_h); } renderer.draw_background(buffer.data, win_w, win_h, buffer.stride); renderer.draw(buffer.data, win_w, win_h, buffer.stride, t); surface.attach(buffer.buf, 0, 0); surface.damage(0, 0, win_w, win_h); surface.commit(); callback = surface.frame(); callback->add_listener(callback_listener); } void run() { display = display.connect(nullptr); registry = display.get_registry(); registry->add_listener(registry_listener); display.roundtrip(); if (!compositor || !wm_base || !shm) return; renderer.set_size(win_w, win_h); surface = compositor->create_surface(); xdg_surface = wm_base->get_xdg_surface(surface); xdg_surface->add_listener(surface_listener); toplevel = xdg_surface->get_toplevel(); toplevel->add_listener(toplevel_listener); toplevel->set_title("shm-triangle"); toplevel->set_min_size(0, 0); toplevel->set_max_size(2048, 2048); surface.commit(); while (!close_requested && display.dispatch() != -1) {} } }; int main() { window w; w.run(); }
No replies yet
Featured Collection
Popular Ranking
Popular Events
项目地址
该项目AI含量80%,做这个的原因是因为,我在用wayland的CAPI写玩具窗口的时候,看到了令人震惊的繁琐程度,于是决定包装一下。
这个是针对客户端cAPI的薄封装。尽可能保留c的功能,并用c++方式增强。
采用多阶段生成,一次性解析全部xml,按功能聚合成声明,枚举,方法实现,等。
使用了c++23标准,暂时不支持更早版本编译器。需要安装wayland-scanner和wayland-protocols,libwayland-dev。需要在wayland环境下才能够完整生成。
命名风格,把协议的名称的
_,第一个_前的前缀作为命名空间,wl::display。尽可能不重新额外命名除非冲突。生成了两种监听器,一个是通过lambda设置回调方法,一个是通过模板设置回调方法。
第一次做这种项目,欢迎提意见。
不多说,下方是ai写的简单窗口示例。