8#define GLFW_EXPOSE_NATIVE_COCOA
9#include <GLFW/glfw3native.h>
13GlfwWindow::GlfwWindow(
const WindowCreateInfo& create_info,
15 : m_create_info(create_info)
17 GLFWSingleton::configure(pre_init_config);
19 if (!GLFWSingleton::initialize()) {
20 error<std::runtime_error>(Journal::Component::Core, Journal::Context::WindowingSubsystem, std::source_location::current(),
21 "Failed to initialize GLFW for window creation");
24 configure_window_hints(surface_info, api);
26 GLFWmonitor* monitor =
nullptr;
27 if (create_info.fullscreen) {
28 if (create_info.monitor_id >= 0) {
30 std::span<GLFWmonitor*> monitors(glfwGetMonitors(&
count),
count);
31 if (create_info.monitor_id <
count) {
32 monitor = monitors[create_info.monitor_id];
35 monitor = glfwGetPrimaryMonitor();
39 m_window = glfwCreateWindow(
40 (int32_t)create_info.width,
41 (int32_t)create_info.height,
42 create_info.title.c_str(),
47 error<std::runtime_error>(Journal::Component::Core, Journal::Context::WindowingSubsystem, std::source_location::current(),
48 "Failed to create GLFW window: {}", create_info.title);
51 glfwSetWindowUserPointer(m_window,
this);
55 glfwGetWindowSize(m_window, &w, &
h);
56 m_state.current_width = w;
57 m_state.current_height =
h;
58 m_state.is_visible =
false;
60 GLFWSingleton::mark_window_created();
62 MF_INFO(Journal::Component::Core, Journal::Context::WindowingSubsystem,
63 "Created window '{}' ({}x{})", create_info.title, w,
h);
66GlfwWindow::~GlfwWindow()
71void GlfwWindow::destroy()
74 glfwDestroyWindow(m_window);
75 GLFWSingleton::mark_window_destroyed();
80GlfwWindow::GlfwWindow(GlfwWindow&& other) noexcept
81 : m_window(other.m_window)
82 , m_create_info(std::move(other.m_create_info))
83 , m_state(other.m_state)
84 , m_input_config(other.m_input_config)
85 , m_event_callback(std::move(other.m_event_callback))
87 other.m_window =
nullptr;
89 glfwSetWindowUserPointer(m_window,
this);
93GlfwWindow& GlfwWindow::operator=(GlfwWindow&& other)
noexcept
97 glfwDestroyWindow(m_window);
98 GLFWSingleton::mark_window_destroyed();
101 m_window = other.m_window;
102 m_create_info = std::move(other.m_create_info);
103 m_state = other.m_state;
104 m_input_config = other.m_input_config;
105 m_event_callback = std::move(other.m_event_callback);
107 other.m_window =
nullptr;
109 glfwSetWindowUserPointer(m_window,
this);
115void GlfwWindow::set_title(
const std::string& title)
118 glfwSetWindowTitle(m_window, title.c_str());
119 m_create_info.title = title;
123void GlfwWindow::configure_window_hints(
const GraphicsSurfaceInfo& , GlobalGraphicsConfig::GraphicsApi api)
const
125 glfwDefaultWindowHints();
127#ifdef MAYAFLUX_PLATFORM_MACOS
128 glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
130 glfwWindowHint(GLFW_RESIZABLE, m_create_info.resizable ? GLFW_TRUE : GLFW_FALSE);
133 glfwWindowHint(GLFW_DECORATED, m_create_info.decorated ? GLFW_TRUE : GLFW_FALSE);
134 glfwWindowHint(GLFW_FLOATING, m_create_info.floating ? GLFW_TRUE : GLFW_FALSE);
135 glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, m_create_info.transparent ? GLFW_TRUE : GLFW_FALSE);
136 glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
138 if (api == GlobalGraphicsConfig::GraphicsApi::VULKAN) {
139 glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
140 }
else if (api == GlobalGraphicsConfig::GraphicsApi::OPENGL) {
141 glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API);
145void GlfwWindow::setup_callbacks()
147 glfwSetWindowSizeCallback(m_window, glfw_window_size_callback);
148 glfwSetWindowCloseCallback(m_window, glfw_window_close_callback);
149 glfwSetWindowFocusCallback(m_window, glfw_window_focus_callback);
150 glfwSetFramebufferSizeCallback(m_window, glfw_framebuffer_size_callback);
151 glfwSetKeyCallback(m_window, glfw_key_callback);
152 glfwSetCursorPosCallback(m_window, glfw_cursor_pos_callback);
153 glfwSetMouseButtonCallback(m_window, glfw_mouse_button_callback);
154 glfwSetScrollCallback(m_window, glfw_scroll_callback);
157void GlfwWindow::show()
160 glfwShowWindow(m_window);
161 m_state.is_visible =
true;
165void GlfwWindow::hide()
168 glfwHideWindow(m_window);
169 m_state.is_visible =
false;
173bool GlfwWindow::should_close()
const
175 return m_window ? glfwWindowShouldClose(m_window) : true;
178void GlfwWindow::set_event_callback(WindowEventCallback callback)
180 m_event_callback = std::move(callback);
183void* GlfwWindow::get_native_handle()
const
188 return glfwGetCocoaWindow(m_window);
191void GlfwWindow::glfw_window_size_callback(GLFWwindow* window,
int width,
int height)
193 auto* win =
static_cast<GlfwWindow*
>(glfwGetWindowUserPointer(window));
194 if (win && win->m_event_callback) {
195 win->m_state.current_width =
width;
196 win->m_state.current_height = height;
198 if (win->m_event_callback) {
200 event.type = WindowEventType::WINDOW_RESIZED;
201 event.timestamp = glfwGetTime();
202 event.data = WindowEvent::ResizeData {
203 .width =
static_cast<uint32_t
>(
width),
204 .height =
static_cast<uint32_t
>(height)
206 win->m_event_callback(event);
211void GlfwWindow::set_size(uint32_t
width, uint32_t height)
214 glfwSetWindowSize(m_window,
static_cast<int>(
width),
static_cast<int>(height));
217 m_create_info.width =
width;
218 m_create_info.height = height;
221void GlfwWindow::set_position(uint32_t x, uint32_t y)
224 glfwSetWindowPos(m_window,
static_cast<int>(x),
static_cast<int>(y));
228void GlfwWindow::set_color(
const std::array<float, 4>& color)
230 m_create_info.clear_color = color;
233void GlfwWindow::glfw_window_close_callback(GLFWwindow* window)
235 auto* win =
static_cast<GlfwWindow*
>(glfwGetWindowUserPointer(window));
240 event.type = WindowEventType::WINDOW_CLOSED;
241 event.timestamp = glfwGetTime();
243 win->m_event_source.signal(event);
245 if (win->m_event_callback) {
246 win->m_event_callback(event);
250void GlfwWindow::glfw_window_focus_callback(GLFWwindow* window,
int focused)
252 auto* win =
static_cast<GlfwWindow*
>(glfwGetWindowUserPointer(window));
256 win->m_state.is_focused = (focused == GLFW_TRUE);
259 event.type = focused ? WindowEventType::WINDOW_FOCUS_GAINED
260 : WindowEventType::WINDOW_FOCUS_LOST;
261 event.timestamp = glfwGetTime();
263 win->m_event_source.signal(event);
265 if (win->m_event_callback) {
266 win->m_event_callback(event);
270void GlfwWindow::glfw_framebuffer_size_callback(GLFWwindow* window,
int width,
int height)
272 auto* win =
static_cast<GlfwWindow*
>(glfwGetWindowUserPointer(window));
277 event.type = WindowEventType::FRAMEBUFFER_RESIZED;
278 event.timestamp = glfwGetTime();
279 event.data = WindowEvent::ResizeData {
280 .width =
static_cast<uint32_t
>(
width),
281 .height =
static_cast<uint32_t
>(height)
284 win->m_event_source.signal(event);
286 if (win->m_event_callback) {
287 win->m_event_callback(event);
291void GlfwWindow::glfw_key_callback(GLFWwindow* window,
int key,
int scancode,
int action,
int mods)
293 auto* win =
static_cast<GlfwWindow*
>(glfwGetWindowUserPointer(window));
300 type = WindowEventType::KEY_PRESSED;
303 type = WindowEventType::KEY_RELEASED;
306 type = WindowEventType::KEY_REPEAT;
314 event.timestamp = glfwGetTime();
315 event.data = WindowEvent::KeyData {
316 .key =
static_cast<int16_t
>(key),
317 .scancode = scancode,
321 win->m_event_source.signal(event);
323 if (win->m_event_callback) {
324 win->m_event_callback(event);
328void GlfwWindow::glfw_cursor_pos_callback(GLFWwindow* window,
double xpos,
double ypos)
330 auto* win =
static_cast<GlfwWindow*
>(glfwGetWindowUserPointer(window));
335 event.type = WindowEventType::MOUSE_MOTION;
336 event.timestamp = glfwGetTime();
338 event.data = WindowEvent::MousePosData {
343 win->m_event_source.signal(event);
345 if (win->m_event_callback) {
346 win->m_event_callback(event);
350void GlfwWindow::glfw_mouse_button_callback(GLFWwindow* window,
int button,
int action,
int mods)
352 auto* win =
static_cast<GlfwWindow*
>(glfwGetWindowUserPointer(window));
357 event.type = (action == GLFW_PRESS) ? WindowEventType::MOUSE_BUTTON_PRESSED
359 event.timestamp = glfwGetTime();
361 event.data = WindowEvent::MouseButtonData {
362 .button =
static_cast<int8_t
>(button),
366 win->m_event_source.signal(event);
368 if (win->m_event_callback) {
369 win->m_event_callback(event);
373void GlfwWindow::glfw_scroll_callback(GLFWwindow* window,
double xoffset,
double yoffset)
375 auto* win =
static_cast<GlfwWindow*
>(glfwGetWindowUserPointer(window));
380 event.type = WindowEventType::MOUSE_SCROLLED;
381 event.timestamp = glfwGetTime();
382 event.data = WindowEvent::ScrollData {
387 win->m_event_source.signal(event);
389 if (win->m_event_callback) {
390 win->m_event_callback(event);
394void GlfwWindow::set_graphics_registered(
bool registered)
396 m_graphics_registered.store(registered, std::memory_order_release);
399void GlfwWindow::register_rendering_buffer(std::shared_ptr<Buffers::VKBuffer> buffer)
401 for (
const auto& weak_buf : m_rendering_buffers) {
402 if (
auto buf = weak_buf.lock()) {
409 std::lock_guard lock(m_render_tracking_mutex);
410 m_rendering_buffers.push_back(buffer);
412 MF_RT_DEBUG(Journal::Component::Core, Journal::Context::GraphicsCallback,
413 "Window '{}': registered VKBuffer for rendering (total: {})",
414 m_create_info.title, m_rendering_buffers.size());
417void GlfwWindow::unregister_rendering_buffer(std::shared_ptr<Buffers::VKBuffer> buffer)
419 auto it = std::ranges::find_if(m_rendering_buffers,
420 [&buffer](
const std::weak_ptr<Buffers::VKBuffer>& weak_buf) {
421 auto buf = weak_buf.lock();
422 return buf == buffer;
425 if (it != m_rendering_buffers.end()) {
426 std::lock_guard lock(m_render_tracking_mutex);
427 m_rendering_buffers.erase(it);
431void GlfwWindow::track_frame_command(uint64_t cmd_id)
433 std::lock_guard lock(m_render_tracking_mutex);
434 m_frame_commands.push_back(cmd_id);
436 MF_RT_TRACE(Journal::Component::Core, Journal::Context::GraphicsCallback,
437 "Window '{}': tracked command buffer {} (total this frame: {})",
438 m_create_info.title, cmd_id, m_frame_commands.size());
441const std::vector<uint64_t>& GlfwWindow::get_frame_commands()
const
443 return m_frame_commands;
446void GlfwWindow::clear_frame_commands()
448 std::lock_guard lock(m_render_tracking_mutex);
449 m_frame_commands.clear();
452std::vector<std::shared_ptr<Buffers::VKBuffer>> GlfwWindow::get_rendering_buffers()
const
454 std::lock_guard lock(m_render_tracking_mutex);
456 std::vector<std::shared_ptr<Buffers::VKBuffer>> buffers;
457 for (
const auto& weak_buf : m_rendering_buffers) {
458 if (
auto buf = weak_buf.lock()) {
459 buffers.push_back(buf);
#define MF_INFO(comp, ctx,...)
#define MF_RT_TRACE(comp, ctx,...)
#define MF_RT_DEBUG(comp, ctx,...)
WindowEventType
Types of window and input events.