WindowServer: Add support for background images

WindowServer now looks in _$HOME/.config/WindowServer.conf_ for a
configuration file that can specify a background image.

Also add default background image /usr/share/images/sample.ppm to the
base sysroot provided in the git repo.
This commit is contained in:
Bananymous 2024-06-16 00:28:09 +03:00
parent 14d4551476
commit dd64e2060e
5 changed files with 117 additions and 3 deletions

Binary file not shown.

View File

@ -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}/

View File

@ -11,6 +11,15 @@
#include <sys/mman.h>
#include <sys/socket.h>
BAN::ErrorOr<void> WindowServer::set_background_image(BAN::UniqPtr<LibImage::Image> 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)
{

View File

@ -10,6 +10,7 @@
#include <LibFont/Font.h>
#include <LibGUI/Window.h>
#include <LibImage/Image.h>
#include <LibInput/KeyEvent.h>
#include <LibInput/MouseEvent.h>
@ -26,6 +27,8 @@ public:
invalidate(m_framebuffer.area());
}
BAN::ErrorOr<void> set_background_image(BAN::UniqPtr<LibImage::Image>);
void on_window_packet(int fd, LibGUI::WindowPacket);
void on_key_event(LibInput::KeyEvent event);
@ -50,6 +53,8 @@ private:
BAN::Vector<BAN::RefPtr<Window>> m_client_windows;
BAN::Vector<int> m_client_fds;
BAN::UniqPtr<LibImage::Image> m_background_image;
bool m_is_mod_key_held { false };
bool m_is_moving_window { false };
BAN::RefPtr<Window> m_focused_window;

View File

@ -1,6 +1,7 @@
#include "WindowServer.h"
#include <BAN/Debug.h>
#include <BAN/ScopeGuard.h>
#include <LibGUI/Window.h>
#include <LibInput/KeyboardLayout.h>
@ -15,6 +16,88 @@
#include <sys/un.h>
#include <unistd.h>
struct Config
{
BAN::UniqPtr<LibImage::Image> background_image;
};
BAN::Optional<BAN::String> 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;