diff --git a/base-sysroot.tar.gz b/base-sysroot.tar.gz index 4e09ee60..f1a12eb1 100644 Binary files a/base-sysroot.tar.gz and b/base-sysroot.tar.gz differ diff --git a/userspace/WindowServer/CMakeLists.txt b/userspace/WindowServer/CMakeLists.txt index 2dc7827d..bb70ad6d 100644 --- a/userspace/WindowServer/CMakeLists.txt +++ b/userspace/WindowServer/CMakeLists.txt @@ -11,7 +11,7 @@ set(SOURCES add_executable(WindowServer ${SOURCES}) target_compile_options(WindowServer PUBLIC -O2 -g) -target_link_libraries(WindowServer PUBLIC libc ban libfont libgui libinput) +target_link_libraries(WindowServer PUBLIC libc ban libfont libgui libimage libinput) add_custom_target(WindowServer-install COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/WindowServer ${BANAN_BIN}/ diff --git a/userspace/WindowServer/WindowServer.cpp b/userspace/WindowServer/WindowServer.cpp index 9f8c34cb..86d410d9 100644 --- a/userspace/WindowServer/WindowServer.cpp +++ b/userspace/WindowServer/WindowServer.cpp @@ -11,6 +11,15 @@ #include #include +BAN::ErrorOr WindowServer::set_background_image(BAN::UniqPtr image) +{ + if (image->width() != (uint64_t)m_framebuffer.width || image->height() != (uint64_t)m_framebuffer.height) + image = TRY(image->resize(m_framebuffer.width, m_framebuffer.height)); + m_background_image = BAN::move(image); + invalidate(m_framebuffer.area()); + return {}; +} + void WindowServer::on_window_packet(int fd, LibGUI::WindowPacket packet) { switch (packet.type) @@ -270,8 +279,19 @@ void WindowServer::invalidate(Rectangle area) return; area = fb_overlap.release_value(); - for (int32_t y = area.y; y < area.y + area.height; y++) - memset(&m_framebuffer.mmap[y * m_framebuffer.width + area.x], 0x10, area.width * 4); + if (m_background_image) + { + ASSERT(m_background_image->width() == (uint64_t)m_framebuffer.width); + ASSERT(m_background_image->height() == (uint64_t)m_framebuffer.height); + for (int32_t y = area.y; y < area.y + area.height; y++) + for (int32_t x = area.x; x < area.x + area.width; x++) + m_framebuffer.mmap[y * m_framebuffer.width + x] = m_background_image->get_color(x, y).as_rgba(); + } + else + { + for (int32_t y = area.y; y < area.y + area.height; y++) + memset(&m_framebuffer.mmap[y * m_framebuffer.width + area.x], 0x10, area.width * 4); + } for (auto& pwindow : m_client_windows) { diff --git a/userspace/WindowServer/WindowServer.h b/userspace/WindowServer/WindowServer.h index f8cba48b..eba52abd 100644 --- a/userspace/WindowServer/WindowServer.h +++ b/userspace/WindowServer/WindowServer.h @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -26,6 +27,8 @@ public: invalidate(m_framebuffer.area()); } + BAN::ErrorOr set_background_image(BAN::UniqPtr); + void on_window_packet(int fd, LibGUI::WindowPacket); void on_key_event(LibInput::KeyEvent event); @@ -50,6 +53,8 @@ private: BAN::Vector> m_client_windows; BAN::Vector m_client_fds; + BAN::UniqPtr m_background_image; + bool m_is_mod_key_held { false }; bool m_is_moving_window { false }; BAN::RefPtr m_focused_window; diff --git a/userspace/WindowServer/main.cpp b/userspace/WindowServer/main.cpp index c92f26dc..b984e1d8 100644 --- a/userspace/WindowServer/main.cpp +++ b/userspace/WindowServer/main.cpp @@ -1,6 +1,7 @@ #include "WindowServer.h" #include +#include #include #include @@ -15,6 +16,88 @@ #include #include +struct Config +{ + BAN::UniqPtr background_image; +}; + +BAN::Optional file_read_line(FILE* file) +{ + BAN::String line; + + char buffer[128]; + while (fgets(buffer, sizeof(buffer), file)) + { + MUST(line.append(buffer)); + if (line.back() == '\n') + { + line.pop_back(); + return BAN::move(line); + } + } + + if (line.empty()) + return {}; + return BAN::move(line); +} + +Config parse_config() +{ + Config config; + + auto home_env = getenv("HOME"); + if (!home_env) + { + dprintln("HOME environment variable not set"); + return config; + } + + auto config_path = BAN::String::formatted("{}/.config/WindowServer.conf", home_env); + FILE* fconfig = fopen(config_path.data(), "r"); + if (!fconfig) + { + dprintln("Could not open '{}'", config_path); + return config; + } + + BAN::ScopeGuard _([fconfig] { fclose(fconfig); }); + + while (true) + { + auto line = file_read_line(fconfig); + if (!line.has_value()) + break; + if (line->empty()) + continue; + + auto parts = MUST(line->sv().split('=')); + if (parts.size() != 2) + { + dwarnln("Invalid config line: {}", line.value()); + break; + } + + auto variable = parts[0]; + auto value = parts[1]; + + if (variable == "bg"sv) + { + auto image = LibImage::Image::load_from_file(value); + if (image.is_error()) + dwarnln("Could not load image: {}", image.error()); + else + config.background_image = image.release_value(); + } + else + { + dwarnln("Unknown config variable: {}", variable); + break; + } + } + + return config; +} + int open_server_fd() { struct stat st; @@ -91,7 +174,13 @@ int main() window_packet_sizes[LibGUI::WindowPacketType::Invalidate] = sizeof(LibGUI::WindowInvalidatePacket); static_assert(LibGUI::WindowPacketType::COUNT == 3); + auto config = parse_config(); + WindowServer window_server(framebuffer); + if (config.background_image) + if (auto ret = window_server.set_background_image(BAN::move(config.background_image)); ret.is_error()) + dwarnln("Could not set background image: {}", ret.error()); + while (!window_server.is_stopped()) { int max_fd = server_fd;