diff --git a/CMakeLists.txt b/CMakeLists.txt index ead05fa..82fb62e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -215,7 +215,10 @@ elseif (IS_OS_LINUX) if (LINUX_WINDOW_SYSTEM STREQUAL "Wayland") add_compile_definitions(EHS_WS_WAYLAND) - list(APPEND EHS_SOURCES src/io/xdg-shell-protocol.c include/ehs/io/xdg-shell-client-protocol.h src/io/Window_Way.cpp include/ehs/io/Window_Way.h) + list(APPEND EHS_SOURCES + src/io/xdg-shell-protocol.c include/ehs/io/xdg-shell-client-protocol.h + src/io/xdg-decoration.c include/ehs/io/xdg-decoration.h + src/io/Window_Way.cpp include/ehs/io/Window_Way.h) message("Building for Wayland.") elseif (LINUX_WINDOW_SYSTEM STREQUAL "XCB") add_compile_definitions(EHS_WS_XCB) diff --git a/include/ehs/Str.h b/include/ehs/Str.h index e2a2b58..b56485c 100644 --- a/include/ehs/Str.h +++ b/include/ehs/Str.h @@ -1888,11 +1888,7 @@ namespace ehs if (aSize != bSize) return false; - for (UInt_64 i = 0; i < aSize; ++i) - if (a[i] != b[i]) - return false; - - return true; + return Util::Compare(a, b, aSize); } }; diff --git a/include/ehs/io/Window_Way.h b/include/ehs/io/Window_Way.h index 83a96b1..3011740 100644 --- a/include/ehs/io/Window_Way.h +++ b/include/ehs/io/Window_Way.h @@ -4,19 +4,28 @@ #include #include "xdg-shell-client-protocol.h" +#include "xdg-decoration.h" namespace ehs { class Window : public BaseWindow { - private: - wl_display* display; + protected: + wl_display *display; wl_registry *registry; - wl_compositor* compositor; - wl_surface* surface; + wl_compositor *compositor; + wl_surface *wlSurface; xdg_wm_base *xdgShell; xdg_surface *xdgSurface; xdg_toplevel *xdgToplevel; + wl_shm *shm; + wl_buffer *buffer; + zxdg_decoration_manager_v1 *decManager; + zxdg_toplevel_decoration_v1 *dec; + + static Int_32 CreateShmFile(Size size); + + void CreateBuffer(Vec2_u32 scale); static void SurfaceConfigure(void *data, xdg_surface *xdg_surface, UInt_32 serial); @@ -26,11 +35,21 @@ namespace ehs static void RegistryRemoved(void *data, wl_registry *registry, UInt_32 id); + static void Resolution(void *data, struct xdg_toplevel *xdg_toplevel, Int_32 width, Int_32 height, wl_array *states); + public: ~Window() override; Window(); + Window(Window &&win) noexcept; + + Window(const Window &win); + + Window &operator=(Window &&win) noexcept; + + Window &operator=(const Window &win); + void Create_32(const Str_32& title, const Vec2_s32& pos, const Vec2_u32 scale) override; void Create_16(const Str_16& title, const Vec2_s32& pos, const Vec2_u32 scale) override; diff --git a/src/io/Window_Way.cpp b/src/io/Window_Way.cpp index dbcb3df..c842ad6 100644 --- a/src/io/Window_Way.cpp +++ b/src/io/Window_Way.cpp @@ -1,7 +1,74 @@ #include "ehs/io/Window_Way.h" +#include +#include + +#include "ehs/io/Console.h" +#include "ehs/io/xdg-shell-client-protocol.h" + namespace ehs { + Int_32 Window::CreateShmFile(Size size) + { + const char *path = getenv("XDG_RUNTIME_DIR"); + if (!path) + { + EHS_LOG_INT(LogType::ERR, 0, "XDG_RUNTIME_DIR is not set."); + return -1; + } + + Str_8 tmplPath = Str_8(path) + "/wl_shm_XXXXXX"; + + Int_32 fd = mkstemp(tmplPath); + if (fd < 0) + { + EHS_LOG_INT(LogType::ERR, 1, "Failed to create shared memory file."); + return -1; + } + + if (unlink(tmplPath) < 0) + { + EHS_LOG_INT(LogType::ERR, 2, "Failed to unlink shared memory file."); + close(fd); + return -1; + } + + if (ftruncate(fd, size) < 0) + { + EHS_LOG_INT(LogType::ERR, 3, "Failed to set size of shared memory file to " + Str_8::FromNum(size) + "."); + close(fd); + return -1; + } + + EHS_LOG_SUCCESS(); + + return fd; + } + + void Window::CreateBuffer(Vec2_u32 scale) + { + const Size stride = scale.x * 4; + const Size size = stride * scale.y; + + const Int_32 fd = CreateShmFile(size); + + if (mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0) == MAP_FAILED) + { + EHS_LOG_INT(LogType::ERR, 0, "Failed to map shared memory file."); + close(fd); + return; + } + + wl_shm_pool *pool = wl_shm_create_pool(shm, fd, (int32_t)size); + + buffer = wl_shm_pool_create_buffer(pool, 0, (int32_t)scale.x, (int32_t)scale.y, (int32_t)stride, + WL_SHM_FORMAT_XRGB8888); + + wl_shm_pool_destroy(pool); + + close(fd); + } + void Window::SurfaceConfigure(void* data, xdg_surface* xdg_surface, UInt_32 serial) { xdg_surface_ack_configure(xdg_surface, serial); @@ -16,41 +83,139 @@ namespace ehs { Serializer* ser = (Serializer*)data; - if (Str_8::Cmp(interface, "wl_compositor")) + if (Str_8::Cmp(interface, wl_compositor_interface.name)) { ser->SetOffset(0); wl_compositor** comp = ser->Read(); *comp = (wl_compositor*)wl_registry_bind(registry, id, &wl_compositor_interface, 1); } - - if (Str_8::Cmp(interface, "xdg_wm_base")) + else if (Str_8::Cmp(interface, xdg_wm_base_interface.name)) { ser->SetOffset(sizeof(void*)); xdg_wm_base** base = ser->Read(); *base = (xdg_wm_base*)wl_registry_bind(registry, id, &xdg_wm_base_interface, 1); } + else if (Str_8::Cmp(interface, wl_shm_interface.name)) + { + ser->SetOffset(sizeof(void*) * 2); + wl_shm** shm = ser->Read(); + *shm = (wl_shm*)wl_registry_bind(registry, id, &wl_shm_interface, 1); + } + else if (Str_8::Cmp(interface, zxdg_decoration_manager_v1_interface.name)) + { + ser->SetOffset(sizeof(void*) * 3); + zxdg_decoration_manager_v1** decManager = ser->Read(); + *decManager = (zxdg_decoration_manager_v1*)wl_registry_bind(registry, id, &zxdg_decoration_manager_v1_interface, 1); + } } void Window::RegistryRemoved(void* data, wl_registry* registry, UInt_32 id) { } + void Window::Resolution(void *data, struct xdg_toplevel *xdg_toplevel, Int_32 width, Int_32 height, wl_array *states) + { + Console::Write_8("Resolution: " + Str_8::FromNum(width) + "x" + Str_8::FromNum(height)); + } + Window::~Window() { xdg_toplevel_destroy(xdgToplevel); xdg_surface_destroy(xdgSurface); xdg_wm_base_destroy(xdgShell); - wl_surface_destroy(surface); + wl_surface_destroy(wlSurface); wl_compositor_destroy(compositor); wl_registry_destroy(registry); wl_display_disconnect(display); } Window::Window() - : display(nullptr), registry(nullptr), compositor(nullptr) , surface(nullptr) + : display(nullptr), registry(nullptr), compositor(nullptr), wlSurface(nullptr), xdgShell(nullptr), + xdgSurface(nullptr), xdgToplevel(nullptr), shm(nullptr), buffer(nullptr), decManager(nullptr), dec(nullptr) { } + Window::Window(Window &&win) noexcept + : BaseWindow(win), display(win.display), registry(win.registry), compositor(win.compositor), + wlSurface(win.wlSurface), xdgShell(win.xdgShell), xdgSurface(win.xdgSurface), xdgToplevel(win.xdgToplevel), + shm(win.shm), buffer(win.buffer), decManager(win.decManager), dec(win.dec) + { + win.display = nullptr; + win.registry = nullptr; + win.compositor = nullptr; + win.wlSurface = nullptr; + win.xdgShell = nullptr; + win.xdgSurface = nullptr; + win.xdgToplevel = nullptr; + win.shm = nullptr; + win.buffer = nullptr; + win.decManager = nullptr; + win.dec = nullptr; + } + + Window::Window(const Window &win) + : BaseWindow(win), display(nullptr), registry(nullptr), compositor(nullptr), wlSurface(nullptr), + xdgShell(nullptr), xdgSurface(nullptr), xdgToplevel(nullptr), shm(nullptr), buffer(nullptr), decManager(nullptr), + dec(nullptr) + { + } + + Window & Window::operator=(Window &&win) noexcept + { + if (this == &win) + return *this; + + BaseWindow::operator=(win); + + display = win.display; + registry = win.registry; + compositor = win.compositor; + wlSurface = win.wlSurface; + xdgShell = win.xdgShell; + xdgSurface = win.xdgSurface; + xdgToplevel = win.xdgToplevel; + shm = win.shm; + buffer = win.buffer; + decManager = win.decManager; + dec = win.dec; + + win.display = nullptr; + win.registry = nullptr; + win.compositor = nullptr; + win.wlSurface = nullptr; + win.xdgShell = nullptr; + win.xdgSurface = nullptr; + win.xdgToplevel = nullptr; + win.shm = nullptr; + win.buffer = nullptr; + win.decManager = nullptr; + win.dec = nullptr; + + return *this; + } + + Window & Window::operator=(const Window &win) + { + if (this == &win) + return *this; + + BaseWindow::operator=(win); + + display = nullptr; + registry = nullptr; + compositor = nullptr; + wlSurface = nullptr; + xdgShell = nullptr; + xdgSurface = nullptr; + xdgToplevel = nullptr; + shm = nullptr; + buffer = nullptr; + decManager = nullptr; + dec = nullptr; + + return *this; + } + void Window::Create_32(const Str_32& title, const Vec2_s32& pos, const Vec2_u32 scale) { Create_8(UTF::To_8(title), pos, scale); @@ -73,6 +238,8 @@ namespace ehs Serializer data(Endianness::LE); data.Write(&compositor); data.Write(&xdgShell); + data.Write(&shm); + data.Write(&decManager); static constexpr wl_registry_listener registry_listener = { RegistryHandler, @@ -95,22 +262,41 @@ namespace ehs xdg_wm_base_add_listener(xdgShell, &xdg_shell_listener, nullptr); - surface = wl_compositor_create_surface(compositor); - if (!surface) + wlSurface = wl_compositor_create_surface(compositor); + if (!wlSurface) { EHS_LOG_INT(LogType::ERR, 2, "Can't create surface."); return; } - xdgSurface = xdg_wm_base_get_xdg_surface(xdgShell, surface); - xdgToplevel = xdg_surface_get_toplevel(xdgSurface); + CreateBuffer(scale); + + xdgSurface = xdg_wm_base_get_xdg_surface(xdgShell, wlSurface); static constexpr xdg_surface_listener surfaceListener = {SurfaceConfigure}; xdg_surface_add_listener(xdgSurface, &surfaceListener, nullptr); + xdgToplevel = xdg_surface_get_toplevel(xdgSurface); + + static constexpr xdg_toplevel_listener topLevelListener = { + .configure = Resolution + }; + + xdg_toplevel_add_listener(xdgToplevel, &topLevelListener, nullptr); + xdg_toplevel_set_title(xdgToplevel, title); - wl_surface_commit(surface); + xdg_toplevel_set_app_id(xdgToplevel, "dsadasfsaAS"); + + dec = zxdg_decoration_manager_v1_get_toplevel_decoration(decManager, xdgToplevel); + zxdg_toplevel_decoration_v1_set_mode(dec, ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); + + wl_surface_attach(wlSurface, buffer, 0, 0); + wl_surface_commit(wlSurface); + + wl_display_roundtrip(display); + + OnCreated(); } void Window::OnCreated() @@ -128,8 +314,8 @@ namespace ehs xdg_wm_base_destroy(xdgShell); xdgShell = nullptr; - wl_surface_destroy(surface); - surface = nullptr; + wl_surface_destroy(wlSurface); + wlSurface = nullptr; wl_compositor_destroy(compositor); compositor = nullptr;