From 7370d562de22c6efdb2b9d8d584dd28485168039 Mon Sep 17 00:00:00 2001 From: Oskari Alaranta Date: Sun, 7 Jun 2026 20:39:23 +0300 Subject: [PATCH] Rework rendering --- xbanan/Base.cpp | 390 +++++++++++++++-------------------- xbanan/Base.h | 7 +- xbanan/Definitions.h | 3 + xbanan/Drawing.cpp | 10 +- xbanan/Events.cpp | 65 +----- xbanan/Platform.h | 11 +- xbanan/SDL3/sdl3.cpp | 49 ++--- xbanan/banan-os/banan-os.cpp | 30 ++- xbanan/main.cpp | 12 ++ 9 files changed, 261 insertions(+), 316 deletions(-) diff --git a/xbanan/Base.cpp b/xbanan/Base.cpp index fce9fcc..dd4d2ab 100644 --- a/xbanan/Base.cpp +++ b/xbanan/Base.cpp @@ -296,85 +296,61 @@ static BAN::ErrorOr send_visibility_events_recursively(Client& client_info return {}; } -static void invalidate_window_recursive(WINDOW wid, int32_t x, int32_t y, int32_t w, int32_t h) +static void invalidate_window_recursive(Object::Window& dst_window, int32_t dst_x, int32_t dst_y, const Object::Window& src_window, int32_t src_x, int32_t src_y, int32_t w, int32_t h) { - ASSERT(wid != g_root.windowId); + ASSERT(src_window.mapped); - if (x + w <= 0 || y + h <= 0) - return; - if (w <= 0 || h <= 0) - return; - - auto& object = *g_objects[wid]; - ASSERT(object.type == Object::Type::Window); - - auto& window = object.object.get(); - if (!window.mapped) - return; - - for (auto child_wid : window.children) + if (src_window.c_class == InputOutput) { - const auto& child_object = *g_objects[child_wid]; - ASSERT(child_object.type == Object::Type::Window); + ASSERT(src_x >= 0); + ASSERT(src_y >= 0); + ASSERT(src_x + w <= src_window.width); + ASSERT(src_y + h <= src_window.height); + ASSERT(dst_x + w <= dst_window.width); + ASSERT(dst_y + h <= dst_window.height); - const auto& child_window = child_object.object.get(); - if (!child_window.mapped) - continue; - - const auto child_x = x - child_window.x; - const auto child_y = y - child_window.y; - - const auto child_w = BAN::Math::min(w - child_window.x, child_window.width - child_x); - const auto child_h = BAN::Math::min(h - child_window.y, child_window.height - child_y); - - invalidate_window_recursive( - child_wid, - child_x, child_y, - child_w, child_h - ); + for (int32_t y = 0; y < h; y++) + { + uint32_t* dst_u32 = &dst_window.double_buffer[(dst_y + y) * dst_window.width + dst_x]; + const uint32_t* src_u32 = &src_window. pixels[(src_y + y) * src_window.width + src_x]; + for (int32_t x = 0; x < w; x++) + { + if (src_u32[x] != COLOR_INVISIBLE) + dst_u32[x] = 0xFF000000 | src_u32[x]; + else if (&dst_window == &src_window) + dst_u32[x] = 0x00000000; + } + } } - if (window.platform_window || window.c_class == InputOnly) - return; - - auto& parent_object = *g_objects[window.parent]; - ASSERT(parent_object.type == Object::Type::Window); - - auto& parent_window = parent_object.object.get(); - - const uint32_t* child_pix = window.pixels.data(); - const int32_t child_w = window.width; - const int32_t child_h = window.height; - - uint32_t* parent_pix = parent_window.pixels.data(); - const int32_t parent_w = parent_window.width; - const int32_t parent_h = parent_window.height; - - // FIXME: optimize this - for (int32_t y_off = 0; y_off < h; y_off++) + for (auto child_wid : src_window.children) { - const int32_t child_y = y + y_off; - if (child_y < 0 || child_y >= child_h) + const auto& child = g_objects[child_wid]->object.get(); + if (!child.mapped) continue; - const int32_t parent_y = window.y + y + y_off; - if (parent_y < 0 || parent_y >= parent_h) + const auto diff_x = src_x - child.x; + const auto diff_y = src_y - child.y; + + const auto min_x = BAN::Math::max(diff_x, 0); + const auto min_y = BAN::Math::max(diff_y, 0); + + const auto max_x = BAN::Math::min(diff_x + w, child.width); + const auto max_y = BAN::Math::min(diff_y + h, child.height); + + if (max_x <= min_x || max_y <= min_y) continue; - for (int32_t x_off = 0; x_off < w; x_off++) - { - const int32_t child_x = x + x_off; - if (child_x < 0 || child_x >= child_w) - continue; - - const int32_t parent_x = window.x + x + x_off; - if (parent_x < 0 || parent_x >= parent_w) - continue; - - const uint32_t color = child_pix[child_y * child_w + child_x]; - if (color != COLOR_INVISIBLE) - parent_pix[parent_y * parent_w + parent_x] = color; - } + invalidate_window_recursive( + dst_window, + dst_x - (diff_x - min_x), + dst_y - (diff_y - min_y), + child, + min_x, + min_y, + max_x - min_x, + max_y - min_y + ); } } @@ -382,68 +358,120 @@ void invalidate_window(WINDOW wid, int32_t x, int32_t y, int32_t w, int32_t h) { ASSERT(wid != g_root.windowId); + int32_t min_x { x }, max_x { x + w }; + int32_t min_y { y }, max_y { y + h }; + for (;;) { if (wid == g_root.windowId) return; - auto& object = *g_objects[wid]; - ASSERT(object.type == Object::Type::Window); - - auto& window = object.object.get(); + const auto& window = g_objects[wid]->object.get(); if (!window.mapped) return; + + if (min_x < 0) + min_x = 0; + if (min_y < 0) + min_y = 0; + + if (max_x > window.width) + max_x = window.width; + if (max_y > window.height) + max_y = window.height; + + if (max_x <= min_x || max_y <= min_y) + return; + if (window.platform_window) break; - x += window.x; - y += window.y; + min_x += window.x; + min_y += window.y; wid = window.parent; } - auto& object = *g_objects[wid]; - ASSERT(object.type == Object::Type::Window); + auto& window = g_objects[wid]->object.get(); - auto& window = object.object.get(); - ASSERT(window.platform_window); + invalidate_window_recursive( + window, min_x, min_y, + window, min_x, min_y, + max_x - min_x, + max_y - min_y + ); - invalidate_window_recursive(wid, x, y, w, h); + if (!window.platform_window_invalidated && g_platform_ops.begin_frame) + g_platform_ops.begin_frame(window.platform_window.ptr()); + window.platform_window_invalidated = true; - const auto min_x = BAN::Math::max(x, 0); - const auto min_y = BAN::Math::max(y, 0); - const auto max_x = BAN::Math::min(x + w, window.width); - const auto max_y = BAN::Math::min(y + h, window.height); - - if (min_x >= max_x || min_y >= max_y) - return; - - uint32_t* pixels = window.pixels.data(); - for (auto y = min_y; y < max_y; y++) - { - for (auto x = min_x; x < max_x; x++) - { - auto& pixel = pixels[y * window.width + x]; - if (pixel == COLOR_INVISIBLE) - pixel = 0x00000000; - else - pixel |= 0xFF000000; - } - } - - g_platform_ops.invalidate(window.platform_window.ptr(), window.pixels.data(), min_x, min_y, max_x - min_x, max_y - min_y); + g_platform_ops.invalidate( + window.platform_window.ptr(), + &window.double_buffer[min_y * window.width + min_x], + window.width * sizeof(uint32_t), + min_x, min_y, + max_x - min_x, + max_y - min_y + ); } -void send_exposure_recursive(WINDOW wid) +BAN::ErrorOr send_configure_notify(WINDOW wid) { - auto& object = *g_objects[wid]; - ASSERT(object.type == Object::Type::Window); + auto& window = g_objects[wid]->object.get(); - auto& window = object.object.get(); + { + xEvent event = { .u = { + .configureNotify = { + .event = wid, + .window = wid, + .aboveSibling = xFalse, + .x = static_cast(window.x), + .y = static_cast(window.y), + .width = static_cast(window.width), + .height = static_cast(window.height), + .borderWidth = 0, + .override = xFalse, + } + }}; + event.u.u.type = ConfigureNotify; + TRY(window.send_event(event, StructureNotifyMask)); + } + + auto& parent_object = *g_objects[window.parent]; + ASSERT(parent_object.type == Object::Type::Window); + auto& parent_window = parent_object.object.get(); + + { + xEvent event = { .u = { + .configureNotify = { + .event = window.parent, + .window = wid, + .aboveSibling = xFalse, + .x = static_cast(window.x), + .y = static_cast(window.y), + .width = static_cast(window.width), + .height = static_cast(window.height), + .borderWidth = 0, + .override = xFalse, + } + }}; + event.u.u.type = ConfigureNotify; + TRY(parent_window.send_event(event, SubstructureNotifyMask)); + } + + return {}; +} + +BAN::ErrorOr send_exposure_events_recursive(WINDOW wid) +{ + auto& window = g_objects[wid]->object.get(); if (!window.mapped) - return; + return {}; for (auto child_wid : window.children) - send_exposure_recursive(child_wid); + TRY(send_exposure_events_recursive(child_wid)); + + if (window.c_class == InputOnly) + return {}; xEvent event = { .u = { .expose = { @@ -455,66 +483,32 @@ void send_exposure_recursive(WINDOW wid) } }}; event.u.u.type = Expose; - MUST(window.send_event(event, ExposureMask)); + TRY(window.send_event(event, ExposureMask)); + + return {}; } -struct PlatformWindowInfo -{ - PlatformWindow* parent; - WindowType type; -}; - -static PlatformWindowInfo get_plaform_window_info(const Object::Window& window) +static WindowType get_plaform_window_info(const Object::Window& window) { static const CARD32 ATOM = g_atoms_name_to_id["ATOM"_sv]; - static const CARD32 WINDOW = g_atoms_name_to_id["WINDOW"_sv]; - static const CARD32 WM_TRANSIENT_FOR = g_atoms_name_to_id["WM_TRANSIENT_FOR"_sv]; static const CARD32 _NET_WM_WINDOW_TYPE = g_atoms_name_to_id["_NET_WM_WINDOW_TYPE"_sv]; static const CARD32 _NET_WM_WINDOW_TYPE_DIALOG = g_atoms_name_to_id["_NET_WM_WINDOW_TYPE_DIALOG"_sv]; static const CARD32 _NET_WM_WINDOW_TYPE_NORMAL = g_atoms_name_to_id["_NET_WM_WINDOW_TYPE_NORMAL"_sv]; static const CARD32 _NET_WM_WINDOW_TYPE_SPLASH = g_atoms_name_to_id["_NET_WM_WINDOW_TYPE_SPLASH"_sv]; - static const CARD32 _NET_WM_WINDOW_TYPE_UTILITY = g_atoms_name_to_id["_NET_WM_WINDOW_TYPE_UTILITY"_sv]; - PlatformWindowInfo info { - .parent = nullptr, - .type = WindowType::Normal, - }; + auto it = window.properties.find(_NET_WM_WINDOW_TYPE); + if (it == window.properties.end()) + return WindowType::Normal; - if (auto it = window.properties.find(_NET_WM_WINDOW_TYPE); it != window.properties.end()) - { - if (it->value.type != ATOM || it->value.data.size() != sizeof(CARD32)) - goto wm_window_type_done; + if (it->value.type != ATOM || it->value.data.size() != sizeof(CARD32)) + return WindowType::Normal; - const CARD32 type = *reinterpret_cast(it->value.data.data()); - if (type == _NET_WM_WINDOW_TYPE_NORMAL) - info.type = WindowType::Normal; - else if (type == _NET_WM_WINDOW_TYPE_SPLASH || type == _NET_WM_WINDOW_TYPE_DIALOG) - info.type = WindowType::Utility; - else - info.type = WindowType::Popup; - } -wm_window_type_done: - - if (auto it = window.properties.find(WM_TRANSIENT_FOR); it != window.properties.end()) - { - if (it->value.type != WINDOW || it->value.data.size() != sizeof(CARD32)) - goto transitient_for_done; - - const CARD32 wid = *reinterpret_cast(it->value.data.data()); - - auto it2 = g_objects.find(wid); - if (it2 == g_objects.end()) - goto transitient_for_done; - if (it2->value->type != Object::Type::Window) - goto transitient_for_done; - - // FIXME: support child windows - auto& window = it2->value->object.get(); - info.parent = window.platform_window.ptr(); - } -transitient_for_done: - - return info; + const CARD32 type = *reinterpret_cast(it->value.data.data()); + if (type == _NET_WM_WINDOW_TYPE_NORMAL) + return WindowType::Normal; + if (type == _NET_WM_WINDOW_TYPE_SPLASH || type == _NET_WM_WINDOW_TYPE_DIALOG) + return WindowType::Utility; + return WindowType::Popup; } static BAN::ErrorOr map_window(Client& client_info, WINDOW wid) @@ -537,10 +531,13 @@ static BAN::ErrorOr map_window(Client& client_info, WINDOW wid) if (window.width <= 10 || window.height <= 10) return {}; - auto info = get_plaform_window_info(window); + TRY(window.double_buffer.resize(window.width * window.height)); + for (auto& pixel : window.double_buffer) + pixel = window.background; + + const auto type = get_plaform_window_info(window); window.platform_window = TRY(g_platform_ops.create_window( - info.parent, - info.type, + type, wid, window.x, window.y, @@ -584,19 +581,7 @@ static BAN::ErrorOr map_window(Client& client_info, WINDOW wid) if (is_visible(window.parent)) TRY(send_visibility_events_recursively(client_info, wid, true)); - { - xEvent event = { .u = { - .expose = { - .window = wid, - .x = 0, - .y = 0, - .width = static_cast(window.width), - .height = static_cast(window.height), - } - }}; - event.u.u.type = Expose; - TRY(window.send_event(event, ExposureMask)); - } + TRY(send_exposure_events_recursive(wid)); return {}; } @@ -612,8 +597,8 @@ static BAN::ErrorOr unmap_window(Client& client_info, WINDOW wid) window.mapped = false; - if (window.platform_window) - window.platform_window.clear(); + window.double_buffer.clear(); + window.platform_window.clear(); if (is_visible(window.parent)) TRY(send_visibility_events_recursively(client_info, wid, false)); @@ -1228,6 +1213,7 @@ BAN::ErrorOr handle_packet(Client& client_info, BAN::ConstByteSpan packet) dprintln("ConfigureWindow"); dprintln(" window: {}", request.window); + dprintln(" mask: {4h}", request.mask); auto& window = TRY_REF(get_window(client_info, request.window, opcode)); @@ -1236,7 +1222,6 @@ BAN::ErrorOr handle_packet(Client& client_info, BAN::ConstByteSpan packet) uint32_t new_width = window.width; uint32_t new_height = window.height; - dprintln(" mask:"); for (size_t i = 0; i < 7; i++) { if (!(request.mask & (1 << i))) @@ -1248,15 +1233,19 @@ BAN::ErrorOr handle_packet(Client& client_info, BAN::ConstByteSpan packet) { case 0: new_x = value; + dprintln(" x: {}", value); break; case 1: new_y = value; + dprintln(" y: {}", value); break; case 2: new_width = value; + dprintln(" w: {}", value); break; case 3: new_height = value; + dprintln(" h: {}", value); break; default: dprintln(" {4h}: {4h}", 1 << i, value); @@ -1264,7 +1253,7 @@ BAN::ErrorOr handle_packet(Client& client_info, BAN::ConstByteSpan packet) } } - bool send_configure = false; + bool should_send_configure_notify = false; if (new_x != window.x || new_y != window.y) { @@ -1277,7 +1266,7 @@ BAN::ErrorOr handle_packet(Client& client_info, BAN::ConstByteSpan packet) { window.x = new_x; window.y = new_y; - send_configure = true; + should_send_configure_notify = true; } } @@ -1296,52 +1285,17 @@ BAN::ErrorOr handle_packet(Client& client_info, BAN::ConstByteSpan packet) window.width = new_width; window.height = new_height; - send_configure = true; + should_send_configure_notify = true; } } - if (!send_configure) + if (!should_send_configure_notify) break; - { - xEvent event = { .u = { - .configureNotify = { - .event = request.window, - .window = request.window, - .aboveSibling = xFalse, - .x = static_cast(window.x), - .y = static_cast(window.y), - .width = static_cast(window.width), - .height = static_cast(window.height), - .borderWidth = 0, - .override = xFalse, - } - }}; - event.u.u.type = ConfigureNotify; - TRY(window.send_event(event, StructureNotifyMask)); - } + TRY(send_configure_notify(request.window)); - auto& parent_object = *g_objects[window.parent]; - ASSERT(parent_object.type == Object::Type::Window); - auto& parent_window = parent_object.object.get(); - - { - xEvent event = { .u = { - .configureNotify = { - .event = window.parent, - .window = request.window, - .aboveSibling = xFalse, - .x = static_cast(window.x), - .y = static_cast(window.y), - .width = static_cast(window.width), - .height = static_cast(window.height), - .borderWidth = 0, - .override = xFalse, - } - }}; - event.u.u.type = ConfigureNotify; - TRY(parent_window.send_event(event, SubstructureNotifyMask)); - } + if (is_visible(request.window)) + TRY(send_exposure_events_recursive(request.window)); break; } @@ -2194,7 +2148,7 @@ BAN::ErrorOr handle_packet(Client& client_info, BAN::ConstByteSpan packet) // TODO: support invisible background uint32_t foreground = 0x000000; - uint32_t background = 0x000000; + uint32_t background = 0xFFFFFF; uint16_t line_width = 0; uint32_t font = None; bool graphics_exposures = true; diff --git a/xbanan/Base.h b/xbanan/Base.h index 6765548..2156882 100644 --- a/xbanan/Base.h +++ b/xbanan/Base.h @@ -6,7 +6,9 @@ BAN::ErrorOr setup_client_conneciton(Client& client_info, const xConnClien BAN::ErrorOr handle_packet(Client& client_info, BAN::ConstByteSpan packet); void invalidate_window(WINDOW wid, int32_t x, int32_t y, int32_t w, int32_t h); -void send_exposure_recursive(WINDOW wid); + +BAN::ErrorOr send_configure_notify(WINDOW wid); +BAN::ErrorOr send_exposure_events_recursive(WINDOW wid); void update_cursor(WINDOW wid, int32_t x, int32_t y); @@ -16,7 +18,8 @@ WINDOW find_child_window(WINDOW wid, int32_t& x, int32_t& y); xPoint get_window_position(WINDOW wid); -static constexpr uint32_t COLOR_INVISIBLE = 0x69000000; +// random number with alpha 0 :D +static constexpr uint32_t COLOR_INVISIBLE = 0x00b205AF; extern CARD16 g_keymask; extern CARD16 g_butmask; diff --git a/xbanan/Definitions.h b/xbanan/Definitions.h index 6562778..3703d49 100644 --- a/xbanan/Definitions.h +++ b/xbanan/Definitions.h @@ -66,8 +66,11 @@ struct Object uint32_t background { 0 }; + bool platform_window_invalidated { false }; BAN::UniqPtr platform_window; + BAN::Vector double_buffer; + BAN::HashMap event_masks; BAN::HashMap properties; diff --git a/xbanan/Drawing.cpp b/xbanan/Drawing.cpp index a486972..c6e54f6 100644 --- a/xbanan/Drawing.cpp +++ b/xbanan/Drawing.cpp @@ -107,7 +107,7 @@ BAN::ErrorOr poly_line(Client& client_info, BAN::ConstByteSpan packet) auto request = decode(packet).value(); dprintln("PolyLine"); - dprintln(" drawable: {}", request.drawable); + dprintln(" drawable: {h}", request.drawable); dprintln(" gc: {}", request.gc); dprintln(" coordMode: {}", request.coordMode); @@ -161,7 +161,7 @@ BAN::ErrorOr poly_segment(Client& client_info, BAN::ConstByteSpan packet) auto request = decode(packet).value(); dprintln("PolySegment"); - dprintln(" drawable: {}", request.drawable); + dprintln(" drawable: {h}", request.drawable); dprintln(" gc: {}", request.gc); auto [out_data_u32, out_w, out_h, _] = TRY(get_drawable_info(client_info, request.drawable, X_PolySegment)); @@ -203,7 +203,7 @@ BAN::ErrorOr fill_poly(Client& client_info, BAN::ConstByteSpan packet) auto request = decode(packet).value(); dprintln("FillPoly"); - dprintln(" drawable: {}", request.drawable); + dprintln(" drawable: {h}", request.drawable); dprintln(" gc: {}", request.gc); dprintln(" shape: {}", request.shape); dprintln(" coordMode: {}", request.coordMode); @@ -278,7 +278,7 @@ BAN::ErrorOr poly_fill_rectangle(Client& client_info, BAN::ConstByteSpan p auto request = decode(packet).value(); dprintln("PolyFillRectangle"); - dprintln(" drawable: {}", request.drawable); + dprintln(" drawable: {h}", request.drawable); dprintln(" gc: {}", request.gc); auto [out_data_u32, out_w, out_h, _] = TRY(get_drawable_info(client_info, request.drawable, X_PolyFillRectangle)); @@ -320,7 +320,7 @@ BAN::ErrorOr poly_fill_arc(Client& client_info, BAN::ConstByteSpan packet) auto request = decode(packet).value(); dprintln("PolyFillArc"); - dprintln(" drawable: {}", request.drawable); + dprintln(" drawable: {h}", request.drawable); dprintln(" gc: {}", request.gc); auto [out_data_32, out_w, out_h, _] = TRY(get_drawable_info(client_info, request.drawable, X_PolyFillArc)); diff --git a/xbanan/Events.cpp b/xbanan/Events.cpp index 48442a7..cdaa2d6 100644 --- a/xbanan/Events.cpp +++ b/xbanan/Events.cpp @@ -75,69 +75,26 @@ void on_window_close_event(WINDOW wid) } } -static void send_window_configure(WINDOW wid, Object::Window& window) -{ - { - xEvent event = { .u = { - .configureNotify = { - .event = wid, - .window = wid, - .aboveSibling = xFalse, - .x = static_cast(window.x), - .y = static_cast(window.y), - .width = static_cast(window.width), - .height = static_cast(window.height), - .borderWidth = 0, - .override = xFalse, - } - }}; - event.u.u.type = ConfigureNotify; - MUST(window.send_event(event, StructureNotifyMask)); - } - - auto& parent_object = *g_objects[window.parent]; - ASSERT(parent_object.type == Object::Type::Window); - auto& parent_window = parent_object.object.get(); - - { - xEvent event = { .u = { - .configureNotify = { - .event = window.parent, - .window = wid, - .aboveSibling = xFalse, - .x = static_cast(window.x), - .y = static_cast(window.y), - .width = static_cast(window.width), - .height = static_cast(window.height), - .borderWidth = 0, - .override = xFalse, - } - }}; - event.u.u.type = ConfigureNotify; - MUST(parent_window.send_event(event, SubstructureNotifyMask)); - } -} - void on_window_resize_event(WINDOW wid, uint32_t new_width, uint32_t new_height) { auto& object = *g_objects[wid]; ASSERT(object.type == Object::Type::Window); auto& window = object.object.get(); - { - window.width = new_width; - window.height = new_height; + window.width = new_width; + window.height = new_height; - MUST(window.pixels.resize(new_width * new_height)); - for (auto& pixel : window.pixels) - pixel = window.background; - } + MUST(window.pixels.resize(new_width * new_height)); + for (auto& pixel : window.pixels) + pixel = window.background; - send_window_configure(wid, window); + MUST(window.double_buffer.resize(new_width * new_height)); + for (auto& pixel : window.double_buffer) + pixel = window.background; - send_exposure_recursive(wid); + MUST(send_configure_notify(wid)); - invalidate_window(wid, 0, 0, window.width, window.height); + MUST(send_exposure_events_recursive(wid)); } void on_window_move_event(WINDOW wid, int32_t x, int32_t y) @@ -149,7 +106,7 @@ void on_window_move_event(WINDOW wid, int32_t x, int32_t y) window.x = x; window.y = y; - send_window_configure(wid, window); + MUST(send_configure_notify(wid)); } void on_window_focus_event(WINDOW wid, bool focused) diff --git a/xbanan/Platform.h b/xbanan/Platform.h index ed29d1a..acd3966 100644 --- a/xbanan/Platform.h +++ b/xbanan/Platform.h @@ -51,9 +51,14 @@ struct PlatformOps /* Handle pending events */ void (*poll_events)(void*); /* Create a window with given size */ - BAN::ErrorOr> (*create_window)(PlatformWindow* parent, WindowType, WINDOW wid, int32_t x, int32_t y, uint32_t width, uint32_t height); - /* Invaldate part of a window */ - void (*invalidate)(PlatformWindow*, const uint32_t* pixels, uint32_t x, uint32_t y, uint32_t width, uint32_t height); + BAN::ErrorOr> (*create_window)(WindowType, WINDOW wid, int32_t x, int32_t y, uint32_t width, uint32_t height); + /* All invalidate calls during one frame happen between calls to begin_frame and end_frame. pixels is in ARGB8888 + * invalidate should update the underlying textures + * begin_frame should do any necessary preparations to update a frame + * end_frame should flush the updated texturee to the window */ + void (*invalidate)(PlatformWindow*, const void* pixels, uint32_t pitch, uint32_t x, uint32_t y, uint32_t width, uint32_t height); + void (*begin_frame)(PlatformWindow*); + void (*end_frame)(PlatformWindow*); /* Request resize of a window, can be async */ void (*request_resize)(PlatformWindow*, uint32_t width, uint32_t height); /* Request window repositioning */ diff --git a/xbanan/SDL3/sdl3.cpp b/xbanan/SDL3/sdl3.cpp index 41739ff..95146f0 100644 --- a/xbanan/SDL3/sdl3.cpp +++ b/xbanan/SDL3/sdl3.cpp @@ -108,7 +108,7 @@ static bool sdl3_initialize() return true; } -static BAN::ErrorOr> sdl3_create_window(PlatformWindow* parent, WindowType type, WINDOW wid, int32_t x, int32_t y, uint32_t width, uint32_t height) +static BAN::ErrorOr> sdl3_create_window(WindowType type, WINDOW wid, int32_t x, int32_t y, uint32_t width, uint32_t height) { auto window = TRY(BAN::UniqPtr::create()); @@ -120,29 +120,19 @@ static BAN::ErrorOr> sdl3_create_window(PlatformWin switch (type) { case WindowType::Normal: - case WindowType::Utility: flags = SDL_WINDOW_RESIZABLE; break; + case WindowType::Utility: + flags = SDL_WINDOW_RESIZABLE | SDL_WINDOW_UTILITY; + break; case WindowType::Popup: - flags = SDL_WINDOW_BORDERLESS; + flags = SDL_WINDOW_BORDERLESS | SDL_WINDOW_UTILITY; break; } - if (parent == nullptr || type != WindowType::Popup) - { - if (type != WindowType::Normal) - flags |= SDL_WINDOW_UTILITY; - window->window = SDL_CreateWindow("", width, height, flags); - } - else - { - auto& sdl_parent = *static_cast(parent); + flags |= SDL_WINDOW_TRANSPARENT; - int parent_x, parent_y; - SDL_GetWindowPosition(sdl_parent.window, &parent_x, &parent_y); - - window->window = SDL_CreatePopupWindow(sdl_parent.window, x - parent_x, y - parent_y, width, height, flags | SDL_WINDOW_POPUP_MENU); - } + window->window = SDL_CreateWindow("", width, height, flags); if (window->window == nullptr) { @@ -150,6 +140,9 @@ static BAN::ErrorOr> sdl3_create_window(PlatformWin return BAN::Error::from_errno(EFAULT); } + if (x != 0 || y != 0) + SDL_SetWindowPosition(window->window, x, y); + window->renderer = SDL_CreateRenderer(window->window, nullptr); if (window->renderer == nullptr) { @@ -157,6 +150,8 @@ static BAN::ErrorOr> sdl3_create_window(PlatformWin return BAN::Error::from_errno(EFAULT); } + SDL_SetRenderDrawColor(window->renderer, 0, 0, 0, 0); + window->texture = SDL_CreateTexture(window->renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, width, height); if (window->texture == nullptr) { @@ -292,7 +287,7 @@ static void sdl3_poll_events(void*) } } -static void sdl3_invalidate(PlatformWindow* window, const uint32_t* src_pixels, uint32_t x, uint32_t y, uint32_t width, uint32_t height) +static void sdl3_invalidate(PlatformWindow* window, const void* src_pixels, uint32_t src_pitch, uint32_t x, uint32_t y, uint32_t width, uint32_t height) { auto& sdl_window = *static_cast(window); @@ -317,16 +312,20 @@ static void sdl3_invalidate(PlatformWindow* window, const uint32_t* src_pixels, for (int32_t y_off = 0; y_off < rect.h; y_off++) { memcpy( - static_cast(dst_pixels) + y_off * dst_pitch, - &src_pixels[(rect.y + y_off) * sdl_window.width + rect.x], + static_cast< uint8_t*>(dst_pixels) + y_off * dst_pitch, + static_cast(src_pixels) + y_off * src_pitch, rect.w * sizeof(uint32_t) ); } SDL_UnlockTexture(sdl_window.texture); +} +static void sdl3_end_frame(PlatformWindow* window) +{ + auto& sdl_window = *static_cast(window); SDL_RenderClear(sdl_window.renderer); - SDL_RenderTexture(sdl_window.renderer, sdl_window.texture, NULL, NULL); + SDL_RenderTexture(sdl_window.renderer, sdl_window.texture, nullptr, nullptr); SDL_RenderPresent(sdl_window.renderer); } @@ -439,6 +438,8 @@ PlatformOps g_platform_ops = { .poll_events = sdl3_poll_events, .create_window = sdl3_create_window, .invalidate = sdl3_invalidate, + .begin_frame = nullptr, + .end_frame = sdl3_end_frame, .request_resize = sdl3_request_resize, .request_reposition = sdl3_request_reposition, .request_fullscreen = sdl3_request_fullscreen, @@ -506,9 +507,9 @@ static uint32_t sdl3_keycode_to_x_keysym(SDL_Keycode keycode) { if (iswprint(keycode)) { - if ((keycode >= 0x20 && keycode <= 0x7E) || (keycode >= 0xA0 && keycode <= 0xFF)) - return keycode; - return 0x01000000 | keycode; + if (keycode >= 0x100) + keycode |= 0x01000000; + return keycode; } switch (keycode) diff --git a/xbanan/banan-os/banan-os.cpp b/xbanan/banan-os/banan-os.cpp index 83a9b34..f1b913d 100644 --- a/xbanan/banan-os/banan-os.cpp +++ b/xbanan/banan-os/banan-os.cpp @@ -57,12 +57,9 @@ static void bananos_poll_events(void* window) banan_window.window->poll_events(); } -static BAN::ErrorOr> bananos_create_window(PlatformWindow* parent, WindowType type, WINDOW wid, int32_t x, int32_t y, uint32_t width, uint32_t height) +static BAN::ErrorOr> bananos_create_window(WindowType type, WINDOW wid, int32_t x, int32_t y, uint32_t width, uint32_t height) { - (void)parent; (void)type; - (void)x; - (void)y; auto window = TRY(BAN::UniqPtr::create()); @@ -70,6 +67,7 @@ static BAN::ErrorOr> bananos_create_window(Platform attributes.shown = true; attributes.title_bar = false; attributes.resizable = true; + attributes.alpha_channel = true; auto gui_window = TRY(LibGUI::Window::create(width, height, ""_sv, attributes)); auto* winp = gui_window.ptr(); @@ -132,18 +130,28 @@ static void bananos_request_resize(PlatformWindow* window, uint32_t width, uint3 banan_window.window->request_resize(width, height); } -static void bananos_invalidate(PlatformWindow* window, const uint32_t* pixels, uint32_t x, uint32_t y, uint32_t width, uint32_t height) +static void bananos_invalidate(PlatformWindow* window, const void* src_pixels, uint32_t src_pitch, uint32_t x, uint32_t y, uint32_t width, uint32_t height) { auto& banan_window = *static_cast(window); - const uint32_t win_width = banan_window.window->width(); + auto& texture = banan_window.window->texture(); + void* dst_pixels = &texture.pixels()[y * texture.width() + x]; + const uint32_t dst_pitch = texture.width() * sizeof(uint32_t); - auto* out_pixels = banan_window.window->texture().pixels().data(); for (uint32_t y_off = 0; y_off < height; y_off++) - for (uint32_t x_off = 0; x_off < width; x_off++) - out_pixels[(y + y_off) * win_width + (x + x_off)] = pixels[(y + y_off) * win_width + (x + x_off)]; + { + memcpy( + static_cast< uint8_t*>(dst_pixels) + y_off * dst_pitch, + static_cast(src_pixels) + y_off * src_pitch, + width * sizeof(uint32_t) + ); + } +} - banan_window.window->invalidate(x, y, width, height); +static void bananos_end_frame(PlatformWindow* window) +{ + auto& banan_window = *static_cast(window); + banan_window.window->invalidate(); } static void bananos_request_fullscreen(PlatformWindow* window, bool fullscreen) @@ -186,6 +194,8 @@ PlatformOps g_platform_ops = { .poll_events = bananos_poll_events, .create_window = bananos_create_window, .invalidate = bananos_invalidate, + .begin_frame = nullptr, + .end_frame = bananos_end_frame, .request_resize = bananos_request_resize, .request_reposition = nullptr, .request_fullscreen = bananos_request_fullscreen, diff --git a/xbanan/main.cpp b/xbanan/main.cpp index 099be6c..0a27928 100644 --- a/xbanan/main.cpp +++ b/xbanan/main.cpp @@ -629,6 +629,18 @@ int main() } } + for (auto& [_, object] : g_objects) + { + if (object->type != Object::Type::Window) + continue; + auto& window = object->object.get(); + if (!window.platform_window_invalidated) + continue; + if (g_platform_ops.end_frame) + g_platform_ops.end_frame(window.platform_window.ptr()); + window.platform_window_invalidated = false; + } + iterator_invalidated: for (auto& [_, thingy] : g_epoll_thingies) {