Compare commits

...

7 Commits

Author SHA1 Message Date
689494db63 LibGUI/WindowServer: Allow querying global cursor position 2026-06-23 23:31:17 +03:00
1287c8e335 LibGUI: Cleanup packet creation 2026-06-23 23:30:42 +03:00
763a742f6d WindowServer: Fix client fd leaks 2026-06-23 21:08:57 +03:00
4ad586552d LibGUI/WindowServer: Send window move events 2026-06-23 20:52:12 +03:00
8bc93069be Terminal: Fix foreground and background colors when inverted
I was not checking for inverted colors in a lot of places :P
2026-06-23 20:16:25 +03:00
160821869d ports: Add libX{composite,cursor,damage,inerama} ports 2026-06-23 15:28:25 +03:00
aa1b1e1af9 ports: Add butterscotch port 2026-06-22 21:25:04 +03:00
18 changed files with 440 additions and 75 deletions

26
ports/butterscotch/build.sh Executable file
View File

@@ -0,0 +1,26 @@
#!/bin/bash ../install.sh
NAME='butterscotch'
VERSION='git'
DOWNLOAD_URL="https://github.com/ButterscotchRunner/Butterscotch.git#b95f61c1aa84d9dd4a7b589b2a3331ab28dfa2ea"
DEPENDENCIES=('SDL2' 'openal-soft')
configure() {
cmake --fresh -B build -S . -G Ninja \
--toolchain="$BANAN_TOOLCHAIN_DIR/Toolchain.txt" \
-DCMAKE_INSTALL_PREFIX=/usr \
-DCMAKE_BUILD_TYPE=Release \
-DPLATFORM='desktop' \
-DAUDIO_BACKEND='openal' \
-DDESKTOP_BACKEND='sdl2' \
. || exit 1
}
build() {
cmake --build build || exit 1
}
install() {
mkdir -p "$DESTDIR/usr/bin" || exit 1
cp -vf build/butterscotch "$DESTDIR/usr/bin/" || exit 1
}

View File

@@ -0,0 +1,41 @@
From 1ae068333558eec65a11e575d3c08111efd85938 Mon Sep 17 00:00:00 2001
From: Oskari Alaranta <oskari.alaranta@bananymous.com>
Date: Mon, 22 Jun 2026 21:21:36 +0300
Subject: [PATCH] include alloca.h
---
src/runner.c | 4 ++++
vendor/stb/vorbis/stb_vorbis.c | 2 +-
2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/src/runner.c b/src/runner.c
index 411ccf5..24110c1 100644
--- a/src/runner.c
+++ b/src/runner.c
@@ -17,6 +17,10 @@
#include "gettime.h"
#include "stb_ds.h"
+#ifdef __banan_os__
+#include <alloca.h>
+#endif
+
// ===[ Runtime Layer Teardown Helpers ]===
void Runner_freeRuntimeLayer(RuntimeLayer* runtimeLayer) {
free(runtimeLayer->dynamicName);
diff --git a/vendor/stb/vorbis/stb_vorbis.c b/vendor/stb/vorbis/stb_vorbis.c
index 0af6406..d35822e 100644
--- a/vendor/stb/vorbis/stb_vorbis.c
+++ b/vendor/stb/vorbis/stb_vorbis.c
@@ -588,7 +588,7 @@ enum STBVorbisError
#if defined(_MSC_VER) || defined(__MINGW32__)
#include <malloc.h>
#endif
- #if defined(__linux__) || defined(__linux) || defined(__sun__) || defined(__EMSCRIPTEN__) || defined(__NEWLIB__)
+ #if defined(__linux__) || defined(__linux) || defined(__sun__) || defined(__EMSCRIPTEN__) || defined(__NEWLIB__) || defined(__banan_os__)
#include <alloca.h>
#endif
#else // STB_VORBIS_NO_CRT
--
2.54.0

View File

@@ -0,0 +1,25 @@
From 98fffc5330e51a0dbe25017653d46e15c185dc4b Mon Sep 17 00:00:00 2001
From: Oskari Alaranta <oskari.alaranta@bananymous.com>
Date: Mon, 22 Jun 2026 21:24:07 +0300
Subject: [PATCH] fix maybe used uninitialized error
---
src/desktop/backends/sdl2.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/desktop/backends/sdl2.c b/src/desktop/backends/sdl2.c
index 91029a6..34716f8 100644
--- a/src/desktop/backends/sdl2.c
+++ b/src/desktop/backends/sdl2.c
@@ -50,7 +50,7 @@ bool platformGetScaledWindowSize(int32_t* outW, int32_t* outH) {
static void platformGetWindowScale(float *scale_x, float *scale_y) {
if (!scale_x || !scale_y) return;
- int32_t draw_w, draw_h;
+ int32_t draw_w = 0, draw_h = 0;
int logical_w, logical_h;
platformGetWindowSize(&draw_w, &draw_h);
SDL_GetWindowSize(window, &logical_w, &logical_h);
--
2.54.0

11
ports/libXcomposite/build.sh Executable file
View File

@@ -0,0 +1,11 @@
#!/bin/bash ../install.sh
NAME='libXcomposite'
VERSION='0.4.7'
DOWNLOAD_URL="https://www.x.org/releases/individual/lib/libXcomposite-$VERSION.tar.xz#8bdf310967f484503fa51714cf97bff0723d9b673e0eecbf92b3f97c060c8ccb"
CONFIG_SUB=('config.sub')
DEPENDENCIES=('libX11' 'libXfixes')
CONFIGURE_OPTIONS=(
'--enable-shared=yes'
'--enable-static=no'
)

View File

@@ -0,0 +1,31 @@
diff -ruN libXcomposite-0.4.7/configure libXcomposite-0.4.7-banan_os/configure
--- libXcomposite-0.4.7/configure 2026-01-26 00:32:39.000000000 +0200
+++ libXcomposite-0.4.7-banan_os/configure 2026-05-23 02:11:49.423679807 +0300
@@ -6236,6 +6236,10 @@
lt_cv_deplibs_check_method=pass_all
;;
+banan_os*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
beos*)
lt_cv_deplibs_check_method=pass_all
;;
@@ -11771,6 +11775,16 @@
esac
;;
+banan_os*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ dynamic_linker="$host_os DynamicLoader.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
beos*)
library_names_spec='$libname$shared_ext'
dynamic_linker="$host_os ld.so"

11
ports/libXcursor/build.sh Executable file
View File

@@ -0,0 +1,11 @@
#!/bin/bash ../install.sh
NAME='libXcursor'
VERSION='1.2.3'
DOWNLOAD_URL="https://www.x.org/releases/individual/lib/libXcursor-$VERSION.tar.xz#fde9402dd4cfe79da71e2d96bb980afc5e6ff4f8a7d74c159e1966afb2b2c2c0"
CONFIG_SUB=('config.sub')
DEPENDENCIES=('libX11' 'libXrender' 'libXfixes')
CONFIGURE_OPTIONS=(
'--enable-shared=yes'
'--enable-static=no'
)

View File

@@ -0,0 +1,31 @@
diff -ruN libXcursor-1.2.3/configure libXcursor-1.2.3-banan_os/configure
--- libXcursor-1.2.3/configure 2024-11-06 01:15:13.000000000 +0200
+++ libXcursor-1.2.3-banan_os/configure 2026-03-25 16:39:14.759269796 +0200
@@ -6052,6 +6052,10 @@
lt_cv_deplibs_check_method=pass_all
;;
+banan_os*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
beos*)
lt_cv_deplibs_check_method=pass_all
;;
@@ -11388,6 +11392,16 @@
esac
;;
+banan_os*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ dynamic_linker="$host_os DynamicLoader.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
beos*)
library_names_spec='$libname$shared_ext'
dynamic_linker="$host_os ld.so"

11
ports/libXdamage/build.sh Executable file
View File

@@ -0,0 +1,11 @@
#!/bin/bash ../install.sh
NAME='libXdamage'
VERSION='1.1.7'
DOWNLOAD_URL="https://www.x.org/releases/individual/lib/libXdamage-$VERSION.tar.xz#127067f521d3ee467b97bcb145aeba1078e2454d448e8748eb984d5b397bde24"
CONFIG_SUB=('config.sub')
DEPENDENCIES=('libX11') # FIXME: check deps
CONFIGURE_OPTIONS=(
'--enable-shared=yes'
'--enable-static=no'
)

View File

@@ -0,0 +1,31 @@
diff -ruN libXdamage-1.1.7/configure libXdamage-1.1.7-banan_os/configure
--- libXdamage-1.1.7/configure 2026-01-26 01:03:29.000000000 +0200
+++ libXdamage-1.1.7-banan_os/configure 2026-05-23 02:22:11.429490232 +0300
@@ -6157,6 +6157,10 @@
lt_cv_deplibs_check_method=pass_all
;;
+banan_os*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
beos*)
lt_cv_deplibs_check_method=pass_all
;;
@@ -11692,6 +11696,16 @@
esac
;;
+banan_os*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ dynamic_linker="$host_os DynamicLoader.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
beos*)
library_names_spec='$libname$shared_ext'
dynamic_linker="$host_os ld.so"

11
ports/libXinerama/build.sh Executable file
View File

@@ -0,0 +1,11 @@
#!/bin/bash ../install.sh
NAME='libXinerama'
VERSION='1.1.6'
DOWNLOAD_URL="https://www.x.org/releases/individual/lib/libXinerama-$VERSION.tar.xz#d00fc1599c303dc5cbc122b8068bdc7405d6fcb19060f4597fc51bd3a8be51d7"
CONFIG_SUB=('config.sub')
DEPENDENCIES=('libX11' 'libXext')
CONFIGURE_OPTIONS=(
'--enable-shared=yes'
'--enable-static=no'
)

View File

@@ -0,0 +1,31 @@
diff -ruN libXinerama-1.1.6/configure libXinerama-1.1.6-banan_os/configure
--- libXinerama-1.1.6/configure 2026-01-26 01:40:12.000000000 +0200
+++ libXinerama-1.1.6-banan_os/configure 2026-03-25 16:26:39.166177404 +0200
@@ -6173,6 +6173,10 @@
lt_cv_deplibs_check_method=pass_all
;;
+banan_os*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
beos*)
lt_cv_deplibs_check_method=pass_all
;;
@@ -11707,6 +11711,16 @@
;;
esac
;;
+
+banan_os*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ dynamic_linker="$host_os DynamicLoader.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
beos*)
library_names_spec='$libname$shared_ext'

View File

@@ -63,22 +63,30 @@ namespace LibGUI
auto window = TRY(BAN::UniqPtr<Window>::create(server_fd, epoll_fd, attributes));
WindowPacket::WindowCreate create_packet;
create_packet.width = width;
create_packet.height = height;
create_packet.attributes = attributes;
WindowPacket::WindowCreate create_packet {
.width = width,
.height = height,
.attributes = attributes,
.title = {},
};
TRY(create_packet.title.append(title));
window->send_packet(create_packet, __FUNCTION__);
bool resized = false;
int32_t x, y;
bool resized { false }, moved { false };
window->set_resize_window_event_callback([&]() { resized = true; });
while (!resized)
window->set_window_move_event_callback([&](auto event) { x = event.x; y = event.y; moved = true; });
while (!resized || !moved)
{
// FIXME: timeout?
window->wait_events();
window->poll_events();
}
window->set_resize_window_event_callback({});
window->set_window_move_event_callback({});
// hack to resend move event :^)
window->set_position(x, y);
server_closer.disable();
epoll_closer.disable();
@@ -163,40 +171,46 @@ namespace LibGUI
);
}
WindowPacket::WindowInvalidate packet;
packet.x = x;
packet.y = y;
packet.width = width;
packet.height = height;
const WindowPacket::WindowInvalidate packet {
.x = static_cast<uint32_t>(x),
.y = static_cast<uint32_t>(y),
.width = width,
.height = height,
};
send_packet(packet, __FUNCTION__);
}
void Window::set_mouse_relative(bool enabled)
{
WindowPacket::WindowSetMouseRelative packet;
packet.enabled = enabled;
const WindowPacket::WindowSetMouseRelative packet {
.enabled = enabled,
};
send_packet(packet, __FUNCTION__);
}
void Window::set_fullscreen(bool fullscreen)
{
WindowPacket::WindowSetFullscreen packet;
packet.fullscreen = fullscreen;
const WindowPacket::WindowSetFullscreen packet {
.fullscreen = fullscreen,
};
send_packet(packet, __FUNCTION__);
}
void Window::set_title(BAN::StringView title)
{
WindowPacket::WindowSetTitle packet;
WindowPacket::WindowSetTitle packet {
.title = {},
};
MUST(packet.title.append(title));
send_packet(packet, __FUNCTION__);
}
void Window::set_position(int32_t x, int32_t y)
{
WindowPacket::WindowSetPosition packet;
packet.x = x;
packet.y = y;
const WindowPacket::WindowSetPosition packet {
.x = x,
.y = y,
};
send_packet(packet, __FUNCTION__);
}
@@ -211,11 +225,14 @@ namespace LibGUI
void Window::set_cursor(uint32_t width, uint32_t height, BAN::Span<const uint32_t> pixels, int32_t origin_x, int32_t origin_y)
{
WindowPacket::WindowSetCursor packet;
packet.width = width;
packet.height = height;
packet.origin_x = origin_x;
packet.origin_y = origin_y;
// TODO: no need to copy here
WindowPacket::WindowSetCursor packet {
.width = width,
.height = height,
.origin_x = origin_x,
.origin_y = origin_y,
.pixels = {},
};
MUST(packet.pixels.resize(pixels.size()));
for (size_t i = 0; i < packet.pixels.size(); i++)
packet.pixels[i] = pixels[i];
@@ -224,17 +241,19 @@ namespace LibGUI
void Window::set_min_size(uint32_t width, uint32_t height)
{
WindowPacket::WindowSetMinSize packet;
packet.width = width;
packet.height = height;
const WindowPacket::WindowSetMinSize packet {
.width = width,
.height = height,
};
send_packet(packet, __FUNCTION__);
}
void Window::set_max_size(uint32_t width, uint32_t height)
{
WindowPacket::WindowSetMaxSize packet;
packet.width = width;
packet.height = height;
const WindowPacket::WindowSetMaxSize packet {
.width = width,
.height = height,
};
send_packet(packet, __FUNCTION__);
}
@@ -248,9 +267,16 @@ namespace LibGUI
void Window::request_resize(uint32_t width, uint32_t height)
{
WindowPacket::WindowSetSize packet;
packet.width = width;
packet.height = height;
const WindowPacket::WindowSetSize packet {
.width = width,
.height = height,
};
send_packet(packet, __FUNCTION__);
}
void Window::query_cursor_position()
{
const WindowPacket::QueryPointer packet {};
send_packet(packet, __FUNCTION__);
}
@@ -365,6 +391,10 @@ namespace LibGUI
if (m_window_fullscreen_event_callback)
m_window_fullscreen_event_callback(TRY_OR_BREAK(EventPacket::WindowFullscreenEvent::deserialize(packet_span)).event);
break;
case PacketType::WindowMoveEvent:
if (m_window_move_event_callback)
m_window_move_event_callback(TRY_OR_BREAK(EventPacket::WindowMoveEvent::deserialize(packet_span)).event);
break;
case PacketType::KeyEvent:
if (m_key_event_callback)
m_key_event_callback(TRY_OR_BREAK(EventPacket::KeyEvent::deserialize(packet_span)).event);
@@ -395,6 +425,10 @@ namespace LibGUI
if (m_mouse_scroll_event_callback)
m_mouse_scroll_event_callback(TRY_OR_BREAK(EventPacket::MouseScrollEvent::deserialize(packet_span)).event);
break;
case PacketType::QueryPointerEvent:
if (m_query_pointer_event_callback)
m_query_pointer_event_callback(TRY_OR_BREAK(EventPacket::QueryPointerEvent::deserialize(packet_span)).event);
break;
#undef TRY_OR_BREAK
default:
dprintln("unhandled packet type: {}", static_cast<uint32_t>(header.type));

View File

@@ -206,10 +206,14 @@ namespace LibGUI
WindowShownEvent,
WindowFocusEvent,
WindowFullscreenEvent,
WindowMoveEvent,
KeyEvent,
MouseButtonEvent,
MouseMoveEvent,
MouseScrollEvent,
QueryPointer,
QueryPointerEvent,
};
struct PacketHeader
@@ -302,6 +306,10 @@ namespace LibGUI
BAN::Vector<uint32_t>, pixels
);
DEFINE_PACKET(
QueryPointer
);
}
namespace EventPacket
@@ -346,6 +354,15 @@ namespace LibGUI
event_t, event
);
DEFINE_PACKET_EXTRA(
WindowMoveEvent,
struct event_t {
int32_t x;
int32_t y;
},
event_t, event
);
DEFINE_PACKET_EXTRA(
KeyEvent,
using event_t = LibInput::KeyEvent,
@@ -380,6 +397,15 @@ namespace LibGUI
event_t, event
);
DEFINE_PACKET_EXTRA(
QueryPointerEvent,
struct event_t {
int32_t x;
int32_t y;
},
event_t, event
);
}
}

View File

@@ -63,6 +63,8 @@ namespace LibGUI
// actual resize is only done after resize callback is called
void request_resize(uint32_t width, uint32_t height);
void query_cursor_position();
uint32_t width() const { return m_width; }
uint32_t height() const { return m_height; }
@@ -79,6 +81,8 @@ namespace LibGUI
void set_window_shown_event_callback(BAN::Function<void(EventPacket::WindowShownEvent::event_t)> callback) { m_window_shown_event_callback = callback; }
void set_window_focus_event_callback(BAN::Function<void(EventPacket::WindowFocusEvent::event_t)> callback) { m_window_focus_event_callback = callback; }
void set_window_fullscreen_event_callback(BAN::Function<void(EventPacket::WindowFullscreenEvent::event_t)> callback) { m_window_fullscreen_event_callback = callback; }
void set_window_move_event_callback(BAN::Function<void(EventPacket::WindowMoveEvent::event_t)> callback) { m_window_move_event_callback = callback; }
void set_query_pointer_event_callback(BAN::Function<void(EventPacket::QueryPointerEvent::event_t)> callback) { m_query_pointer_event_callback = callback; }
int server_fd() const { return m_server_fd; }
@@ -118,10 +122,12 @@ namespace LibGUI
BAN::Function<void(EventPacket::WindowShownEvent::event_t)> m_window_shown_event_callback;
BAN::Function<void(EventPacket::WindowFocusEvent::event_t)> m_window_focus_event_callback;
BAN::Function<void(EventPacket::WindowFullscreenEvent::event_t)> m_window_fullscreen_event_callback;
BAN::Function<void(EventPacket::WindowMoveEvent::event_t)> m_window_move_event_callback;
BAN::Function<void(EventPacket::KeyEvent::event_t)> m_key_event_callback;
BAN::Function<void(EventPacket::MouseButtonEvent::event_t)> m_mouse_button_event_callback;
BAN::Function<void(EventPacket::MouseMoveEvent::event_t)> m_mouse_move_event_callback;
BAN::Function<void(EventPacket::MouseScrollEvent::event_t)> m_mouse_scroll_event_callback;
BAN::Function<void(EventPacket::QueryPointerEvent::event_t)> m_query_pointer_event_callback;
size_t m_in_buffer_size { 0 };
BAN::Array<uint8_t, 64 * 1024> m_in_buffer;

View File

@@ -651,6 +651,9 @@ Rectangle Terminal::handle_csi(char ch)
auto& texture = m_window->texture();
const auto fg_color = m_colors_inverted ? m_bg_color : m_fg_color;
const auto bg_color = m_colors_inverted ? m_fg_color : m_bg_color;
switch (m_csi_info.param)
{
case 0:
@@ -706,8 +709,8 @@ Rectangle Terminal::handle_csi(char ch)
{
m_cells[i] = {
.codepoint = 0,
.fg_color = m_fg_color,
.bg_color = m_bg_color,
.fg_color = fg_color,
.bg_color = bg_color,
.bold = m_is_bold,
};
}
@@ -730,8 +733,8 @@ Rectangle Terminal::handle_csi(char ch)
{
m_cells[i] = {
.codepoint = 0,
.fg_color = m_fg_color,
.bg_color = m_bg_color,
.fg_color = fg_color,
.bg_color = bg_color,
.bold = m_is_bold,
};
}
@@ -754,8 +757,8 @@ Rectangle Terminal::handle_csi(char ch)
{
m_cells[i] = {
.codepoint = 0,
.fg_color = m_fg_color,
.bg_color = m_bg_color,
.fg_color = fg_color,
.bg_color = bg_color,
.bold = m_is_bold,
};
}
@@ -770,7 +773,7 @@ Rectangle Terminal::handle_csi(char ch)
for (size_t i = 0; i < rect_count; i++)
{
texture.fill_rect(rects[i].x, rects[i].y, rects[i].width, rects[i].height, m_bg_color);
texture.fill_rect(rects[i].x, rects[i].y, rects[i].width, rects[i].height, bg_color);
should_invalidate = should_invalidate.get_bounding_box(rects[i]);
}
@@ -785,8 +788,8 @@ Rectangle Terminal::handle_csi(char ch)
for (size_t i = s_col; i <= e_col; i++)
m_cells[m_cursor.y * cols() + i] = {
.codepoint = ' ',
.fg_color = m_fg_color,
.bg_color = m_bg_color,
.fg_color = fg_color,
.bg_color = bg_color,
.bold = m_is_bold,
};
@@ -796,7 +799,7 @@ Rectangle Terminal::handle_csi(char ch)
rect.width = (m_csi_info.fields[0] == 1) ? m_cursor.x * m_font.width() : m_window->width() - rect.x;
rect.height = m_font.height();
texture.fill_rect(rect.x, rect.y, rect.width, rect.height, m_bg_color);
texture.fill_rect(rect.x, rect.y, rect.width, rect.height, bg_color);
should_invalidate = rect;
break;
@@ -814,13 +817,13 @@ Rectangle Terminal::handle_csi(char ch)
for (size_t col = 0; col < cols(); col++)
m_cells[row * cols() + col] = {
.codepoint = ' ',
.fg_color = m_fg_color,
.bg_color = m_bg_color,
.fg_color = fg_color,
.bg_color = bg_color,
.bold = m_is_bold,
};
texture.copy_horizontal_slice(dst_y, src_y, m_window->height() - dst_y);
texture.fill_rect(0, src_y, m_window->width(), count * m_font.height(), m_bg_color);
texture.fill_rect(0, src_y, m_window->width(), count * m_font.height(), bg_color);
should_invalidate = {
0,
src_y,
@@ -843,13 +846,13 @@ Rectangle Terminal::handle_csi(char ch)
for (size_t col = 0; col < cols(); col++)
m_cells[row * cols() + col] = {
.codepoint = ' ',
.fg_color = m_fg_color,
.bg_color = m_bg_color,
.fg_color = fg_color,
.bg_color = bg_color,
.bold = m_is_bold,
};
texture.copy_horizontal_slice(dst_y, src_y, m_window->height() - dst_y);
texture.fill_rect(0, m_window->height() - count * m_font.height(), m_window->width(), count * m_font.height(), m_bg_color);
texture.fill_rect(0, m_window->height() - count * m_font.height(), m_window->width(), count * m_font.height(), bg_color);
should_invalidate = {
0,
src_y,
@@ -871,13 +874,13 @@ Rectangle Terminal::handle_csi(char ch)
for (size_t i = m_cursor.x + count; i < cols(); i++)
m_cells[m_cursor.y * cols() + i] = {
.codepoint = ' ',
.fg_color = m_fg_color,
.bg_color = m_bg_color,
.fg_color = fg_color,
.bg_color = bg_color,
.bold = m_is_bold,
};
texture.copy_rect(dst_x, y, src_x, y, m_window->width() - src_x, m_font.height());
texture.fill_rect(m_window->width() - count * m_font.width(), y, count * m_font.width(), m_font.height(), m_bg_color);
texture.fill_rect(m_window->width() - count * m_font.width(), y, count * m_font.width(), m_font.height(), bg_color);
should_invalidate = {
dst_x,
y,
@@ -899,13 +902,13 @@ Rectangle Terminal::handle_csi(char ch)
for (size_t i = m_cursor.x; i < m_cursor.x + count; i++)
m_cells[m_cursor.y * cols() + i] = {
.codepoint = ' ',
.fg_color = m_fg_color,
.bg_color = m_bg_color,
.fg_color = fg_color,
.bg_color = bg_color,
.bold = m_is_bold,
};
texture.copy_rect(dst_x, y, src_x, y, m_window->width() - dst_x, m_font.height());
texture.fill_rect(src_x, y, count * m_font.width(), m_font.height(), m_bg_color);
texture.fill_rect(src_x, y, count * m_font.width(), m_font.height(), bg_color);
should_invalidate = {
src_x,
y,

View File

@@ -40,6 +40,19 @@ BAN::ErrorOr<void> WindowServer::set_background_image(BAN::UniqPtr<LibImage::Ima
return {};
}
void WindowServer::on_query_pointer(int fd, const LibGUI::WindowPacket::QueryPointer&)
{
const LibGUI::EventPacket::QueryPointerEvent event_packet { .event = {
.x = m_cursor.x,
.y = m_cursor.y,
}};
if (auto ret = append_serialized_packet(event_packet, fd); ret.is_error())
{
dwarnln("could not respond to query pointer request: {}", ret.error());
return;
}
}
void WindowServer::on_window_create(int fd, const LibGUI::WindowPacket::WindowCreate& packet)
{
for (auto& window : m_client_windows)
@@ -75,10 +88,11 @@ void WindowServer::on_window_create(int fd, const LibGUI::WindowPacket::WindowCr
}
window->set_attributes(packet.attributes);
window->set_position({
static_cast<int32_t>((m_framebuffer.width - window->client_width()) / 2),
static_cast<int32_t>((m_framebuffer.height - window->client_height()) / 2),
});
move_window(
window,
(m_framebuffer.width - window->client_width()) / 2,
(m_framebuffer.height - window->client_height()) / 2
);
const LibGUI::EventPacket::ResizeWindowEvent event_packet {
.width = static_cast<uint32_t>(window->client_width()),
@@ -151,10 +165,7 @@ void WindowServer::on_window_set_position(int fd, const LibGUI::WindowPacket::Wi
}
const auto old_client_area = target_window->full_area();
target_window->set_position({
.x = packet.x,
.y = packet.y,
});
move_window(target_window, packet.x, packet.y);
if (!target_window->get_attributes().shown)
return;
@@ -186,7 +197,7 @@ void WindowServer::on_window_set_attributes(int fd, const LibGUI::WindowPacket::
{
if (!resize_window(m_focused_window, m_non_full_screen_rect.width(), m_non_full_screen_rect.height()))
return;
m_focused_window->set_position({ m_non_full_screen_rect.min_x, m_non_full_screen_rect.min_y });
move_window(m_focused_window, m_non_full_screen_rect.min_x, m_non_full_screen_rect.min_y);
}
m_focused_window = nullptr;
@@ -310,7 +321,7 @@ void WindowServer::on_window_set_fullscreen(int fd, const LibGUI::WindowPacket::
{
if (!resize_window(m_focused_window, m_non_full_screen_rect.width(), m_non_full_screen_rect.height()))
return;
m_focused_window->set_position({ m_non_full_screen_rect.min_x, m_non_full_screen_rect.min_y });
move_window(m_focused_window, m_non_full_screen_rect.min_x, m_non_full_screen_rect.min_y);
}
const LibGUI::EventPacket::WindowFullscreenEvent event_packet { .event = {
@@ -344,7 +355,7 @@ void WindowServer::on_window_set_fullscreen(int fd, const LibGUI::WindowPacket::
const auto old_area = target_window->client_area();
if (!resize_window(target_window, m_framebuffer.width, m_framebuffer.height))
return;
target_window->set_position({ 0, 0 });
move_window(target_window, 0, 0);
m_non_full_screen_rect = old_area;
}
@@ -510,7 +521,7 @@ void WindowServer::on_key_event(LibInput::KeyEvent event)
{
if (!resize_window(m_focused_window, m_non_full_screen_rect.width(), m_non_full_screen_rect.height()))
return;
m_focused_window->set_position({ m_non_full_screen_rect.min_x, m_non_full_screen_rect.min_y });
move_window(m_focused_window, m_non_full_screen_rect.min_x, m_non_full_screen_rect.min_y);
}
m_state = State::Normal;
}
@@ -521,7 +532,7 @@ void WindowServer::on_key_event(LibInput::KeyEvent event)
const auto old_area = m_focused_window->client_area();
if (!resize_window(m_focused_window, m_framebuffer.width, m_framebuffer.height))
return;
m_focused_window->set_position({ 0, 0 });
move_window(m_focused_window, 0, 0);
m_non_full_screen_rect = old_area;
}
m_state = State::Fullscreen;
@@ -656,7 +667,7 @@ void WindowServer::on_mouse_button(LibInput::MouseButtonEvent event)
dwarnln("could not resize client window {}", ret.error());
return;
}
m_focused_window->set_position({ resize_area.min_x, resize_area.min_y + m_focused_window->title_bar_height() });
move_window(m_focused_window, resize_area.min_x, resize_area.min_y + m_focused_window->title_bar_height());
const LibGUI::EventPacket::ResizeWindowEvent event_packet {
.width = static_cast<uint32_t>(m_focused_window->client_width()),
@@ -723,10 +734,11 @@ void WindowServer::on_mouse_move_impl(int32_t new_x, int32_t new_y)
case State::Moving:
{
const auto old_window_area = m_focused_window->full_area();
m_focused_window->set_position({
move_window(
m_focused_window,
m_focused_window->client_x() + event.rel_x,
m_focused_window->client_y() + event.rel_y,
});
m_focused_window->client_y() + event.rel_y
);
add_damaged_area(old_window_area);
add_damaged_area(m_focused_window->full_area());
break;
@@ -1579,11 +1591,14 @@ void WindowServer::sync()
{
static int32_t dir_x = 7;
static int32_t dir_y = 4;
auto old_window = m_focused_window->full_area();
m_focused_window->set_position({
move_window(
m_focused_window,
m_focused_window->client_x() + dir_x,
m_focused_window->client_y() + dir_y,
});
m_focused_window->client_y() + dir_y
);
add_damaged_area(old_window);
add_damaged_area(m_focused_window->full_area());
@@ -1717,6 +1732,19 @@ bool WindowServer::resize_window(BAN::RefPtr<Window> window, uint32_t width, uin
return true;
}
void WindowServer::move_window(BAN::RefPtr<Window> window, int32_t x, int32_t y)
{
window->set_position({ x, y });
const LibGUI::EventPacket::WindowMoveEvent event_packet {
.event = {
.x = window->client_x(),
.y = window->client_y(),
},
};
(void)append_serialized_packet(event_packet, window->client_fd());
}
BAN::ErrorOr<void> WindowServer::add_client_fd(int fd)
{
TRY(m_client_data.emplace(fd));

View File

@@ -31,6 +31,8 @@ public:
BAN::ErrorOr<void> set_background_image(BAN::UniqPtr<LibImage::Image>);
void on_query_pointer(int fd, const LibGUI::WindowPacket::QueryPointer&);
void on_window_create(int fd, const LibGUI::WindowPacket::WindowCreate&);
void on_window_invalidate(int fd, const LibGUI::WindowPacket::WindowInvalidate&);
void on_window_set_position(int fd, const LibGUI::WindowPacket::WindowSetPosition&);
@@ -71,6 +73,7 @@ private:
void add_damaged_area_impl(Rectangle area);
bool resize_window(BAN::RefPtr<Window> window, uint32_t width, uint32_t height);
void move_window(BAN::RefPtr<Window> window, int32_t x, int32_t y);
BAN::RefPtr<Window> find_window_with_fd(int fd) const;
BAN::RefPtr<Window> find_hovered_window() const;

View File

@@ -380,6 +380,7 @@ int main()
{
epoll_ctl(g_epoll_fd, EPOLL_CTL_DEL, client_fd, nullptr);
window_server.remove_client_fd(client_fd);
close(client_fd);
continue;
}
@@ -395,6 +396,7 @@ int main()
dwarnln("send: {}", strerror(errno));
epoll_ctl(g_epoll_fd, EPOLL_CTL_DEL, client_fd, nullptr);
window_server.remove_client_fd(client_fd);
close(client_fd);
break;
}
@@ -434,6 +436,7 @@ int main()
dwarnln("recv: {}", strerror(errno));
epoll_ctl(g_epoll_fd, EPOLL_CTL_DEL, client_fd, nullptr);
window_server.remove_client_fd(client_fd);
close(client_fd);
break;
}
if (nrecv > 0)
@@ -469,6 +472,7 @@ int main()
WINDOW_PACKET_CASE(WindowSetFullscreen, on_window_set_fullscreen);
WINDOW_PACKET_CASE(WindowSetTitle, on_window_set_title);
WINDOW_PACKET_CASE(WindowSetCursor, on_window_set_cursor);
WINDOW_PACKET_CASE(QueryPointer, on_query_pointer);
#undef WINDOW_PACKET_CASE
default:
dprintln("unhandled packet type: {}", static_cast<uint32_t>(header.type));
@@ -494,6 +498,7 @@ int main()
dwarnln("client tried to send a {} byte packet", header.size);
epoll_ctl(g_epoll_fd, EPOLL_CTL_DEL, client_fd, nullptr);
window_server.remove_client_fd(client_fd);
close(client_fd);
break;
}
}