From 520a0e1363b3287d300df1c41d68730b1762b350 Mon Sep 17 00:00:00 2001 From: Medusa Slockbower Date: Mon, 15 Dec 2025 23:40:06 -0500 Subject: [PATCH] - Setup libdecor, which is used automatically when available. TODO: - xdg decorations - threading - thread-safe window manager --- CMakeLists.txt | 3 + gdb/fennec/__init__.py | 1 + gdb/fennec/math.py | 6 +- include/fennec/containers/bitfield.h | 43 ++++- include/fennec/math/detail/_fwd.h | 4 +- include/fennec/math/ext/rect.h | 52 ++++++ include/fennec/math/matrix.h | 2 +- include/fennec/math/vector.h | 18 +- .../platform/interface/display_server.h | 19 +- include/fennec/platform/interface/platform.h | 2 + include/fennec/platform/interface/window.h | 64 +++++-- .../fennec/platform/linux/wayland/window.h | 17 +- include/fennec/platform/opengl/egl/context.h | 1 + include/fennec/platform/opengl/egl/error.h | 59 +++++++ include/fennec/platform/opengl/egl/surface.h | 7 +- include/fennec/platform/window_manager.h | 48 +++++ .../fennec/renderers/interface/gfxcontext.h | 6 +- include/fennec/rtti/type.h | 8 + source/platform/interface/platform.cpp | 3 +- source/platform/linux/wayland/egl/surface.cpp | 10 +- source/platform/linux/wayland/server.cpp | 17 +- source/platform/linux/wayland/window.cpp | 166 +++++++++++++++--- source/platform/opengl/egl/context.cpp | 8 +- source/platform/opengl/egl/surface.cpp | 18 +- test/tests/test_platform.h | 16 +- 25 files changed, 508 insertions(+), 90 deletions(-) create mode 100644 include/fennec/math/ext/rect.h create mode 100644 include/fennec/platform/opengl/egl/error.h create mode 100644 include/fennec/platform/window_manager.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 0efe2ca..182ab02 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -286,6 +286,9 @@ add_library(fennec STATIC # EXTRA SOURCES ======================================================================================================== ${FENNEC_EXTRA_SOURCES} + include/fennec/math/ext/rect.h + include/fennec/platform/opengl/egl/error.h + include/fennec/platform/window_manager.h ) diff --git a/gdb/fennec/__init__.py b/gdb/fennec/__init__.py index 80da99d..854a0af 100644 --- a/gdb/fennec/__init__.py +++ b/gdb/fennec/__init__.py @@ -20,6 +20,7 @@ # GDB CODE ============================================================================================================= import gdb +import gdb.printing from . import containers from . import strings diff --git a/gdb/fennec/math.py b/gdb/fennec/math.py index 28050a2..932aee3 100644 --- a/gdb/fennec/math.py +++ b/gdb/fennec/math.py @@ -24,7 +24,7 @@ from . import utility class VectorPrinter: def __init__(self, val): self.val = val - self.base = val['data']['elements'] + self.base = val['data']['data'] self.len = self.base.type.range()[1] + 1 def to_string(self): @@ -51,7 +51,7 @@ class VectorPrinter: class QuaternionPrinter: def __init__(self, val): self.val = val - self.base = val['data']['elements'] + self.base = val['data']['data'] def to_string(self): res = ("< " @@ -72,7 +72,7 @@ class QuaternionPrinter: # VECTOR ================================================================================================================= class MatrixPrinter: def __init__(self, val): - self.columns = val['data']['elements'] + self.columns = val['data']['data'] self.num_columns = self.columns.type.range()[1] + 1 self.num_rows = val.type.template_argument(1) diff --git a/include/fennec/containers/bitfield.h b/include/fennec/containers/bitfield.h index 22c2b74..104a2ef 100644 --- a/include/fennec/containers/bitfield.h +++ b/include/fennec/containers/bitfield.h @@ -43,7 +43,8 @@ namespace fennec /// \tparam N The number of bits in the bitfield template struct bitfield { - static constexpr size_t size = N; + static constexpr size_t bits = N; + static constexpr size_t bytes = (N + 7) / 8; public: constexpr bitfield() @@ -66,51 +67,79 @@ public: } template + constexpr bitfield(ArgsT&&...args) + : _bytes() { + (this->store(fennec::forward(args), true), ...); + } + + template requires((is_bool_v or is_convertible_v) and ...) constexpr bitfield(ArgsT&&...args) : _bytes() { size_t i = 0; (this->store(i++, fennec::forward(args)), ...); } + bitfield(const bitfield& bf) + : _bytes(bf._bytes) { + } + + bitfield(bitfield&& bf) noexcept + : _bytes(bf._bytes) { + } + constexpr ~bitfield() = default; + bitfield& operator=(const bitfield& bf) = default; + bitfield& operator=(bitfield&& bf) noexcept = default; + bool test(size_t i) const { - assertd(i < size, "Index out of Bounds!"); + assertd(i < bits, "Index out of Bounds!"); size_t b = i / 8; size_t o = i % 8; return _bytes[b] & (1 << o); } void set(size_t i) { - assertd(i < size, "Index out of Bounds!"); + assertd(i < bits, "Index out of Bounds!"); size_t b = i / 8; size_t o = i % 8; _bytes[b] |= (1 << o); } void clear(size_t i) { - assertd(i < size, "Index out of Bounds!"); + assertd(i < bits, "Index out of Bounds!"); size_t b = i / 8; size_t o = i % 8; _bytes[b] &= ~(1 << o); } void toggle(size_t i) { - assertd(i < size, "Index out of Bounds!"); + assertd(i < bits, "Index out of Bounds!"); size_t b = i / 8; size_t o = i % 8; _bytes[b] ^= (1 << o); } void store(size_t i, bool v) { - assertd(i < size, "Index out of Bounds!"); + assertd(i < bits, "Index out of Bounds!"); size_t b = i / 8; size_t o = i % 8; (_bytes[b] &= ~((1 << o))) |= ((v << o)); } + bitfield operator~() const { + bitfield res = *this; + res._inv_helper(make_index_metasequence_t{}); + return res; + } + private: - array _bytes; + array _bytes; + + template + void _inv_helper(index_metasequence) { + ((_bytes[I] = ~_bytes[I]), ...); + } }; diff --git a/include/fennec/math/detail/_fwd.h b/include/fennec/math/detail/_fwd.h index 3176846..fd02f28 100644 --- a/include/fennec/math/detail/_fwd.h +++ b/include/fennec/math/detail/_fwd.h @@ -24,8 +24,8 @@ namespace fennec { -template struct vector; // Forward def for vectors -template struct matrix; // Forward def for matrices +template requires(is_scalar_v) struct vector; // Forward def for vectors +template requires(is_scalar_v) struct matrix; // Forward def for matrices // Simplified interface for creating sized vectors or matrices template using vec diff --git a/include/fennec/math/ext/rect.h b/include/fennec/math/ext/rect.h new file mode 100644 index 0000000..ebb041a --- /dev/null +++ b/include/fennec/math/ext/rect.h @@ -0,0 +1,52 @@ +// ===================================================================================================================== +// fennec, a free and open source game engine +// Copyright © 2025 Medusa Slockbower +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// ===================================================================================================================== + +/// +/// \file rect.h +/// \brief +/// +/// +/// \details +/// \author Medusa Slockbower +/// +/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html)) +/// +/// + + +#ifndef FENNEC_MATH_EXT_RECT_H +#define FENNEC_MATH_EXT_RECT_H + +#include + +namespace fennec +{ + +template +struct rectangle { + tvec2 position, size; +}; + +using rect = rectangle; +using irect = rectangle; +using urect = rectangle; +using drect = rectangle; + +} + +#endif // FENNEC_MATH_EXT_RECT_H \ No newline at end of file diff --git a/include/fennec/math/matrix.h b/include/fennec/math/matrix.h index 872c0ff..9968279 100644 --- a/include/fennec/math/matrix.h +++ b/include/fennec/math/matrix.h @@ -182,7 +182,7 @@ constexpr matrix inverse(const matrix +template requires(is_scalar_v) struct matrix { // Assertions ========================================================================================================== diff --git a/include/fennec/math/vector.h b/include/fennec/math/vector.h index 0fed24d..0943cc8 100644 --- a/include/fennec/math/vector.h +++ b/include/fennec/math/vector.h @@ -103,6 +103,7 @@ /// /// +#include #include #include @@ -177,7 +178,7 @@ using dvec4 = tvec4; /// \tparam ScalarT base \ref scalar type of each Component /// \tparam IndicesV index of each Component /// \nosubgrouping -template +template requires(is_scalar_v) struct vector : detail::vector_base_type { // Assertions ========================================================================================================== @@ -337,6 +338,21 @@ struct vector : detail::vector_base_type vector::_construct<0>(args...); } + constexpr vector(initializer_list init) { + size_t i = 0; + for (ScalarT x : init) { + data[i++] = x; + } + } + + template + constexpr vector(initializer_list init) { + size_t i = 0; + for (OScalarT x : init) { + data[i++] = ScalarT(x); + } + } + /// @} diff --git a/include/fennec/platform/interface/display_server.h b/include/fennec/platform/interface/display_server.h index a46fd25..7f1bfbd 100644 --- a/include/fennec/platform/interface/display_server.h +++ b/include/fennec/platform/interface/display_server.h @@ -32,8 +32,12 @@ #define FENNEC_PLATFORM_INTERFACE_DISPLAY_SERVER_H #include + #include #include + +#include + #include #include @@ -89,6 +93,8 @@ enum feature_ : uint32_t { }; using featureset_t = bitfield; + using window_id = uint32_t; + using window_pool = object_pool; struct config { }; @@ -109,10 +115,6 @@ enum feature_ : uint32_t { return features.test(feature); } - gfxcontext* get_gfx_context() { - return gfx_context; - } - virtual window* create_window(const window::config& conf) = 0; window* get_window(size_t id) { @@ -127,11 +129,14 @@ enum feature_ : uint32_t { virtual void* get_native_handle() = 0; + gfxcontext* get_gfx_context() { + return gfx_context.get(); + } protected: - featureset_t features; - object_pool windows; - gfxcontext* gfx_context; + featureset_t features; + window_pool windows; + unique_ptr gfx_context; FENNEC_RTTI_CLASS_ENABLE() { } diff --git a/include/fennec/platform/interface/platform.h b/include/fennec/platform/interface/platform.h index d05786a..e179a7f 100644 --- a/include/fennec/platform/interface/platform.h +++ b/include/fennec/platform/interface/platform.h @@ -60,6 +60,8 @@ namespace fennec { +/// +/// \brief Main platform class class platform : public singleton { public: using shared_object = struct shared_object; diff --git a/include/fennec/platform/interface/window.h b/include/fennec/platform/interface/window.h index 843f712..51f6081 100644 --- a/include/fennec/platform/interface/window.h +++ b/include/fennec/platform/interface/window.h @@ -32,9 +32,13 @@ #define FENNEC_PLATFORM_INTERFACE_WINDOW_H #include -#include + +#include + #include + #include +#include namespace fennec { @@ -61,21 +65,27 @@ public: enum flag_ : uint8_t { flag_always_on_top = 0, // Window always appears on top level flag_borderless, // Window has no border decorations - flag_child, // Window is a child window, and closes when the parent does - flag_decorations, // Window has a titlebar with basic functions flag_modal, // Window always appears above parent and blocks input going to parent flag_pass_mouse, // Mouse interaction passes to next underlying window in the application flag_popup, // Window does not show in taskbar and closes when loses focus flag_resizable, // Window can be resized through functions defined by Desktop Environment flag_transparent, // Window has an alpha value - flag_visible, // Window is visible - flag_running, // Window is running flag_no_focus, // Window can be focused flag_count }; + enum state_ : uint8_t { + state_running = 0, // Window is running + state_child, // Window is a child + state_suspended, // Window is suspended + state_visible, // Window is visible + + state_count + }; + using flags_t = bitfield; + using state_t = bitfield; struct accessibility { string name, description; @@ -87,15 +97,25 @@ public: uint8_t mode; size_t parent; - ivec2 size; + irect rect; + + double_t fractional_scaling; accessibility accessibility; }; + struct state { + uint8_t mode; + irect rect; + state_t flags; + int_t buffer_scale; + double_t fractional_scaling; + }; + window(display_server* server, size_t id, const config& conf) : server(server), id(id) - , cfg(conf), root(nullptr) { - cfg.flags.clear(flag_visible); + , cfg(conf), state(), root(nullptr) { + state.mode = conf.mode; } virtual ~window() = default; @@ -103,25 +123,33 @@ public: size_t get_id() const { return id; } size_t get_parent_id() const { return cfg.parent; } + const config& get_config() const { return cfg; } + window* get_parent() const; - const ivec2& get_size() const { return cfg.size; } - int get_width() const { return cfg.size.x; } - int get_height() const { return cfg.size.y; } + const ivec2& get_size() const { return state.rect.size; } + const ivec2& get_position() const { return state.rect.position; } + + int get_width() const { return state.rect.size.x; } + int get_height() const { return state.rect.size.y; } + int get_pos_x() const { return state.rect.position.x; } + int get_pos_y() const { return state.rect.position.y; } + + + bool is_visible() const { return state.flags.test(state_visible); } + bool is_child() const { return state.flags.test(state_child); } + bool is_running() const { return state.flags.test(state_running); } + bool is_suspended() const { return state.flags.test(state_suspended); } bool get_flag(uint8_t flag) const { return cfg.flags.test(flag); } bool is_always_on_top() const { return get_flag(flag_always_on_top); } bool is_borderless() const { return get_flag(flag_borderless); } - bool is_child() const { return get_flag(flag_child); } - bool has_decorations() const { return get_flag(flag_decorations); } bool is_modal() const { return get_flag(flag_modal); } bool is_passing_mouse() const { return get_flag(flag_pass_mouse); } bool is_popup() const { return get_flag(flag_popup); } bool is_resizable() const { return get_flag(flag_resizable); } bool is_transparent() const { return get_flag(flag_transparent); } - bool is_visible() const { return get_flag(flag_visible); } - bool is_running() const { return get_flag(flag_running); } bool is_no_focus() const { return get_flag(flag_no_focus); } @@ -129,7 +157,6 @@ public: bool set_always_on_top(bool val) { return set_flag(flag_always_on_top, val); } bool set_borderless(bool val) { return set_flag(flag_borderless, val); } - bool set_decorations(bool val) { return set_flag(flag_decorations, val); } bool set_modal(bool val) { return set_flag(flag_modal, val); } bool set_passing_mouse(bool val) { return set_flag(flag_pass_mouse, val); } bool set_popup(bool val) { return set_flag(flag_popup, val); } @@ -137,8 +164,8 @@ public: bool set_transparent(bool val) { return set_flag(flag_transparent, val); } bool set_no_focus(bool val) { return set_flag(flag_no_focus, val); } - virtual void show() = 0; - virtual void hide() = 0; + virtual void initialize() = 0; + virtual void shutdown() = 0; virtual void begin_frame(); virtual void end_frame(); @@ -149,6 +176,7 @@ protected: display_server* const server; const size_t id; config cfg; + state state; window* root; gfxsurface* gfx_surface; }; diff --git a/include/fennec/platform/linux/wayland/window.h b/include/fennec/platform/linux/wayland/window.h index 9b4dfd7..f7be543 100644 --- a/include/fennec/platform/linux/wayland/window.h +++ b/include/fennec/platform/linux/wayland/window.h @@ -53,13 +53,15 @@ public: wayland_window(display_server* server, uint32_t id, const config& cfg); ~wayland_window(); - void show() override; - void hide() override; + void initialize() override; + void shutdown() override; void* get_native_handle() override; bool set_flag(uint8_t flag, bool val) override; + +// Fields ============================================================================================================== private: wl_surface* surface; xdg_surface* xdgsurface; @@ -67,9 +69,18 @@ private: wl_callback* frame_callback; #if FENNEC_HAS_LIBDECOR - libdecor_frame* libdecorframe; + libdecor_frame* libdecorframe; + libdecor_configuration* libdecorcfg; #endif + +// Helpers ============================================================================================================= + + void _update_size(const ivec2& size); + + +// Listeners =========================================================================================================== + static void _wl_surface_listen_enter(void*, wl_surface*, wl_output*); static void _wl_surface_listen_leave(void*, wl_surface*, wl_output*); static void _wl_surface_listen_preferred_buffer_scale(void*, wl_surface*, int32_t); diff --git a/include/fennec/platform/opengl/egl/context.h b/include/fennec/platform/opengl/egl/context.h index db4f9ba..def1845 100644 --- a/include/fennec/platform/opengl/egl/context.h +++ b/include/fennec/platform/opengl/egl/context.h @@ -33,6 +33,7 @@ #define FENNEC_PLATFORM_LINUX_WAYLAND_OPENGL_EGLCONTEXT_H #include +#include #include #include diff --git a/include/fennec/platform/opengl/egl/error.h b/include/fennec/platform/opengl/egl/error.h new file mode 100644 index 0000000..af09e05 --- /dev/null +++ b/include/fennec/platform/opengl/egl/error.h @@ -0,0 +1,59 @@ +// ===================================================================================================================== +// fennec, a free and open source game engine +// Copyright © 2025 Medusa Slockbower +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// ===================================================================================================================== + +/// +/// \file error.h +/// \brief +/// +/// +/// \details +/// \author Medusa Slockbower +/// +/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html)) +/// +/// + + +#ifndef FENNEC_PLATFORM_OPENGL_EGL_ERROR_H +#define FENNEC_PLATFORM_OPENGL_EGL_ERROR_H + +#include +#include + +inline fennec::cstring eglErrorString(EGLint err) { + switch (err) { + case EGL_SUCCESS: return "None"; + case EGL_NOT_INITIALIZED: return "Not Initialized"; + case EGL_BAD_ACCESS: return "Bad Access"; + case EGL_BAD_ALLOC: return "Bad Alloc"; + case EGL_BAD_ATTRIBUTE: return "Bad Attribute"; + case EGL_BAD_CONTEXT: return "Bad Context"; + case EGL_BAD_CONFIG: return "Bad Config"; + case EGL_BAD_CURRENT_SURFACE: return "Bad Current Surface"; + case EGL_BAD_DISPLAY: return "Bad Display"; + case EGL_BAD_SURFACE: return "Bad Surface"; + case EGL_BAD_MATCH: return "Bad Match"; + case EGL_BAD_PARAMETER: return "Bad Parameter"; + case EGL_BAD_NATIVE_PIXMAP: return "Bad Native Pixmap"; + case EGL_BAD_NATIVE_WINDOW: return "Bad Native Window"; + case EGL_CONTEXT_LOST: return "Context Lost"; + default: return "Unknown Error"; + } +} + +#endif // FENNEC_PLATFORM_OPENGL_EGL_ERROR_H \ No newline at end of file diff --git a/include/fennec/platform/opengl/egl/surface.h b/include/fennec/platform/opengl/egl/surface.h index a9c0a80..c1922c9 100644 --- a/include/fennec/platform/opengl/egl/surface.h +++ b/include/fennec/platform/opengl/egl/surface.h @@ -33,6 +33,7 @@ #define FENNEC_PLATFORM_OPENGL_EGL_SURFACE_H #include +#include #include #include @@ -42,15 +43,15 @@ namespace fennec class eglsurface : public gfxsurface { public: - eglsurface(fennec::window* win, eglcontext* ctx, EGLNativeWindowType eglwindow); + eglsurface(fennec::window* win, eglcontext* ctx, void* eglwindow); ~eglsurface(); void make_current() override; void swap() override; protected: - EGLNativeWindowType _eglwindow; - EGLSurface _eglsurface; + void* _eglwindow; + EGLSurface _eglsurface; }; } // fennec diff --git a/include/fennec/platform/window_manager.h b/include/fennec/platform/window_manager.h new file mode 100644 index 0000000..84cc203 --- /dev/null +++ b/include/fennec/platform/window_manager.h @@ -0,0 +1,48 @@ +// ===================================================================================================================== +// fennec, a free and open source game engine +// Copyright © 2025 Medusa Slockbower +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// ===================================================================================================================== + +/// +/// \file window_manager.h +/// \brief +/// +/// +/// \details +/// \author Medusa Slockbower +/// +/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html)) +/// +/// + + +#ifndef FENNEC_PLATFORM_WINDOW_MANAGER_H +#define FENNEC_PLATFORM_WINDOW_MANAGER_H + +namespace fennec +{ + +/// +/// \brief Thread-Safe wrapper for `display_server` and `window` +class window_manager { +public: + +private: +}; + +} + +#endif // FENNEC_PLATFORM_WINDOW_MANAGER_H \ No newline at end of file diff --git a/include/fennec/renderers/interface/gfxcontext.h b/include/fennec/renderers/interface/gfxcontext.h index 1b064ff..7e3631d 100644 --- a/include/fennec/renderers/interface/gfxcontext.h +++ b/include/fennec/renderers/interface/gfxcontext.h @@ -31,10 +31,14 @@ #ifndef FENNEC_RENDERERS_INTERFACE_GFXCONTEXT_H #define FENNEC_RENDERERS_INTERFACE_GFXCONTEXT_H +#include + #include #include -#include #include + +#include + #include #include diff --git a/include/fennec/rtti/type.h b/include/fennec/rtti/type.h index e64ea89..58c654d 100644 --- a/include/fennec/rtti/type.h +++ b/include/fennec/rtti/type.h @@ -117,6 +117,14 @@ struct type { template static type get_from_instance(TypeT* t) { return type(t); } + /// + /// \brief Get the type info of the provided object. + /// \tparam TypeT The type, automatically deduced + /// \param t A pointer to an object + /// \returns The type info of the provided type + template + static type get_from_instance(const TypeT*) { return type(static_cast(nullptr)); } + private: const type_data* _data; diff --git a/source/platform/interface/platform.cpp b/source/platform/interface/platform.cpp index 31e9e20..edf3eb7 100644 --- a/source/platform/interface/platform.cpp +++ b/source/platform/interface/platform.cpp @@ -29,7 +29,7 @@ platform::platform() { } void platform::initialize() { - logger::log(fennec::format("Initializing platform {}", get_type().name())); + logger::log(format("Initializing platform {}", get_type().name())); display_server::entrylist_t display_servers = display_server::get_type_list(); while (not display_servers.empty()) { @@ -39,6 +39,7 @@ void platform::initialize() { unique_ptr server = unique_ptr(it.ctor(this)); server->connect(); if (server->connected()) { + logger::log(format("Selected {} for the display server.", server->get_type().name())); display = move(server); break; } diff --git a/source/platform/linux/wayland/egl/surface.cpp b/source/platform/linux/wayland/egl/surface.cpp index ac4cbdd..5fbeca0 100644 --- a/source/platform/linux/wayland/egl/surface.cpp +++ b/source/platform/linux/wayland/egl/surface.cpp @@ -25,11 +25,11 @@ namespace fennec { wayland_eglsurface::wayland_eglsurface(wayland_window* win, eglcontext* ctx) - : eglsurface(win, ctx, - reinterpret_cast( - wl_egl_window_create( - static_cast(win->get_native_handle()), win->get_size().x, win->get_size().y - ) + : eglsurface( + win, ctx, + wl_egl_window_create( + static_cast(win->get_native_handle()), + win->get_config().rect.size.x, win->get_config().rect.size.y ) ) { diff --git a/source/platform/linux/wayland/server.cpp b/source/platform/linux/wayland/server.cpp index b57e3fa..e23e80a 100644 --- a/source/platform/linux/wayland/server.cpp +++ b/source/platform/linux/wayland/server.cpp @@ -114,18 +114,18 @@ void wayland_server::connect() { auto contexts = ctx_registry::get_type_list(); while (not contexts.empty()) { const auto& ctx = contexts.front(); - gfx_context = ctx.ctor(this); + gfx_context = unique_ptr(ctx.ctor(this)); if (gfx_context->is_valid()) { break; } else { - delete gfx_context; + gfx_context.reset(); gfx_context = nullptr; contexts.pop(); } } - assertf(gfx_context != nullptr, "Failed to create graphics context."); + assertf(not gfx_context.empty(), "Failed to create graphics context."); } void wayland_server::disconnect() { @@ -136,7 +136,7 @@ void wayland_server::disconnect() { } // delete the gfx context - delete gfx_context; + gfx_context.reset(); // check compositor @@ -167,7 +167,14 @@ bool wayland_server::connected() const { } void wayland_server::dispatch() { - wl_display_dispatch_pending(display); +#if FENNEC_HAS_LIBDECOR + if (libdecor) { + libdecor_dispatch(libdecor, 0); + } else +#endif + { + wl_display_dispatch_pending(display); + } } window* wayland_server::create_window(const window::config& conf) { diff --git a/source/platform/linux/wayland/window.cpp b/source/platform/linux/wayland/window.cpp index 9b75aaa..3fb2235 100644 --- a/source/platform/linux/wayland/window.cpp +++ b/source/platform/linux/wayland/window.cpp @@ -16,6 +16,8 @@ // along with this program. If not, see . // ===================================================================================================================== +#include +#include #include #include @@ -24,6 +26,8 @@ #include #include #include +#include +#include #if FENNEC_HAS_LIBDECOR #include @@ -42,7 +46,7 @@ wayland_window::~wayland_window() { } -void wayland_window::show() { +void wayland_window::initialize() { static constexpr wl_surface_listener surface_listener = { .enter = _wl_surface_listen_enter, .leave = _wl_surface_listen_leave, @@ -106,14 +110,17 @@ void wayland_window::show() { .reserved9 = nullptr, }; + gfx_surface = wl_server->get_gfx_context()->create_surface(this); + if (wl_server->has_libdecor) { libdecorframe = libdecor_decorate(wl_server->libdecor, surface, &libdecor_frame_listener, this); + libdecor_frame_set_app_id(libdecorframe, cfg.title.cstr()); + libdecor_frame_set_title(libdecorframe, cfg.title.cstr()); libdecor_frame_map(libdecorframe); xdgsurface = libdecor_frame_get_xdg_surface(libdecorframe); xdgtoplevel = libdecor_frame_get_xdg_toplevel(libdecorframe); - } else #endif { @@ -123,23 +130,21 @@ void wayland_window::show() { xdgtoplevel = xdg_surface_get_toplevel(xdgsurface); xdg_toplevel_add_listener(xdgtoplevel, &xdg_toplevel_listener, this); + frame_callback = wl_surface_frame(surface); + wl_callback_add_listener(frame_callback, &frame_callback_listener, this); + + + wl_surface_commit(surface); } - - frame_callback = wl_surface_frame(surface); - wl_callback_add_listener(frame_callback, &frame_callback_listener, this); - - - wl_surface_commit(surface); + wl_display_roundtrip(wl_server->display); wl_display_roundtrip(wl_server->display); - cfg.flags.set(flag_visible); - cfg.flags.set(flag_running); - - gfx_surface = wl_server->get_gfx_context()->create_surface(this); + state.flags.set(state_visible); + state.flags.set(state_running); } -void wayland_window::hide() { +void wayland_window::shutdown() { if (not is_running()) { return; } @@ -176,18 +181,99 @@ void wayland_window::hide() { wl_display_roundtrip(wl_server->display); - cfg.flags.clear(flag_visible); - cfg.flags.clear(flag_running); + state.flags.clear(state_visible); + state.flags.clear(state_running); } void* wayland_window::get_native_handle() { return surface; } -bool wayland_window::set_flag(uint8_t, bool) { - return false; +bool wayland_window::set_flag(uint8_t flag, bool value) { + + // Do nothing if already set + if (cfg.flags.test(flag) == value) { + return false; + } + + if (not is_running()) { + return false; + } + + switch (flag) { + case flag_always_on_top: + break; + + case flag_borderless: +#if FENNEC_HAS_LIBDECOR + if (libdecorframe) { + bool vis = libdecor_frame_is_visible(libdecorframe); + bool tgt = not value; + + if (vis != tgt) { + libdecor_frame_set_visibility(libdecorframe, tgt); + } + } else +#endif // FENNEC_HAS_LIBDECOR + { + + } + break; + + case flag_modal: + break; + + case flag_pass_mouse: + break; + + case flag_popup: + break; + + case flag_resizable: + break; + + case flag_transparent: + break; + + case flag_no_focus: + break; + + + default: + logger::log("Invalid flag passed to window::set_flag."); + break; + } + + // Store the value + cfg.flags.store(flag, value); + return true; } + +// Helpers ============================================================================================================= + +void wayland_window::_update_size(const ivec2& size) { + //bool size_changed = any(notEqual(size, state.rect.size)); + + state.rect.size = size; + + if (gfx_surface) { + gfx_surface->resize(size); + } + +#if FENNEC_HAS_LIBDECOR + if (libdecorframe) { + libdecor_state* state = libdecor_state_new(size.x, size.y); + libdecor_frame_commit(libdecorframe, state, libdecorcfg); + libdecor_state_free(state); + libdecorcfg = nullptr; + } +#endif +} + + +// Listeners =========================================================================================================== + // Surface Listeners void wayland_window::_wl_surface_listen_enter(void*, wl_surface*, wl_output*) {} @@ -212,7 +298,7 @@ void wayland_window::_xdg_toplevel_listen_configure_bounds(void*, xdg_toplevel*, void wayland_window::_xdg_toplevel_listen_close(void* data, xdg_toplevel*) { wayland_window* window = static_cast(data); - window->hide(); + window->shutdown(); } @@ -223,14 +309,52 @@ void wayland_window::_xdg_toplevel_listen_wm_capabilities(void*, xdg_toplevel*, #if FENNEC_HAS_LIBDECOR -void wayland_window::_libdecor_frame_listen_configure(libdecor_frame*, libdecor_configuration*, void*) {} +void wayland_window::_libdecor_frame_listen_configure(libdecor_frame* frame, libdecor_configuration* cfg, void* data) { + wayland_window* window = static_cast(data); + + ivec2 size = window->state.rect.size; + libdecor_configuration_get_content_size(cfg, frame, &size.x, &size.y); + size.x = size.x == 0 ? window->state.rect.size.x : size.x; + size.y = size.y == 0 ? window->state.rect.size.y : size.y; + + size.x = size.x == 0 ? window->cfg.rect.size.x : size.x; + size.y = size.y == 0 ? window->cfg.rect.size.y : size.y; + + assertf(size.x != 0 or size.y != 0, "Invalid window size!"); + + libdecor_window_state state = LIBDECOR_WINDOW_STATE_NONE; + + window->state.mode = mode_windowed; + window->state.flags.clear(state_suspended); + window->libdecorcfg = cfg; + + if (libdecor_configuration_get_window_state(cfg, &state)) { + if (state & LIBDECOR_WINDOW_STATE_MAXIMIZED) { + window->state.mode = mode_maximized; + } + + if (state & LIBDECOR_WINDOW_STATE_FULLSCREEN) { + window->state.mode = mode_fullscreen; + } + + if (state & LIBDECOR_WINDOW_STATE_SUSPENDED) { + window->state.flags.set(state_suspended); + } + } + + window->_update_size(size); +} void wayland_window::_libdecor_frame_listen_close(libdecor_frame*, void* data) { wayland_window* window = static_cast(data); - window->hide(); + window->shutdown(); +} + +void wayland_window::_libdecor_frame_listen_commit(libdecor_frame*, void* data) { + wayland_window* window = static_cast(data); + window->gfx_surface->swap(); } -void wayland_window::_libdecor_frame_listen_commit(libdecor_frame*, void*) {} void wayland_window::_libdecor_frame_listen_dismiss_popup(libdecor_frame*, const char*, void*) {} #endif diff --git a/source/platform/opengl/egl/context.cpp b/source/platform/opengl/egl/context.cpp index e6d02b6..060bfa8 100644 --- a/source/platform/opengl/egl/context.cpp +++ b/source/platform/opengl/egl/context.cpp @@ -38,7 +38,13 @@ static const cstring& egl_translate_type(EGLint type) { } eglcontext::eglcontext(display_server* display) - : glcontext(display) { + : glcontext(display) + , _egldisplay(nullptr) + , _eglcontext(nullptr) + , _eglconfig(nullptr) + , _eglvmajor(0) + , _eglvminor(0) + , _eglctype(0){ EGLint config_attrs[] = { EGL_SURFACE_TYPE, diff --git a/source/platform/opengl/egl/surface.cpp b/source/platform/opengl/egl/surface.cpp index 06a3889..dc81a3c 100644 --- a/source/platform/opengl/egl/surface.cpp +++ b/source/platform/opengl/egl/surface.cpp @@ -16,12 +16,13 @@ // along with this program. If not, see . // ===================================================================================================================== +#include #include #include namespace fennec { -eglsurface::eglsurface(fennec::window* win, eglcontext* ctx, EGLNativeWindowType eglwindow) +eglsurface::eglsurface(fennec::window* win, eglcontext* ctx, void* eglwindow) : gfxsurface(win, ctx) , _eglwindow(eglwindow) , _eglsurface(nullptr) { @@ -31,25 +32,32 @@ eglsurface::eglsurface(fennec::window* win, eglcontext* ctx, EGLNativeWindowType _eglsurface = eglCreateWindowSurface( ctx->_egldisplay, ctx->_eglconfig, - _eglwindow, + reinterpret_cast(_eglwindow), nullptr ); + + if (not _eglsurface) { + int32_t err = eglGetError(); + logger::log(format("EGL error: {}", eglErrorString(err))); + } assertf(_eglsurface, "Failed to create EGL surface!"); + + eglsurface::make_current(); } eglsurface::~eglsurface() { eglcontext* ctx = static_cast(context); - eglDestroySurface(ctx->_egldisplay, _eglsurface); + assertf(eglDestroySurface(ctx->_egldisplay, _eglsurface), "Error destroying EGL surface!"); } void eglsurface::make_current() { eglcontext* ctx = static_cast(context); - eglMakeCurrent(ctx->_egldisplay, _eglsurface, _eglsurface, ctx->_eglcontext); + assertf(eglMakeCurrent(ctx->_egldisplay, _eglsurface, _eglsurface, ctx->_eglcontext), "Error setting the current surface!"); } void eglsurface::swap() { eglcontext* ctx = static_cast(context); - eglSwapBuffers(ctx->_egldisplay, _eglsurface); + assertf(eglSwapBuffers(ctx->_egldisplay, _eglsurface), "Error swapping surface buffers!"); } } // fennec \ No newline at end of file diff --git a/test/tests/test_platform.h b/test/tests/test_platform.h index 3650732..7ef929b 100644 --- a/test/tests/test_platform.h +++ b/test/tests/test_platform.h @@ -34,18 +34,22 @@ inline void fennec_test_platform() { display_server* display = platform->get_display_server(); - window* window = display->create_window({ - .title = string("test window"), - .flags = {}, + window* window = display->create_window(window::config { + .title = string("fennec-test"), + .flags = { }, .mode = window::mode_windowed, .parent = window::nullid, - .size = ivec2{ 720, 480 }, + .rect = { + .position = { 0, 0 }, + .size = { 720, 480 }, + }, + .fractional_scaling = 0, .accessibility = { string("test window"), string("test window description") } }); assertf(window != nullptr, "Failed to create test window."); - window->show(); + window->initialize(); while (window->is_running()) { window->begin_frame(); @@ -54,7 +58,7 @@ inline void fennec_test_platform() { display->dispatch(); } - window->hide(); + window->shutdown(); delete window;