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

View File

@@ -206,10 +206,14 @@ namespace LibGUI
WindowShownEvent, WindowShownEvent,
WindowFocusEvent, WindowFocusEvent,
WindowFullscreenEvent, WindowFullscreenEvent,
WindowMoveEvent,
KeyEvent, KeyEvent,
MouseButtonEvent, MouseButtonEvent,
MouseMoveEvent, MouseMoveEvent,
MouseScrollEvent, MouseScrollEvent,
QueryPointer,
QueryPointerEvent,
}; };
struct PacketHeader struct PacketHeader
@@ -302,6 +306,10 @@ namespace LibGUI
BAN::Vector<uint32_t>, pixels BAN::Vector<uint32_t>, pixels
); );
DEFINE_PACKET(
QueryPointer
);
} }
namespace EventPacket namespace EventPacket
@@ -346,6 +354,15 @@ namespace LibGUI
event_t, event event_t, event
); );
DEFINE_PACKET_EXTRA(
WindowMoveEvent,
struct event_t {
int32_t x;
int32_t y;
},
event_t, event
);
DEFINE_PACKET_EXTRA( DEFINE_PACKET_EXTRA(
KeyEvent, KeyEvent,
using event_t = LibInput::KeyEvent, using event_t = LibInput::KeyEvent,
@@ -380,6 +397,15 @@ namespace LibGUI
event_t, event 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 // actual resize is only done after resize callback is called
void request_resize(uint32_t width, uint32_t height); void request_resize(uint32_t width, uint32_t height);
void query_cursor_position();
uint32_t width() const { return m_width; } uint32_t width() const { return m_width; }
uint32_t height() const { return m_height; } 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_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_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_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; } 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::WindowShownEvent::event_t)> m_window_shown_event_callback;
BAN::Function<void(EventPacket::WindowFocusEvent::event_t)> m_window_focus_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::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::KeyEvent::event_t)> m_key_event_callback;
BAN::Function<void(EventPacket::MouseButtonEvent::event_t)> m_mouse_button_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::MouseMoveEvent::event_t)> m_mouse_move_event_callback;
BAN::Function<void(EventPacket::MouseScrollEvent::event_t)> m_mouse_scroll_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 }; size_t m_in_buffer_size { 0 };
BAN::Array<uint8_t, 64 * 1024> m_in_buffer; 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(); 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) switch (m_csi_info.param)
{ {
case 0: case 0:
@@ -706,8 +709,8 @@ Rectangle Terminal::handle_csi(char ch)
{ {
m_cells[i] = { m_cells[i] = {
.codepoint = 0, .codepoint = 0,
.fg_color = m_fg_color, .fg_color = fg_color,
.bg_color = m_bg_color, .bg_color = bg_color,
.bold = m_is_bold, .bold = m_is_bold,
}; };
} }
@@ -730,8 +733,8 @@ Rectangle Terminal::handle_csi(char ch)
{ {
m_cells[i] = { m_cells[i] = {
.codepoint = 0, .codepoint = 0,
.fg_color = m_fg_color, .fg_color = fg_color,
.bg_color = m_bg_color, .bg_color = bg_color,
.bold = m_is_bold, .bold = m_is_bold,
}; };
} }
@@ -754,8 +757,8 @@ Rectangle Terminal::handle_csi(char ch)
{ {
m_cells[i] = { m_cells[i] = {
.codepoint = 0, .codepoint = 0,
.fg_color = m_fg_color, .fg_color = fg_color,
.bg_color = m_bg_color, .bg_color = bg_color,
.bold = m_is_bold, .bold = m_is_bold,
}; };
} }
@@ -770,7 +773,7 @@ Rectangle Terminal::handle_csi(char ch)
for (size_t i = 0; i < rect_count; i++) 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]); 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++) for (size_t i = s_col; i <= e_col; i++)
m_cells[m_cursor.y * cols() + i] = { m_cells[m_cursor.y * cols() + i] = {
.codepoint = ' ', .codepoint = ' ',
.fg_color = m_fg_color, .fg_color = fg_color,
.bg_color = m_bg_color, .bg_color = bg_color,
.bold = m_is_bold, .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.width = (m_csi_info.fields[0] == 1) ? m_cursor.x * m_font.width() : m_window->width() - rect.x;
rect.height = m_font.height(); 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; should_invalidate = rect;
break; break;
@@ -814,13 +817,13 @@ Rectangle Terminal::handle_csi(char ch)
for (size_t col = 0; col < cols(); col++) for (size_t col = 0; col < cols(); col++)
m_cells[row * cols() + col] = { m_cells[row * cols() + col] = {
.codepoint = ' ', .codepoint = ' ',
.fg_color = m_fg_color, .fg_color = fg_color,
.bg_color = m_bg_color, .bg_color = bg_color,
.bold = m_is_bold, .bold = m_is_bold,
}; };
texture.copy_horizontal_slice(dst_y, src_y, m_window->height() - dst_y); 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 = { should_invalidate = {
0, 0,
src_y, src_y,
@@ -843,13 +846,13 @@ Rectangle Terminal::handle_csi(char ch)
for (size_t col = 0; col < cols(); col++) for (size_t col = 0; col < cols(); col++)
m_cells[row * cols() + col] = { m_cells[row * cols() + col] = {
.codepoint = ' ', .codepoint = ' ',
.fg_color = m_fg_color, .fg_color = fg_color,
.bg_color = m_bg_color, .bg_color = bg_color,
.bold = m_is_bold, .bold = m_is_bold,
}; };
texture.copy_horizontal_slice(dst_y, src_y, m_window->height() - dst_y); 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 = { should_invalidate = {
0, 0,
src_y, src_y,
@@ -871,13 +874,13 @@ Rectangle Terminal::handle_csi(char ch)
for (size_t i = m_cursor.x + count; i < cols(); i++) for (size_t i = m_cursor.x + count; i < cols(); i++)
m_cells[m_cursor.y * cols() + i] = { m_cells[m_cursor.y * cols() + i] = {
.codepoint = ' ', .codepoint = ' ',
.fg_color = m_fg_color, .fg_color = fg_color,
.bg_color = m_bg_color, .bg_color = bg_color,
.bold = m_is_bold, .bold = m_is_bold,
}; };
texture.copy_rect(dst_x, y, src_x, y, m_window->width() - src_x, m_font.height()); 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 = { should_invalidate = {
dst_x, dst_x,
y, y,
@@ -899,13 +902,13 @@ Rectangle Terminal::handle_csi(char ch)
for (size_t i = m_cursor.x; i < m_cursor.x + count; i++) for (size_t i = m_cursor.x; i < m_cursor.x + count; i++)
m_cells[m_cursor.y * cols() + i] = { m_cells[m_cursor.y * cols() + i] = {
.codepoint = ' ', .codepoint = ' ',
.fg_color = m_fg_color, .fg_color = fg_color,
.bg_color = m_bg_color, .bg_color = bg_color,
.bold = m_is_bold, .bold = m_is_bold,
}; };
texture.copy_rect(dst_x, y, src_x, y, m_window->width() - dst_x, m_font.height()); 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 = { should_invalidate = {
src_x, src_x,
y, y,

View File

@@ -40,6 +40,19 @@ BAN::ErrorOr<void> WindowServer::set_background_image(BAN::UniqPtr<LibImage::Ima
return {}; 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) void WindowServer::on_window_create(int fd, const LibGUI::WindowPacket::WindowCreate& packet)
{ {
for (auto& window : m_client_windows) 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_attributes(packet.attributes);
window->set_position({ move_window(
static_cast<int32_t>((m_framebuffer.width - window->client_width()) / 2), window,
static_cast<int32_t>((m_framebuffer.height - window->client_height()) / 2), (m_framebuffer.width - window->client_width()) / 2,
}); (m_framebuffer.height - window->client_height()) / 2
);
const LibGUI::EventPacket::ResizeWindowEvent event_packet { const LibGUI::EventPacket::ResizeWindowEvent event_packet {
.width = static_cast<uint32_t>(window->client_width()), .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(); const auto old_client_area = target_window->full_area();
target_window->set_position({ move_window(target_window, packet.x, packet.y);
.x = packet.x,
.y = packet.y,
});
if (!target_window->get_attributes().shown) if (!target_window->get_attributes().shown)
return; 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())) if (!resize_window(m_focused_window, m_non_full_screen_rect.width(), m_non_full_screen_rect.height()))
return; 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; 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())) if (!resize_window(m_focused_window, m_non_full_screen_rect.width(), m_non_full_screen_rect.height()))
return; 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 = { 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(); const auto old_area = target_window->client_area();
if (!resize_window(target_window, m_framebuffer.width, m_framebuffer.height)) if (!resize_window(target_window, m_framebuffer.width, m_framebuffer.height))
return; return;
target_window->set_position({ 0, 0 }); move_window(target_window, 0, 0);
m_non_full_screen_rect = old_area; 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())) if (!resize_window(m_focused_window, m_non_full_screen_rect.width(), m_non_full_screen_rect.height()))
return; 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; 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(); const auto old_area = m_focused_window->client_area();
if (!resize_window(m_focused_window, m_framebuffer.width, m_framebuffer.height)) if (!resize_window(m_focused_window, m_framebuffer.width, m_framebuffer.height))
return; return;
m_focused_window->set_position({ 0, 0 }); move_window(m_focused_window, 0, 0);
m_non_full_screen_rect = old_area; m_non_full_screen_rect = old_area;
} }
m_state = State::Fullscreen; m_state = State::Fullscreen;
@@ -656,7 +667,7 @@ void WindowServer::on_mouse_button(LibInput::MouseButtonEvent event)
dwarnln("could not resize client window {}", ret.error()); dwarnln("could not resize client window {}", ret.error());
return; 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 { const LibGUI::EventPacket::ResizeWindowEvent event_packet {
.width = static_cast<uint32_t>(m_focused_window->client_width()), .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: case State::Moving:
{ {
const auto old_window_area = m_focused_window->full_area(); 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_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(old_window_area);
add_damaged_area(m_focused_window->full_area()); add_damaged_area(m_focused_window->full_area());
break; break;
@@ -1579,11 +1591,14 @@ void WindowServer::sync()
{ {
static int32_t dir_x = 7; static int32_t dir_x = 7;
static int32_t dir_y = 4; static int32_t dir_y = 4;
auto old_window = m_focused_window->full_area(); 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_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(old_window);
add_damaged_area(m_focused_window->full_area()); 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; 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) BAN::ErrorOr<void> WindowServer::add_client_fd(int fd)
{ {
TRY(m_client_data.emplace(fd)); TRY(m_client_data.emplace(fd));

View File

@@ -31,6 +31,8 @@ public:
BAN::ErrorOr<void> set_background_image(BAN::UniqPtr<LibImage::Image>); 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_create(int fd, const LibGUI::WindowPacket::WindowCreate&);
void on_window_invalidate(int fd, const LibGUI::WindowPacket::WindowInvalidate&); void on_window_invalidate(int fd, const LibGUI::WindowPacket::WindowInvalidate&);
void on_window_set_position(int fd, const LibGUI::WindowPacket::WindowSetPosition&); void on_window_set_position(int fd, const LibGUI::WindowPacket::WindowSetPosition&);
@@ -71,6 +73,7 @@ private:
void add_damaged_area_impl(Rectangle area); void add_damaged_area_impl(Rectangle area);
bool resize_window(BAN::RefPtr<Window> window, uint32_t width, uint32_t height); 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_window_with_fd(int fd) const;
BAN::RefPtr<Window> find_hovered_window() 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); epoll_ctl(g_epoll_fd, EPOLL_CTL_DEL, client_fd, nullptr);
window_server.remove_client_fd(client_fd); window_server.remove_client_fd(client_fd);
close(client_fd);
continue; continue;
} }
@@ -395,6 +396,7 @@ int main()
dwarnln("send: {}", strerror(errno)); dwarnln("send: {}", strerror(errno));
epoll_ctl(g_epoll_fd, EPOLL_CTL_DEL, client_fd, nullptr); epoll_ctl(g_epoll_fd, EPOLL_CTL_DEL, client_fd, nullptr);
window_server.remove_client_fd(client_fd); window_server.remove_client_fd(client_fd);
close(client_fd);
break; break;
} }
@@ -434,6 +436,7 @@ int main()
dwarnln("recv: {}", strerror(errno)); dwarnln("recv: {}", strerror(errno));
epoll_ctl(g_epoll_fd, EPOLL_CTL_DEL, client_fd, nullptr); epoll_ctl(g_epoll_fd, EPOLL_CTL_DEL, client_fd, nullptr);
window_server.remove_client_fd(client_fd); window_server.remove_client_fd(client_fd);
close(client_fd);
break; break;
} }
if (nrecv > 0) if (nrecv > 0)
@@ -469,6 +472,7 @@ int main()
WINDOW_PACKET_CASE(WindowSetFullscreen, on_window_set_fullscreen); WINDOW_PACKET_CASE(WindowSetFullscreen, on_window_set_fullscreen);
WINDOW_PACKET_CASE(WindowSetTitle, on_window_set_title); WINDOW_PACKET_CASE(WindowSetTitle, on_window_set_title);
WINDOW_PACKET_CASE(WindowSetCursor, on_window_set_cursor); WINDOW_PACKET_CASE(WindowSetCursor, on_window_set_cursor);
WINDOW_PACKET_CASE(QueryPointer, on_query_pointer);
#undef WINDOW_PACKET_CASE #undef WINDOW_PACKET_CASE
default: default:
dprintln("unhandled packet type: {}", static_cast<uint32_t>(header.type)); 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); dwarnln("client tried to send a {} byte packet", header.size);
epoll_ctl(g_epoll_fd, EPOLL_CTL_DEL, client_fd, nullptr); epoll_ctl(g_epoll_fd, EPOLL_CTL_DEL, client_fd, nullptr);
window_server.remove_client_fd(client_fd); window_server.remove_client_fd(client_fd);
close(client_fd);
break; break;
} }
} }