Compare commits

..

No commits in common. "2b0d198b059c7376b784bba0cc9984a6f4d63b91" and "9ff9d679e96598b42e9ccc63788245d73cefc6ea" have entirely different histories.

17 changed files with 93 additions and 350 deletions

View File

@ -5,7 +5,7 @@ VERSION='git'
DOWNLOAD_URL="https://github.com/jewelcodes/tinygb.git#57fdaff675a6b5b963b2b6624868d9698eabe375" DOWNLOAD_URL="https://github.com/jewelcodes/tinygb.git#57fdaff675a6b5b963b2b6624868d9698eabe375"
configure() { configure() {
make -f Makefile.banan_os clean :
} }
build() { build() {

View File

@ -1,14 +1,16 @@
From 7f7c6402e384591bca63021aa97d60a8107de88d Mon Sep 17 00:00:00 2001 From 3e565f7d35e842e246db3371776adae74d02ae62 Mon Sep 17 00:00:00 2001
From: Bananymous <bananymousosq@gmail.com> From: Bananymous <bananymousosq@gmail.com>
Date: Mon, 5 May 2025 00:59:03 +0300 Date: Wed, 23 Apr 2025 13:10:38 +0300
Subject: [PATCH] Add support for banan-os Subject: [PATCH] Add support for banan-os
--- ---
Makefile.banan_os | 28 +++ Makefile.banan_os | 28 +++
src/platform/banan-os/main.cpp | 362 +++++++++++++++++++++++++++++++++ src/platform/banan-os/main.cpp | 365 +++++++++++++++++++++++++++++++
2 files changed, 390 insertions(+) src/platform/banan-os/main.cpp.o | Bin 0 -> 23536 bytes
3 files changed, 393 insertions(+)
create mode 100644 Makefile.banan_os create mode 100644 Makefile.banan_os
create mode 100644 src/platform/banan-os/main.cpp create mode 100644 src/platform/banan-os/main.cpp
create mode 100644 src/platform/banan-os/main.cpp.o
diff --git a/Makefile.banan_os b/Makefile.banan_os diff --git a/Makefile.banan_os b/Makefile.banan_os
new file mode 100644 new file mode 100644
@ -46,10 +48,10 @@ index 0000000..22e191e
+ $(LD) $(OBJ) -o tinygb $(LDFLAGS) + $(LD) $(OBJ) -o tinygb $(LDFLAGS)
diff --git a/src/platform/banan-os/main.cpp b/src/platform/banan-os/main.cpp diff --git a/src/platform/banan-os/main.cpp b/src/platform/banan-os/main.cpp
new file mode 100644 new file mode 100644
index 0000000..94f249e index 0000000..e9c6a02
--- /dev/null --- /dev/null
+++ b/src/platform/banan-os/main.cpp +++ b/src/platform/banan-os/main.cpp
@@ -0,0 +1,362 @@ @@ -0,0 +1,365 @@
+ +
+/* tinygb - a tiny gameboy emulator +/* tinygb - a tiny gameboy emulator
+ (c) 2022 by jewel */ + (c) 2022 by jewel */
@ -244,8 +246,10 @@ index 0000000..94f249e
+ ASSERT(s_window->height() == static_cast<uint32_t>(SGB_HEIGHT * scaling)); + ASSERT(s_window->height() == static_cast<uint32_t>(SGB_HEIGHT * scaling));
+} +}
+ +
+int main(int argc, char **argv) { +int main(int argc, char **argv)
+ if(argc != 2) { +{
+ if(argc != 2)
+ {
+ fprintf(stdout, "usage: %s rom_name\n", argv[0]); + fprintf(stdout, "usage: %s rom_name\n", argv[0]);
+ return 1; + return 1;
+ } + }
@ -257,8 +261,9 @@ index 0000000..94f249e
+ load_keys(); + load_keys();
+ +
+ // open the rom + // open the rom
+ FILE *rom_file = fopen(rom_filename, "r"); + FILE* rom_file = fopen(rom_filename, "r");
+ if(!rom_file) { + if (rom_file == nullptr)
+ {
+ write_log("unable to open %s for reading: %s\n", rom_filename, strerror(errno)); + write_log("unable to open %s for reading: %s\n", rom_filename, strerror(errno));
+ return 1; + return 1;
+ } + }
@ -270,7 +275,8 @@ index 0000000..94f249e
+ write_log("loading rom from file %s, %d KiB\n", rom_filename, rom_size / 1024); + write_log("loading rom from file %s, %d KiB\n", rom_filename, rom_size / 1024);
+ +
+ rom = malloc(rom_size); + rom = malloc(rom_size);
+ if(!rom) { + if (rom == nullptr)
+ {
+ write_log("unable to allocate memory\n"); + write_log("unable to allocate memory\n");
+ fclose(rom_file); + fclose(rom_file);
+ return 1; + return 1;
@ -334,32 +340,31 @@ index 0000000..94f249e
+ time_t rawtime; + time_t rawtime;
+ struct tm *timeinfo; + struct tm *timeinfo;
+ int sec = 500; // any invalid number + int sec = 500; // any invalid number
+ char new_title[256];
+ int percentage; + int percentage;
+ int throttle_underflow = 0; + int throttle_underflow = 0;
+ int throttle_target = throttle_lo + SPEED_ALLOWANCE; + int throttle_target = throttle_lo + SPEED_ALLOWANCE;
+ +
+ while(1) { + for (;;)
+ {
+ s_window->poll_events(); + s_window->poll_events();
+ +
+ for(timing.current_cycles = 0; timing.current_cycles < timing.main_cycles; ) { + for (timing.current_cycles = 0; timing.current_cycles < timing.main_cycles;)
+ {
+ cpu_cycle(); + cpu_cycle();
+ display_cycle(); + display_cycle();
+ timer_cycle(); + timer_cycle();
+ } + }
+ +
+
+ time(&rawtime); + time(&rawtime);
+ timeinfo = localtime(&rawtime); + timeinfo = localtime(&rawtime);
+ +
+ if(sec != timeinfo->tm_sec) { + if (sec != timeinfo->tm_sec)
+ {
+ sec = timeinfo->tm_sec; + sec = timeinfo->tm_sec;
+ percentage = (drawn_frames * 1000) / 597; + percentage = (drawn_frames * 1000) / 597;
+ sprintf(new_title, "tinygb (%d fps - %d%%)", drawn_frames, percentage);
+ s_window->set_title(new_title);
+ +
+ // adjust cpu throttle according to acceptable fps (98%-102%) + // adjust cpu throttle according to acceptable fps (98%-102%)
+ if(throttle_enabled) { + if (throttle_enabled){
+ if(percentage < throttle_lo) { + if(percentage < throttle_lo) {
+ // emulation is too slow + // emulation is too slow
+ if(!throttle_time) { + if(!throttle_time) {
@ -412,7 +417,6 @@ index 0000000..94f249e
+ die(0, ""); + die(0, "");
+ return 0; + return 0;
+} +}
\ No newline at end of file
-- --
2.49.0 2.49.0

View File

@ -1,5 +1,3 @@
// jmp_buf: esp, eip, ebx, ebp, edi, esi
// int setjmp(jmp_buf env) // int setjmp(jmp_buf env)
.global setjmp .global setjmp
setjmp: setjmp:
@ -11,11 +9,6 @@ setjmp:
movl (%esp), %eax movl (%esp), %eax
movl %eax, 4(%edx) movl %eax, 4(%edx)
movl %ebx, 8(%edx)
movl %ebp, 12(%edx)
movl %edi, 16(%edx)
movl %esi, 20(%edx)
xorl %eax, %eax xorl %eax, %eax
ret ret
@ -32,12 +25,8 @@ longjmp:
testl %ecx, %ecx testl %ecx, %ecx
cmovnzl %ecx, %eax cmovnzl %ecx, %eax
movl 0(%edx), %esp movl 0(%edx), %esp
movl 4(%edx), %ecx movl 4(%edx), %ecx
movl 8(%edx), %ebx
movl 12(%edx), %ebp
movl 16(%edx), %edi
movl 20(%edx), %esi
jmp *%ecx jmp *%ecx
.size longjmp, . - longjmp .size longjmp, . - longjmp

View File

@ -1,5 +1,3 @@
// jmp_buf: rsp, rip, rbx, rbp, r12-r15
// int setjmp(jmp_buf env) // int setjmp(jmp_buf env)
.global setjmp .global setjmp
setjmp: setjmp:
@ -9,13 +7,6 @@ setjmp:
movq (%rsp), %rax movq (%rsp), %rax
movq %rax, 8(%rdi) movq %rax, 8(%rdi)
movq %rbx, 16(%rdi)
movq %rbp, 24(%rdi)
movq %r12, 32(%rdi)
movq %r13, 40(%rdi)
movq %r14, 48(%rdi)
movq %r15, 56(%rdi)
xorq %rax, %rax xorq %rax, %rax
ret ret
@ -28,13 +19,7 @@ longjmp:
testq %rsi, %rsi testq %rsi, %rsi
cmovnzq %rsi, %rax cmovnzq %rsi, %rax
movq 0(%rdi), %rsp movq 0(%rdi), %rsp
movq 8(%rdi), %rcx movq 8(%rdi), %rcx
movq 16(%rdi), %rbx
movq 24(%rdi), %rbp
movq 32(%rdi), %r12
movq 40(%rdi), %r13
movq 48(%rdi), %r14
movq 56(%rdi), %r15
jmp *%rcx jmp *%rcx
.size longjmp, . - longjmp .size longjmp, . - longjmp

View File

@ -7,14 +7,8 @@
__BEGIN_DECLS __BEGIN_DECLS
#if defined(__x86_64__) typedef long jmp_buf[2];
#define _JMP_BUF_REGS 8 // rsp, rip, rbx, rbp, r12-r15 typedef long sigjmp_buf[2 + 1 + (sizeof(long long) / sizeof(long))];
#elif defined(__i686__)
#define _JMP_BUF_REGS 6 // esp, eip, ebx, ebp, edi, esi
#endif
typedef long jmp_buf[_JMP_BUF_REGS];
typedef long sigjmp_buf[_JMP_BUF_REGS + 1 + (sizeof(long long) / sizeof(long))];
#define _longjmp longjmp #define _longjmp longjmp
void longjmp(jmp_buf env, int val); void longjmp(jmp_buf env, int val);

View File

@ -240,9 +240,9 @@ static void floating_point_to_exponent_string(char* buffer, T value, bool upper,
// Calculate which number to put as exponent // Calculate which number to put as exponent
int exponent = 0; int exponent = 0;
if (value != static_cast<T>(0.0)) if (value != (T)0.0)
{ {
exponent = BAN::Math::floor<T>(BAN::Math::log10<T>(value)); exponent = (int)BAN::Math::log10<T>(value);
value /= BAN::Math::pow<T>(10.0, exponent); value /= BAN::Math::pow<T>(10.0, exponent);
} }
@ -259,19 +259,6 @@ static void floating_point_to_exponent_string(char* buffer, T value, bool upper,
integer_to_string<int>(buffer + offset, exponent, 10, upper, exponent_options); integer_to_string<int>(buffer + offset, exponent, 10, upper, exponent_options);
} }
template<BAN::floating_point T>
static void floating_point_to_maybe_exponent_string(char* buffer, T value, bool upper, const format_options_t options)
{
int percision = 6;
if (options.percision != -1)
percision = options.percision;
const int exponent = (value != static_cast<T>(0.0)) ? BAN::Math::floor<T>(BAN::Math::log10(value)) : 0;
if (exponent < -4 || exponent >= percision)
return floating_point_to_exponent_string(buffer, value, upper, options);
return floating_point_to_string(buffer, value, upper, options);
}
extern "C" int printf_impl(const char* format, va_list arguments, int (*putc_fun)(int, void*), void* data) extern "C" int printf_impl(const char* format, va_list arguments, int (*putc_fun)(int, void*), void* data)
{ {
int written = 0; int written = 0;
@ -533,16 +520,8 @@ extern "C" int printf_impl(const char* format, va_list arguments, int (*putc_fun
} }
case 'g': case 'g':
case 'G': case 'G':
{ // TODO
switch (options.length)
{
case length_t::L: floating_point_to_maybe_exponent_string<long double>(conversion, va_arg(arguments, long double), *format == 'G', options); break;
default: floating_point_to_maybe_exponent_string<double> (conversion, va_arg(arguments, double), *format == 'G', options); break;
}
string = conversion;
format++;
break; break;
}
case 'a': case 'a':
case 'A': case 'A':
// TODO // TODO

View File

@ -1,19 +1,19 @@
#include <setjmp.h> #include <setjmp.h>
#include <signal.h> #include <signal.h>
static_assert(sizeof(sigjmp_buf) == (_JMP_BUF_REGS + 1) * sizeof(long) + sizeof(sigset_t)); static_assert(sizeof(sigjmp_buf) == sizeof(jmp_buf) + sizeof(long) + sizeof(sigset_t));
void siglongjmp(sigjmp_buf env, int val) void siglongjmp(sigjmp_buf env, int val)
{ {
if (env[_JMP_BUF_REGS]) if (env[2])
pthread_sigmask(SIG_SETMASK, reinterpret_cast<sigset_t*>(&env[_JMP_BUF_REGS + 1]), nullptr); pthread_sigmask(SIG_SETMASK, reinterpret_cast<sigset_t*>(&env[3]), nullptr);
return longjmp(env, val); return longjmp(env, val);
} }
int sigsetjmp(sigjmp_buf env, int savemask) int sigsetjmp(sigjmp_buf env, int savemask)
{ {
env[_JMP_BUF_REGS] = savemask; env[2] = savemask;
if (savemask) if (savemask)
pthread_sigmask(0, nullptr, reinterpret_cast<sigset_t*>(&env[_JMP_BUF_REGS + 1])); pthread_sigmask(0, nullptr, reinterpret_cast<sigset_t*>(&env[3]));
return setjmp(env); return setjmp(env);
} }

View File

@ -38,11 +38,6 @@ time_t time(time_t* tloc)
return tp.tv_sec; return tp.tv_sec;
} }
double difftime(time_t time1, time_t time0)
{
return time1 - time0;
}
// sample implementation from https://pubs.opengroup.org/onlinepubs/9699919799/functions/asctime.html // sample implementation from https://pubs.opengroup.org/onlinepubs/9699919799/functions/asctime.html
char* asctime_r(const struct tm* __restrict tm, char* __restrict buf) char* asctime_r(const struct tm* __restrict tm, char* __restrict buf)
{ {

View File

@ -287,15 +287,6 @@ namespace LibGUI
return on_socket_error(__FUNCTION__); return on_socket_error(__FUNCTION__);
} }
void Window::set_title(BAN::StringView title)
{
WindowPacket::WindowSetTitle packet;
MUST(packet.title.append(title));
if (auto ret = packet.send_serialized(m_server_fd); ret.is_error())
return on_socket_error(__FUNCTION__);
}
void Window::set_position(int32_t x, int32_t y) void Window::set_position(int32_t x, int32_t y)
{ {
WindowPacket::WindowSetPosition packet; WindowPacket::WindowSetPosition packet;
@ -355,7 +346,7 @@ namespace LibGUI
m_framebuffer_smo = nullptr; m_framebuffer_smo = nullptr;
BAN::Vector<uint32_t> framebuffer; BAN::Vector<uint32_t> framebuffer;
TRY(framebuffer.resize(event.width * event.height, m_bg_color)); TRY(framebuffer.resize(event.width * event.height, 0xFFFFFFFF));
void* framebuffer_addr = smo_map(event.smo_key); void* framebuffer_addr = smo_map(event.smo_key);
if (framebuffer_addr == nullptr) if (framebuffer_addr == nullptr)

View File

@ -165,7 +165,6 @@ namespace LibGUI
WindowSetMouseCapture, WindowSetMouseCapture,
WindowSetSize, WindowSetSize,
WindowSetFullscreen, WindowSetFullscreen,
WindowSetTitle,
DestroyWindowEvent, DestroyWindowEvent,
CloseWindowEvent, CloseWindowEvent,
@ -186,7 +185,6 @@ namespace LibGUI
bool focusable; bool focusable;
bool rounded_corners; bool rounded_corners;
bool alpha_channel; bool alpha_channel;
bool resizable;
}; };
DEFINE_PACKET( DEFINE_PACKET(
@ -232,11 +230,6 @@ namespace LibGUI
bool, fullscreen bool, fullscreen
); );
DEFINE_PACKET(
WindowSetTitle,
BAN::String, title
);
} }
namespace EventPacket namespace EventPacket

View File

@ -22,7 +22,6 @@ namespace LibGUI
.focusable = true, .focusable = true,
.rounded_corners = true, .rounded_corners = true,
.alpha_channel = false, .alpha_channel = false,
.resizable = false,
}; };
public: public:
@ -69,7 +68,6 @@ namespace LibGUI
void set_mouse_capture(bool captured); void set_mouse_capture(bool captured);
void set_fullscreen(bool fullscreen); void set_fullscreen(bool fullscreen);
void set_title(BAN::StringView title);
void set_position(int32_t x, int32_t y); void set_position(int32_t x, int32_t y);
@ -83,9 +81,6 @@ namespace LibGUI
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; }
// used on resize to fill empty space
void set_bg_color(uint32_t bg_color) { m_bg_color = bg_color; }
void poll_events(); void poll_events();
void set_socket_error_callback(BAN::Function<void()> callback) { m_socket_error_callback = callback; } void set_socket_error_callback(BAN::Function<void()> callback) { m_socket_error_callback = callback; }
void set_close_window_event_callback(BAN::Function<void()> callback) { m_close_window_event_callback = callback; } void set_close_window_event_callback(BAN::Function<void()> callback) { m_close_window_event_callback = callback; }
@ -122,8 +117,6 @@ namespace LibGUI
uint32_t m_width { 0 }; uint32_t m_width { 0 };
uint32_t m_height { 0 }; uint32_t m_height { 0 };
uint32_t m_bg_color { 0xFFFFFFFF };
BAN::Function<void()> m_socket_error_callback; BAN::Function<void()> m_socket_error_callback;
BAN::Function<void()> m_close_window_event_callback; BAN::Function<void()> m_close_window_event_callback;
BAN::Function<void()> m_resize_window_event_callback; BAN::Function<void()> m_resize_window_event_callback;

View File

@ -116,12 +116,10 @@ void Terminal::run()
auto attributes = LibGUI::Window::default_attributes; auto attributes = LibGUI::Window::default_attributes;
attributes.alpha_channel = true; attributes.alpha_channel = true;
attributes.resizable = true;
m_window = MUST(LibGUI::Window::create(600, 400, "Terminal"_sv, attributes)); m_window = MUST(LibGUI::Window::create(600, 400, "Terminal"_sv, attributes));
m_window->fill(m_bg_color); m_window->fill(m_bg_color);
m_window->invalidate(); m_window->invalidate();
m_window->set_bg_color(m_bg_color);
m_font = MUST(LibFont::Font::load("/usr/share/fonts/lat0-16.psfu"_sv)); m_font = MUST(LibFont::Font::load("/usr/share/fonts/lat0-16.psfu"_sv));
@ -144,27 +142,6 @@ void Terminal::run()
show_cursor(); show_cursor();
m_window->set_key_event_callback([&](LibGUI::EventPacket::KeyEvent::event_t event) { on_key_event(event); }); m_window->set_key_event_callback([&](LibGUI::EventPacket::KeyEvent::event_t event) { on_key_event(event); });
m_window->set_resize_window_event_callback([&] {
if (const auto rem = m_window->height() % m_font.height())
{
m_window->fill_rect(0, m_window->height() - rem, m_window->width(), rem, m_bg_color);
m_window->invalidate(0, m_window->height() - rem, m_window->width(), rem);
}
if (const auto rem = m_window->width() % m_font.width())
{
m_window->fill_rect(m_window->width() - rem, 0, rem, m_window->height(), m_bg_color);
m_window->invalidate(m_window->width() - rem, 0, rem, m_window->height());
}
if (m_cursor.x < cols() && m_cursor.y < rows())
return;
m_cursor.x = BAN::Math::min(m_cursor.x, cols() - 1);
m_cursor.y = BAN::Math::min(m_cursor.y, rows() - 1);
for (auto& pixel : m_cursor_buffer)
pixel = m_bg_color;
});
const int max_fd = BAN::Math::max(m_shell_info.pts_master, m_window->server_fd()); const int max_fd = BAN::Math::max(m_shell_info.pts_master, m_window->server_fd());
while (!s_shell_exited) while (!s_shell_exited)

View File

@ -52,8 +52,6 @@ public:
LibGUI::Window::Attributes get_attributes() const { return m_attributes; }; LibGUI::Window::Attributes get_attributes() const { return m_attributes; };
void set_attributes(LibGUI::Window::Attributes attributes) { m_attributes = attributes; }; void set_attributes(LibGUI::Window::Attributes attributes) { m_attributes = attributes; };
BAN::ErrorOr<void> set_title(BAN::StringView title) { m_title.clear(); TRY(m_title.append(title)); TRY(prepare_title_bar()); return {}; }
const uint32_t* framebuffer() const { return m_fb_addr; } const uint32_t* framebuffer() const { return m_fb_addr; }
uint32_t title_bar_pixel(int32_t abs_x, int32_t abs_y, Position cursor) const uint32_t title_bar_pixel(int32_t abs_x, int32_t abs_y, Position cursor) const

View File

@ -123,11 +123,19 @@ void WindowServer::on_window_invalidate(int fd, const LibGUI::WindowPacket::Wind
return; return;
} }
const int32_t br_x = packet.x + packet.width - 1;
const int32_t br_y = packet.y + packet.height - 1;
if (!target_window->client_size().contains({ br_x, br_y }))
{
dwarnln("invalid Invalidate packet parameters");
return;
}
invalidate({ invalidate({
target_window->client_x() + static_cast<int32_t>(packet.x), target_window->client_x() + static_cast<int32_t>(packet.x),
target_window->client_y() + static_cast<int32_t>(packet.y), target_window->client_y() + static_cast<int32_t>(packet.y),
BAN::Math::min<int32_t>(packet.width, target_window->client_width()), static_cast<int32_t>(packet.width),
BAN::Math::min<int32_t>(packet.height, target_window->client_height()) static_cast<int32_t>(packet.height),
}); });
} }
@ -299,7 +307,7 @@ void WindowServer::on_window_set_fullscreen(int fd, const LibGUI::WindowPacket::
if (!target_window) if (!target_window)
{ {
dwarnln("client tried to set window fullscreen while not owning a window"); dwarnln("client tried to set window size while not owning a window");
return; return;
} }
@ -308,32 +316,6 @@ void WindowServer::on_window_set_fullscreen(int fd, const LibGUI::WindowPacket::
invalidate(m_framebuffer.area()); invalidate(m_framebuffer.area());
} }
void WindowServer::on_window_set_title(int fd, const LibGUI::WindowPacket::WindowSetTitle& packet)
{
BAN::RefPtr<Window> target_window;
for (auto& window : m_client_windows)
{
if (window->client_fd() != fd)
continue;
target_window = window;
break;
}
if (!target_window)
{
dwarnln("client tried to set window title while not owning a window");
return;
}
if (auto ret = target_window->set_title(packet.title); ret.is_error())
{
dwarnln("failed to set window title: {}", ret.error());
return;
}
invalidate(target_window->title_bar_area());
}
void WindowServer::on_key_event(LibInput::KeyEvent event) void WindowServer::on_key_event(LibInput::KeyEvent event)
{ {
// Mod key is not passed to clients // Mod key is not passed to clients
@ -380,11 +362,6 @@ void WindowServer::on_key_event(LibInput::KeyEvent event)
if (!m_focused_window) if (!m_focused_window)
return; return;
m_is_fullscreen_window = !m_is_fullscreen_window; m_is_fullscreen_window = !m_is_fullscreen_window;
if (m_is_fullscreen_window)
{
m_is_moving_window = false;
m_is_resizing_window = false;
}
invalidate(m_framebuffer.area()); invalidate(m_framebuffer.area());
return; return;
} }
@ -428,40 +405,6 @@ void WindowServer::on_mouse_button(LibInput::MouseButtonEvent event)
} }
} }
if (m_is_moving_window && event.button == LibInput::MouseButton::Left && !event.pressed)
{
m_is_moving_window = false;
return;
}
if (m_is_resizing_window && event.button == LibInput::MouseButton::Right && !event.pressed)
{
const auto resize_area = this->resize_area(m_cursor);
m_is_resizing_window = false;
invalidate(resize_area.get_bounding_box(m_focused_window->full_area()));
const auto old_area = m_focused_window->full_area();
if (auto ret = m_focused_window->resize(resize_area.width, resize_area.height - m_focused_window->title_bar_height()); ret.is_error())
{
dwarnln("could not resize client window {}", ret.error());
return;
}
LibGUI::EventPacket::ResizeWindowEvent event;
event.width = m_focused_window->client_width();
event.height = m_focused_window->client_height();
event.smo_key = m_focused_window->smo_key();
if (auto ret = event.send_serialized(m_focused_window->client_fd()); ret.is_error())
{
dwarnln("could not respond to window resize request: {}", ret.error());
return;
}
invalidate(m_focused_window->full_area().get_bounding_box(old_area));
return;
}
// Ignore mouse button events which are not on top of a window // Ignore mouse button events which are not on top of a window
if (!target_window) if (!target_window)
return; return;
@ -469,29 +412,13 @@ void WindowServer::on_mouse_button(LibInput::MouseButtonEvent event)
if (target_window->get_attributes().focusable) if (target_window->get_attributes().focusable)
set_focused_window(target_window); set_focused_window(target_window);
if (!m_is_fullscreen_window && event.button == LibInput::MouseButton::Left) // Handle window moving when mod key is held or mouse press on title bar
{ const bool can_start_move = m_is_mod_key_held || target_window->title_text_area().contains(m_cursor);
const bool can_start_move = m_is_mod_key_held || target_window->title_text_area().contains(m_cursor); if (event.pressed && event.button == LibInput::MouseButton::Left && !m_is_moving_window && can_start_move)
if (can_start_move && !m_is_moving_window && event.pressed) m_is_moving_window = target_window->get_attributes().movable;
{ else if (m_is_moving_window && !event.pressed)
m_is_moving_window = target_window->get_attributes().movable; m_is_moving_window = false;
return; else if (!event.pressed && event.button == LibInput::MouseButton::Left && target_window->close_button_area().contains(m_cursor))
}
}
if (!m_is_fullscreen_window && event.button == LibInput::MouseButton::Right)
{
const bool can_start_resize = m_is_mod_key_held;
if (can_start_resize && !m_is_resizing_window && event.pressed)
{
m_is_resizing_window = target_window->get_attributes().resizable;
if (m_is_resizing_window)
m_resize_start = m_cursor;
return;
}
}
if (!event.pressed && event.button == LibInput::MouseButton::Left && target_window->close_button_area().contains(m_cursor))
{ {
// NOTE: we always have target window if code reaches here // NOTE: we always have target window if code reaches here
LibGUI::EventPacket::CloseWindowEvent packet; LibGUI::EventPacket::CloseWindowEvent packet;
@ -515,6 +442,9 @@ void WindowServer::on_mouse_button(LibInput::MouseButtonEvent event)
return; return;
} }
} }
if (m_is_fullscreen_window)
m_is_moving_window = false;
} }
void WindowServer::on_mouse_move(LibInput::MouseMoveEvent event) void WindowServer::on_mouse_move(LibInput::MouseMoveEvent event)
@ -581,16 +511,6 @@ void WindowServer::on_mouse_move(LibInput::MouseMoveEvent event)
return; return;
} }
if (m_is_resizing_window)
{
const auto max_cursor = Position {
.x = BAN::Math::max(old_cursor.x, new_cursor.x),
.y = BAN::Math::max(old_cursor.y, new_cursor.y),
};
invalidate(resize_area(max_cursor).get_bounding_box(m_focused_window->full_area()));
return;
}
if (m_focused_window) if (m_focused_window)
{ {
LibGUI::EventPacket::MouseMoveEvent packet; LibGUI::EventPacket::MouseMoveEvent packet;
@ -970,24 +890,10 @@ void WindowServer::invalidate(Rectangle area)
} }
} }
if (m_is_resizing_window)
{
if (const auto overlap = resize_area(m_cursor).get_overlap(area); overlap.has_value())
{
for (int32_t y_off = 0; y_off < overlap->height; y_off++)
{
for (int32_t x_off = 0; x_off < overlap->width; x_off++)
{
auto& pixel = m_framebuffer.mmap[(overlap->y + y_off) * m_framebuffer.width + (overlap->x + x_off)];
pixel = alpha_blend(0x80000000, pixel);
}
}
}
}
if (!m_is_mouse_captured) if (!m_is_mouse_captured)
{ {
if (const auto overlap = cursor_area().get_overlap(area); overlap.has_value()) const auto cursor = cursor_area();
if (auto overlap = cursor.get_overlap(area); overlap.has_value())
{ {
for (int32_t y_off = 0; y_off < overlap->height; y_off++) for (int32_t y_off = 0; y_off < overlap->height; y_off++)
{ {
@ -1139,16 +1045,6 @@ Rectangle WindowServer::cursor_area() const
return { m_cursor.x, m_cursor.y, s_cursor_width, s_cursor_height }; return { m_cursor.x, m_cursor.y, s_cursor_width, s_cursor_height };
} }
Rectangle WindowServer::resize_area(Position cursor) const
{
ASSERT(m_is_resizing_window);
return {
.x = m_focused_window->full_x(),
.y = m_focused_window->full_y(),
.width = BAN::Math::max<int32_t>(20, m_focused_window->full_width() + cursor.x - m_resize_start.x),
.height = BAN::Math::max<int32_t>(20, m_focused_window->full_height() + cursor.y - m_resize_start.y),
};
}
void WindowServer::add_client_fd(int fd) void WindowServer::add_client_fd(int fd)
{ {

View File

@ -38,7 +38,6 @@ public:
void on_window_set_mouse_capture(int fd, const LibGUI::WindowPacket::WindowSetMouseCapture&); void on_window_set_mouse_capture(int fd, const LibGUI::WindowPacket::WindowSetMouseCapture&);
void on_window_set_size(int fd, const LibGUI::WindowPacket::WindowSetSize&); void on_window_set_size(int fd, const LibGUI::WindowPacket::WindowSetSize&);
void on_window_set_fullscreen(int fd, const LibGUI::WindowPacket::WindowSetFullscreen&); void on_window_set_fullscreen(int fd, const LibGUI::WindowPacket::WindowSetFullscreen&);
void on_window_set_title(int fd, const LibGUI::WindowPacket::WindowSetTitle&);
void on_key_event(LibInput::KeyEvent event); void on_key_event(LibInput::KeyEvent event);
void on_mouse_button(LibInput::MouseButtonEvent event); void on_mouse_button(LibInput::MouseButtonEvent event);
@ -50,7 +49,6 @@ public:
void sync(); void sync();
Rectangle cursor_area() const; Rectangle cursor_area() const;
Rectangle resize_area(Position cursor) const;
void add_client_fd(int fd); void add_client_fd(int fd);
void remove_client_fd(int fd); void remove_client_fd(int fd);
@ -88,9 +86,6 @@ private:
BAN::RefPtr<Window> m_focused_window; BAN::RefPtr<Window> m_focused_window;
Position m_cursor; Position m_cursor;
bool m_is_resizing_window { false };
Position m_resize_start;
bool m_is_mouse_captured { false }; bool m_is_mouse_captured { false };
bool m_deleted_window { false }; bool m_deleted_window { false };

View File

@ -379,10 +379,6 @@ int main()
if (auto ret = LibGUI::WindowPacket::WindowSetFullscreen::deserialize(client_data.packet_buffer.span()); !ret.is_error()) if (auto ret = LibGUI::WindowPacket::WindowSetFullscreen::deserialize(client_data.packet_buffer.span()); !ret.is_error())
window_server.on_window_set_fullscreen(fd, ret.release_value()); window_server.on_window_set_fullscreen(fd, ret.release_value());
break; break;
case LibGUI::PacketType::WindowSetTitle:
if (auto ret = LibGUI::WindowPacket::WindowSetTitle::deserialize(client_data.packet_buffer.span()); !ret.is_error())
window_server.on_window_set_title(fd, ret.release_value());
break;
default: default:
dprintln("unhandled packet type: {}", *reinterpret_cast<uint32_t*>(client_data.packet_buffer.data())); dprintln("unhandled packet type: {}", *reinterpret_cast<uint32_t*>(client_data.packet_buffer.data()));
} }

View File

@ -1,7 +1,6 @@
#include <BAN/Vector.h> #include <BAN/Vector.h>
#include <fcntl.h> #include <fcntl.h>
#include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -27,7 +26,7 @@ struct Point
bool g_running = true; bool g_running = true;
Point g_grid_size = { 21, 21 }; Point g_grid_size = { 21, 21 };
Direction g_direction = Direction::Up; Direction g_direction = Direction::Up;
Point g_head = { g_grid_size.x / 2, g_grid_size.y / 2 }; Point g_head = { 10, 10 };
size_t g_tail_target = 3; size_t g_tail_target = 3;
int g_score = 0; int g_score = 0;
BAN::Vector<Point> g_tail; BAN::Vector<Point> g_tail;
@ -54,78 +53,53 @@ Direction query_input()
} }
} }
const char* get_tail_char(Direction old_dir, Direction new_dir) void set_grid_tile(Point point, const char* str)
{ {
const size_t old_idx = static_cast<size_t>(old_dir) - 2; printf("\e[%d;%dH%s", (point.y + 1) + 1, (point.x + 1) * 2 + 1, str);
const size_t new_idx = static_cast<size_t>(new_dir) - 2;
// left, right, up, down
constexpr const char* tail_char_map[4][4] {
{ "", "", "", "" },
{ "", "", "", "" },
{ "", "", "", "" },
{ "", "", "", "" },
};
return tail_char_map[old_idx][new_idx];
} }
void set_grid_tile(Point point, const char* str, int off_x = 0) Point get_random_point()
{ {
printf("\e[%d;%dH%s", (point.y + 1) + 1, (point.x + 1) * 2 + 1 + off_x, str); return { .x = rand() % g_grid_size.x, .y = rand() % g_grid_size.y };
}
__attribute__((format(printf, 1, 2)))
void print_score_line(const char* format, ...)
{
printf("\e[%dH\e[m", g_grid_size.y + 3);
va_list args;
va_start(args, format);
vprintf(format, args);
va_end(args);
} }
void update_apple() void update_apple()
{ {
BAN::Vector<Point> free_tiles; for (;;)
for (int y = 0; y < g_grid_size.y; y++)
for (int x = 0; x < g_grid_size.x; x++)
if (const Point point { x, y }; g_head != point && !g_tail.contains(point))
MUST(free_tiles.push_back(point));
if (free_tiles.empty())
{ {
print_score_line("You won!\n"); g_apple = get_random_point();
exit(0); if (g_head == g_apple)
continue;
for (auto point : g_tail)
if (point == g_apple)
continue;
break;
} }
g_apple = free_tiles[rand() % free_tiles.size()];
set_grid_tile(g_apple, "\e[31mO"); set_grid_tile(g_apple, "\e[31mO");
} }
void setup_grid() void setup_grid()
{ {
// Move cursor to beginning and clear screen // Move cursor to beginning and clear screen
printf("\e[H\e[2J"); printf("\e[H\e[J");
// Render top line // Render top line
printf("╔═"); putchar('#');
for (int x = 0; x < g_grid_size.x; x++) for (int x = 1; x < g_grid_size.x + 2; x++)
printf("══"); printf(" #");
printf("\n"); putchar('\n');
// Render side lines // Render side lines
for (int y = 0; y < g_grid_size.y; y++) for (int y = 0; y < g_grid_size.y; y++)
printf("\e[%dC║\n", g_grid_size.x * 2 + 1); printf("#\e[%dC#\n", g_grid_size.x * 2 + 1);
// Render Bottom line // Render Bottom line
printf("╚═"); putchar('#');
for (int x = 0; x < g_grid_size.x; x++) for (int x = 1; x < g_grid_size.x + 2; x++)
printf("══"); printf(" #");
printf(""); putchar('\n');
// Render snake head // Render snake head
printf("\e[32m");
set_grid_tile(g_head, "O"); set_grid_tile(g_head, "O");
// Generate and render apple // Generate and render apple
@ -133,7 +107,7 @@ void setup_grid()
update_apple(); update_apple();
// Render score // Render score
print_score_line("Score: %d", g_score); printf("\e[%dH\e[mScore: %d", g_grid_size.y + 3, g_score);
fflush(stdout); fflush(stdout);
} }
@ -167,7 +141,6 @@ void update()
} }
} }
const auto old_direction = g_direction;
if (new_direction != g_direction && new_direction != Direction::None) if (new_direction != g_direction && new_direction != Direction::None)
g_direction = new_direction; g_direction = new_direction;
@ -208,18 +181,7 @@ void update()
MUST(g_tail.insert(0, old_head)); MUST(g_tail.insert(0, old_head));
if (g_tail.size() > g_tail_target) if (g_tail.size() > g_tail_target)
{ {
const auto comp = g_tail.size() >= 2 ? g_tail[g_tail.size() - 2] : g_head; set_grid_tile(g_tail.back(), " ");
const auto back = g_tail.back();
if (comp.y == back.y)
{
if (comp.x == back.x + 1)
set_grid_tile(back, " ", +1);
if (comp.x == back.x - 1)
set_grid_tile(back, " ", -1);
}
set_grid_tile(back, " ");
g_tail.pop_back(); g_tail.pop_back();
} }
@ -228,16 +190,12 @@ void update()
g_tail_target++; g_tail_target++;
g_score++; g_score++;
update_apple(); update_apple();
print_score_line("Score: %d", g_score); printf("\e[%dH\e[mScore: %d", g_grid_size.y + 3, g_score);
} }
printf("\e[32m"); set_grid_tile(old_head, "\e[32mo");
if (g_direction == Direction::Left) set_grid_tile(g_head, "\e[32mO");
set_grid_tile(g_head, "", +1);
if (g_direction == Direction::Right)
set_grid_tile(g_head, "", -1);
set_grid_tile(old_head, get_tail_char(old_direction, g_direction));
set_grid_tile(g_head, "O");
fflush(stdout); fflush(stdout);
} }