Compare commits
11 Commits
c0832cf240
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| b03a10d601 | |||
| a02355eb20 | |||
| 7d07c069b9 | |||
| b387457337 | |||
| 5474048db5 | |||
| 7370d562de | |||
| b85cbd5edf | |||
| 40c002323e | |||
| 0e0624ceb6 | |||
| a6a581347e | |||
| e843be0a1c |
@@ -1,20 +1,20 @@
|
||||
From c9dd87198ce5262e6ddf6bf3b0c18eb84784d35e Mon Sep 17 00:00:00 2001
|
||||
From e71364497354b511159bf3d883b0e6168f430187 Mon Sep 17 00:00:00 2001
|
||||
From: Oskari Alaranta <oskari.alaranta@bananymous.com>
|
||||
Date: Wed, 15 Apr 2026 17:52:54 +0300
|
||||
Date: Tue, 7 Jul 2026 05:04:45 +0300
|
||||
Subject: [PATCH] linux-window-server-sdl2
|
||||
|
||||
---
|
||||
userspace/libraries/LibGUI/Widget/Widget.cpp | 2 +-
|
||||
userspace/libraries/LibGUI/Window.cpp | 9 +-
|
||||
userspace/libraries/LibGUI/Window.cpp | 11 +-
|
||||
userspace/programs/ProgramLauncher/main.cpp | 2 +-
|
||||
userspace/programs/Terminal/Terminal.cpp | 4 +-
|
||||
userspace/programs/Terminal/Terminal.cpp | 10 +-
|
||||
.../programs/WindowServer/CMakeLists.txt | 3 +
|
||||
.../programs/WindowServer/Framebuffer.cpp | 52 +--
|
||||
userspace/programs/WindowServer/Window.cpp | 29 +-
|
||||
.../programs/WindowServer/WindowServer.cpp | 47 ++-
|
||||
.../programs/WindowServer/WindowServer.h | 1 +
|
||||
userspace/programs/WindowServer/main.cpp | 357 ++++++++++++------
|
||||
10 files changed, 340 insertions(+), 166 deletions(-)
|
||||
10 files changed, 345 insertions(+), 169 deletions(-)
|
||||
|
||||
diff --git a/userspace/libraries/LibGUI/Widget/Widget.cpp b/userspace/libraries/LibGUI/Widget/Widget.cpp
|
||||
index d6489d87..c532fb04 100644
|
||||
@@ -30,7 +30,7 @@ index d6489d87..c532fb04 100644
|
||||
}
|
||||
|
||||
diff --git a/userspace/libraries/LibGUI/Window.cpp b/userspace/libraries/LibGUI/Window.cpp
|
||||
index b4172f70..3a0e9cca 100644
|
||||
index 607421eb..d8aeee7e 100644
|
||||
--- a/userspace/libraries/LibGUI/Window.cpp
|
||||
+++ b/userspace/libraries/LibGUI/Window.cpp
|
||||
@@ -4,9 +4,8 @@
|
||||
@@ -44,7 +44,7 @@ index b4172f70..3a0e9cca 100644
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <time.h>
|
||||
@@ -271,7 +270,7 @@ namespace LibGUI
|
||||
@@ -311,23 +310,23 @@ namespace LibGUI
|
||||
|
||||
void Window::cleanup()
|
||||
{
|
||||
@@ -53,24 +53,25 @@ index b4172f70..3a0e9cca 100644
|
||||
close(m_server_fd);
|
||||
close(m_epoll_fd);
|
||||
}
|
||||
@@ -279,7 +278,7 @@ namespace LibGUI
|
||||
BAN::ErrorOr<void> Window::handle_resize_event(const EventPacket::ResizeWindowEvent& event)
|
||||
|
||||
BAN::ErrorOr<bool> Window::handle_resize_event(const EventPacket::ResizeWindowEvent& event)
|
||||
{
|
||||
- void* framebuffer_addr = smo_map(event.smo_key);
|
||||
+ void* framebuffer_addr = shmat(event.smo_key, nullptr, 0);
|
||||
if (framebuffer_addr == nullptr)
|
||||
{
|
||||
- if (errno == ENOENT)
|
||||
+ if (errno == EINVAL)
|
||||
return false;
|
||||
return BAN::Error::from_errno(errno);
|
||||
}
|
||||
|
||||
if (m_framebuffer_smo)
|
||||
- munmap(m_framebuffer_smo, m_width * m_height * 4);
|
||||
+ shmdt(m_framebuffer_smo);
|
||||
m_framebuffer_smo = nullptr;
|
||||
|
||||
TRY(m_texture.resize(event.width, event.height));
|
||||
@@ -287,7 +286,7 @@ namespace LibGUI
|
||||
if (m_root_widget)
|
||||
TRY(m_root_widget->set_fixed_geometry({ 0, 0, event.width, event.height }));
|
||||
|
||||
- void* framebuffer_addr = smo_map(event.smo_key);
|
||||
+ void* framebuffer_addr = shmat(event.smo_key, nullptr, 0);
|
||||
if (framebuffer_addr == nullptr)
|
||||
return BAN::Error::from_errno(errno);
|
||||
|
||||
diff --git a/userspace/programs/ProgramLauncher/main.cpp b/userspace/programs/ProgramLauncher/main.cpp
|
||||
index c833c582..0e1cc460 100644
|
||||
--- a/userspace/programs/ProgramLauncher/main.cpp
|
||||
@@ -85,10 +86,18 @@ index c833c582..0e1cc460 100644
|
||||
const auto full_program_list = get_program_list();
|
||||
|
||||
diff --git a/userspace/programs/Terminal/Terminal.cpp b/userspace/programs/Terminal/Terminal.cpp
|
||||
index e1bd317d..8a6b5bd0 100644
|
||||
index c470438d..709db432 100644
|
||||
--- a/userspace/programs/Terminal/Terminal.cpp
|
||||
+++ b/userspace/programs/Terminal/Terminal.cpp
|
||||
@@ -92,7 +92,7 @@ void Terminal::start_shell()
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
+#include <sys/ioctl.h>
|
||||
#include <sys/select.h>
|
||||
#include <termios.h>
|
||||
#include <time.h>
|
||||
@@ -92,7 +93,7 @@ void Terminal::start_shell()
|
||||
close(pts_slave);
|
||||
close(pts_master);
|
||||
|
||||
@@ -97,7 +106,7 @@ index e1bd317d..8a6b5bd0 100644
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ void Terminal::run()
|
||||
@@ -127,7 +128,7 @@ void Terminal::run()
|
||||
m_window->texture().set_bg_color(m_bg_color);
|
||||
m_window->invalidate();
|
||||
|
||||
@@ -106,6 +115,25 @@ index e1bd317d..8a6b5bd0 100644
|
||||
|
||||
m_window->set_min_size(m_font.width() * 8, m_font.height() * 2);
|
||||
|
||||
@@ -147,7 +148,8 @@ void Terminal::run()
|
||||
.ws_xpixel = static_cast<unsigned short>(m_window->width()),
|
||||
.ws_ypixel = static_cast<unsigned short>(m_window->height()),
|
||||
};
|
||||
- if (tcsetwinsize(m_shell_info.pts_master, &winsize) == -1)
|
||||
+
|
||||
+ if (ioctl(m_shell_info.pts_master, TIOCSWINSZ, &winsize) == -1)
|
||||
perror("tcsetwinsize");
|
||||
}
|
||||
|
||||
@@ -212,7 +214,7 @@ void Terminal::run()
|
||||
.ws_xpixel = static_cast<unsigned short>(m_window->width()),
|
||||
.ws_ypixel = static_cast<unsigned short>(m_window->height()),
|
||||
};
|
||||
- if (tcsetwinsize(m_shell_info.pts_master, &winsize) == -1)
|
||||
+ if (ioctl(m_shell_info.pts_master, TIOCSWINSZ, &winsize) == -1)
|
||||
perror("tcsetwinsize");
|
||||
});
|
||||
|
||||
diff --git a/userspace/programs/WindowServer/CMakeLists.txt b/userspace/programs/WindowServer/CMakeLists.txt
|
||||
index 8fdf79f9..fcaf441d 100644
|
||||
--- a/userspace/programs/WindowServer/CMakeLists.txt
|
||||
@@ -199,7 +227,7 @@ index 0e727e8f..119f1451 100644
|
||||
return framebuffer;
|
||||
}
|
||||
diff --git a/userspace/programs/WindowServer/Window.cpp b/userspace/programs/WindowServer/Window.cpp
|
||||
index 1e66f522..9759eec9 100644
|
||||
index 78de89c9..c5405695 100644
|
||||
--- a/userspace/programs/WindowServer/Window.cpp
|
||||
+++ b/userspace/programs/WindowServer/Window.cpp
|
||||
@@ -5,15 +5,14 @@
|
||||
@@ -221,7 +249,7 @@ index 1e66f522..9759eec9 100644
|
||||
|
||||
LibGUI::EventPacket::DestroyWindowEvent packet;
|
||||
|
||||
@@ -47,16 +46,16 @@ BAN::ErrorOr<void> Window::resize(uint32_t width, uint32_t height)
|
||||
@@ -45,16 +44,16 @@ BAN::ErrorOr<void> Window::resize(uint32_t width, uint32_t height)
|
||||
{
|
||||
const size_t fb_bytes = width * height * 4;
|
||||
|
||||
@@ -244,7 +272,7 @@ index 1e66f522..9759eec9 100644
|
||||
|
||||
{
|
||||
const auto old_area = m_client_area;
|
||||
@@ -70,16 +69,14 @@ BAN::ErrorOr<void> Window::resize(uint32_t width, uint32_t height)
|
||||
@@ -68,16 +67,14 @@ BAN::ErrorOr<void> Window::resize(uint32_t width, uint32_t height)
|
||||
return title_bar_ret.release_error();
|
||||
}
|
||||
|
||||
@@ -266,7 +294,7 @@ index 1e66f522..9759eec9 100644
|
||||
m_client_area.max_x = m_client_area.min_x + width;
|
||||
m_client_area.max_y = m_client_area.min_y + height;
|
||||
diff --git a/userspace/programs/WindowServer/WindowServer.cpp b/userspace/programs/WindowServer/WindowServer.cpp
|
||||
index 2c67d6c0..600704fd 100644
|
||||
index e6b01476..a14074c3 100644
|
||||
--- a/userspace/programs/WindowServer/WindowServer.cpp
|
||||
+++ b/userspace/programs/WindowServer/WindowServer.cpp
|
||||
@@ -8,19 +8,20 @@
|
||||
@@ -295,16 +323,16 @@ index 2c67d6c0..600704fd 100644
|
||||
{
|
||||
MUST(m_background_image.resize(m_framebuffer.width * m_framebuffer.height, 0xFF101010));
|
||||
|
||||
@@ -440,7 +441,7 @@ static void update_volume(const char* new_volume)
|
||||
@@ -512,7 +513,7 @@ static void update_volume(const char* new_volume)
|
||||
|
||||
void WindowServer::on_key_event(LibInput::KeyEvent event)
|
||||
{
|
||||
- if (event.key == LibInput::Key::Super)
|
||||
- if (event.key == LibInput::Key::LeftSuper)
|
||||
+ if (event.key == LibInput::Key::RightCtrl)
|
||||
m_is_mod_key_held = event.pressed();
|
||||
|
||||
if (event.pressed() && event.key == LibInput::Key::VolumeDown)
|
||||
@@ -461,7 +462,7 @@ void WindowServer::on_key_event(LibInput::KeyEvent event)
|
||||
@@ -533,7 +534,7 @@ void WindowServer::on_key_event(LibInput::KeyEvent event)
|
||||
pid_t pid = fork();
|
||||
if (pid == 0)
|
||||
{
|
||||
@@ -313,7 +341,7 @@ index 2c67d6c0..600704fd 100644
|
||||
exit(1);
|
||||
}
|
||||
if (pid == -1)
|
||||
@@ -475,7 +476,7 @@ void WindowServer::on_key_event(LibInput::KeyEvent event)
|
||||
@@ -547,7 +548,7 @@ void WindowServer::on_key_event(LibInput::KeyEvent event)
|
||||
pid_t pid = fork();
|
||||
if (pid == 0)
|
||||
{
|
||||
@@ -322,7 +350,7 @@ index 2c67d6c0..600704fd 100644
|
||||
exit(1);
|
||||
}
|
||||
if (pid == -1)
|
||||
@@ -1599,16 +1600,34 @@ void WindowServer::sync()
|
||||
@@ -1664,16 +1665,34 @@ void WindowServer::sync()
|
||||
|
||||
for (size_t i = 0; i < m_damaged_area_count; i++)
|
||||
{
|
||||
@@ -364,10 +392,10 @@ index 2c67d6c0..600704fd 100644
|
||||
|
||||
Rectangle WindowServer::cursor_area() const
|
||||
diff --git a/userspace/programs/WindowServer/WindowServer.h b/userspace/programs/WindowServer/WindowServer.h
|
||||
index 94fbc774..bcd7a6b9 100644
|
||||
index 9e2dc70e..40813f2e 100644
|
||||
--- a/userspace/programs/WindowServer/WindowServer.h
|
||||
+++ b/userspace/programs/WindowServer/WindowServer.h
|
||||
@@ -62,6 +62,7 @@ public:
|
||||
@@ -65,6 +65,7 @@ public:
|
||||
|
||||
bool is_damaged() const { return m_damaged_area_count > 0 || m_is_bouncing_window; }
|
||||
bool is_stopped() const { return m_is_stopped; }
|
||||
@@ -376,7 +404,7 @@ index 94fbc774..bcd7a6b9 100644
|
||||
private:
|
||||
void on_mouse_move_impl(int32_t new_x, int32_t new_y);
|
||||
diff --git a/userspace/programs/WindowServer/main.cpp b/userspace/programs/WindowServer/main.cpp
|
||||
index 46f2ba6d..520c8e7d 100644
|
||||
index 61d10e97..e77e5d97 100644
|
||||
--- a/userspace/programs/WindowServer/main.cpp
|
||||
+++ b/userspace/programs/WindowServer/main.cpp
|
||||
@@ -10,7 +10,6 @@
|
||||
@@ -518,7 +546,7 @@ index 46f2ba6d..520c8e7d 100644
|
||||
if (epoll_events == -1 && errno != EINTR)
|
||||
{
|
||||
dwarnln("epoll_pwait2: {}", strerror(errno));
|
||||
@@ -333,48 +288,6 @@ int main()
|
||||
@@ -334,48 +289,6 @@ int main()
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -567,7 +595,7 @@ index 46f2ba6d..520c8e7d 100644
|
||||
const int client_fd = events[i].data.fd;
|
||||
if (events[i].events & (EPOLLHUP | EPOLLERR))
|
||||
{
|
||||
@@ -500,3 +413,237 @@ int main()
|
||||
@@ -507,3 +420,237 @@ int main()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -806,5 +834,5 @@ index 46f2ba6d..520c8e7d 100644
|
||||
+ }
|
||||
+}
|
||||
--
|
||||
2.53.0
|
||||
2.54.0
|
||||
|
||||
|
||||
@@ -26,7 +26,14 @@ set(CMAKE_CXX_STANDARD 20)
|
||||
add_compile_definitions(-Dstddbg=stdout)
|
||||
add_compile_options(-g)
|
||||
|
||||
if(BANAN_OS)
|
||||
set(PLATFORM "banan-os" CACHE STRING "target platform")
|
||||
|
||||
set(VALID_PLATFORMS "banan-os" "SDL3")
|
||||
if(NOT PLATFORM IN_LIST VALID_PLATFORMS)
|
||||
message(FATAL_ERROR "platform \"${PLATFORM}\" not known, valid platforms are ${VALID_PLATFORMS}")
|
||||
endif()
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "banan-os")
|
||||
find_library(BAN ban REQUIRED)
|
||||
add_library(ban SHARED IMPORTED)
|
||||
set_target_properties(ban PROPERTIES IMPORTED_LOCATION "${BAN}")
|
||||
@@ -48,16 +55,19 @@ else()
|
||||
set_target_properties(libc PROPERTIES IMPORTED_LOCATION "${LIBC}")
|
||||
|
||||
add_subdirectory(banan-os/BAN)
|
||||
add_subdirectory(banan-os/userspace/libraries/LibClipboard)
|
||||
add_subdirectory(banan-os/userspace/libraries/LibDEFLATE)
|
||||
add_subdirectory(banan-os/userspace/libraries/LibFont)
|
||||
add_subdirectory(banan-os/userspace/libraries/LibGUI)
|
||||
add_subdirectory(banan-os/userspace/libraries/LibImage)
|
||||
add_subdirectory(banan-os/userspace/libraries/LibInput)
|
||||
|
||||
add_subdirectory(banan-os/userspace/programs/ProgramLauncher)
|
||||
add_subdirectory(banan-os/userspace/programs/Terminal)
|
||||
add_subdirectory(banan-os/userspace/programs/WindowServer)
|
||||
if(PLATFORM STREQUAL "banan-os")
|
||||
add_subdirectory(banan-os/userspace/libraries/LibClipboard)
|
||||
add_subdirectory(banan-os/userspace/libraries/LibFont)
|
||||
add_subdirectory(banan-os/userspace/libraries/LibGUI)
|
||||
add_subdirectory(banan-os/userspace/libraries/LibImage)
|
||||
add_subdirectory(banan-os/userspace/libraries/LibInput)
|
||||
|
||||
add_subdirectory(banan-os/userspace/programs/ProgramLauncher)
|
||||
add_subdirectory(banan-os/userspace/programs/Terminal)
|
||||
add_subdirectory(banan-os/userspace/programs/WindowServer)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_subdirectory(xbanan)
|
||||
|
||||
36
README.md
36
README.md
@@ -1,29 +1,45 @@
|
||||
# xbanan
|
||||
|
||||
An X11 compatibility layer for [banan-os's](https://git.bananymous.com/Bananymous/banan-os) native GUI windowing system.
|
||||
A portable X11 compatibility layer. There are 2 officially supported platforms: [banan-os's](https://git.bananymous.com/Bananymous/banan-os) native GUI windowing system and SDL3.
|
||||
|
||||
## Running on linux
|
||||
|
||||
### Prerequisites
|
||||
|
||||
You need to have SDL3 development library and X11 headers installed on your system.
|
||||
|
||||
### Building
|
||||
```sh
|
||||
git clone --recursive https://git.bananymous.com/Bananymous/xbanan.git
|
||||
cd xbanan
|
||||
|
||||
cd banan-os
|
||||
git apply ../0001-linux-window-server-sdl2.patch
|
||||
cd ..
|
||||
|
||||
cmake -B build -S . -G Ninja
|
||||
cmake --build build
|
||||
cmake -B build -S . -DPLATFORM=SDL3
|
||||
cmake --build build --parallel $(nproc)
|
||||
```
|
||||
|
||||
### Running
|
||||
|
||||
To start the WindowServer, run the following command in project root
|
||||
To start xbanan, run the following command in project root
|
||||
```sh
|
||||
./build/banan-os/userspace/programs/WindowServer/WindowServer
|
||||
./build/xbanan/xbanan
|
||||
```
|
||||
To run X11 apps specify `DISPLAY=:69` environment variable. For example
|
||||
To run X11 apps, specify `DISPLAY=:69` environment variable. For example
|
||||
```sh
|
||||
DISPLAY=:69 xeyes
|
||||
```
|
||||
|
||||
## Porting to a new platform
|
||||
|
||||
Add your platform to the `VALID_PLATFORMS` list in the root `CMakeLists.txt` file. Create a directory for your platform in `xbanan/<your platform>` and define the needed source files and libraries in `xbanan/CMakeLists.txt` based on your platform.
|
||||
|
||||
### Barebones
|
||||
|
||||
For the simplest port, you need to implement 3 functions: `initialize`, `create_window` and `invalidate`. Define the variable `g_platform_ops` declared in `xbanan/Platform.h` with function pointers to the your functions. You can look at the existing platforms and the `xbanan/Platform.h` header for help.
|
||||
|
||||
### Events
|
||||
|
||||
To handle events, you have to hook an event receiver fd for your platform using `register_event_fd` declared in `xbanan/Events.h` and define the `poll_events` function in `g_platform_ops`. When the registered fd becomes readable, xbanan will call your platform's `poll_events` function. This function should drain all of the pending events and call appropriate `on_*_event` function declared in the events header. If your platform does not expose fd(s) that can be polled for events, you can do what the SDL3 port does and create an eventfd/pipe that gets signaled periodically.
|
||||
|
||||
### Installation
|
||||
|
||||
To install xbanan to sysroot, just copy the `build/xbanan/xbanan` to the destination. xbanan is statically linked against the libraries from this repository so you don't have to care about those. **DO NOT** use the cmake's install target, as that installs banan-os libraries to the root of the sysroot. You also need to have the x11 misc fonts at `FONT_PATH/misc` in your sysroot if you want server side font support. The fonts are shipped (public domain) with xbanan, so you can just copy `fonts/misc` into `FONT_PATH`. You can specify the `FONT_PATH` with cmake using `-DFONT_PATH=...` when configuring.
|
||||
|
||||
2
banan-os
2
banan-os
Submodule banan-os updated: 1bf5e6a051...e713644973
510
xbanan/Base.cpp
510
xbanan/Base.cpp
@@ -159,6 +159,16 @@ static const char* s_opcode_to_name[] {
|
||||
[X_NoOperation] = "X_NoOperation",
|
||||
};
|
||||
|
||||
void register_display(int32_t x, int32_t y, uint32_t width, uint32_t height)
|
||||
{
|
||||
MUST(g_displays.push_back({
|
||||
.x = x,
|
||||
.y = y,
|
||||
.w = width,
|
||||
.h = height,
|
||||
}));
|
||||
}
|
||||
|
||||
uint32_t Object::Window::full_event_mask() const
|
||||
{
|
||||
uint32_t full_event_mask = 0;
|
||||
@@ -200,9 +210,9 @@ BAN::ErrorOr<void> setup_client_conneciton(Client& client_info, const xConnClien
|
||||
xConnSetupPrefix setup_prefix {
|
||||
.success = 1,
|
||||
.lengthReason = 0, // wtf is this
|
||||
.majorVersion = client_prefix.majorVersion,
|
||||
.minorVersion = client_prefix.minorVersion,
|
||||
.length = 8 + 2*format_count + (8 + 0 + sz_xWindowRoot + sz_xDepth + sz_xVisualType) / 4,
|
||||
.majorVersion = 11,
|
||||
.minorVersion = 0,
|
||||
.length = 8 + 2 * format_count + (8 + 0 + sz_xWindowRoot + sz_xDepth + sz_xVisualType) / 4,
|
||||
};
|
||||
TRY(encode(client_info.output_buffer, setup_prefix));
|
||||
|
||||
@@ -286,85 +296,61 @@ static BAN::ErrorOr<void> send_visibility_events_recursively(Client& client_info
|
||||
return {};
|
||||
}
|
||||
|
||||
static void invalidate_window_recursive(WINDOW wid, int32_t x, int32_t y, int32_t w, int32_t h)
|
||||
static void invalidate_window_recursive(Object::Window& dst_window, int32_t dst_x, int32_t dst_y, const Object::Window& src_window, int32_t src_x, int32_t src_y, int32_t w, int32_t h)
|
||||
{
|
||||
ASSERT(wid != g_root.windowId);
|
||||
ASSERT(src_window.mapped);
|
||||
|
||||
if (x + w <= 0 || y + h <= 0)
|
||||
return;
|
||||
if (w <= 0 || h <= 0)
|
||||
return;
|
||||
|
||||
auto& object = *g_objects[wid];
|
||||
ASSERT(object.type == Object::Type::Window);
|
||||
|
||||
auto& window = object.object.get<Object::Window>();
|
||||
if (!window.mapped)
|
||||
return;
|
||||
|
||||
for (auto child_wid : window.children)
|
||||
if (src_window.c_class == InputOutput)
|
||||
{
|
||||
const auto& child_object = *g_objects[child_wid];
|
||||
ASSERT(child_object.type == Object::Type::Window);
|
||||
ASSERT(src_x >= 0);
|
||||
ASSERT(src_y >= 0);
|
||||
ASSERT(src_x + w <= src_window.width);
|
||||
ASSERT(src_y + h <= src_window.height);
|
||||
ASSERT(dst_x + w <= dst_window.width);
|
||||
ASSERT(dst_y + h <= dst_window.height);
|
||||
|
||||
const auto& child_window = child_object.object.get<Object::Window>();
|
||||
if (!child_window.mapped)
|
||||
continue;
|
||||
|
||||
const auto child_x = x - child_window.x;
|
||||
const auto child_y = y - child_window.y;
|
||||
|
||||
const auto child_w = BAN::Math::min<int32_t>(w - child_window.x, child_window.width - child_x);
|
||||
const auto child_h = BAN::Math::min<int32_t>(h - child_window.y, child_window.height - child_y);
|
||||
|
||||
invalidate_window_recursive(
|
||||
child_wid,
|
||||
child_x, child_y,
|
||||
child_w, child_h
|
||||
);
|
||||
for (int32_t y = 0; y < h; y++)
|
||||
{
|
||||
uint32_t* dst_u32 = &dst_window.double_buffer[(dst_y + y) * dst_window.width + dst_x];
|
||||
const uint32_t* src_u32 = &src_window. pixels[(src_y + y) * src_window.width + src_x];
|
||||
for (int32_t x = 0; x < w; x++)
|
||||
{
|
||||
if (src_u32[x] != COLOR_INVISIBLE)
|
||||
dst_u32[x] = 0xFF000000 | src_u32[x];
|
||||
else if (&dst_window == &src_window)
|
||||
dst_u32[x] = 0x00000000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (window.platform_window || window.c_class == InputOnly)
|
||||
return;
|
||||
|
||||
auto& parent_object = *g_objects[window.parent];
|
||||
ASSERT(parent_object.type == Object::Type::Window);
|
||||
|
||||
auto& parent_window = parent_object.object.get<Object::Window>();
|
||||
|
||||
const uint32_t* child_pix = window.pixels.data();
|
||||
const int32_t child_w = window.width;
|
||||
const int32_t child_h = window.height;
|
||||
|
||||
uint32_t* parent_pix = parent_window.pixels.data();
|
||||
const int32_t parent_w = parent_window.width;
|
||||
const int32_t parent_h = parent_window.height;
|
||||
|
||||
// FIXME: optimize this
|
||||
for (int32_t y_off = 0; y_off < h; y_off++)
|
||||
for (auto child_wid : src_window.children)
|
||||
{
|
||||
const int32_t child_y = y + y_off;
|
||||
if (child_y < 0 || child_y >= child_h)
|
||||
const auto& child = g_objects[child_wid]->object.get<Object::Window>();
|
||||
if (!child.mapped)
|
||||
continue;
|
||||
|
||||
const int32_t parent_y = window.y + y + y_off;
|
||||
if (parent_y < 0 || parent_y >= parent_h)
|
||||
const auto diff_x = src_x - child.x;
|
||||
const auto diff_y = src_y - child.y;
|
||||
|
||||
const auto min_x = BAN::Math::max<int32_t>(diff_x, 0);
|
||||
const auto min_y = BAN::Math::max<int32_t>(diff_y, 0);
|
||||
|
||||
const auto max_x = BAN::Math::min<int32_t>(diff_x + w, child.width);
|
||||
const auto max_y = BAN::Math::min<int32_t>(diff_y + h, child.height);
|
||||
|
||||
if (max_x <= min_x || max_y <= min_y)
|
||||
continue;
|
||||
|
||||
for (int32_t x_off = 0; x_off < w; x_off++)
|
||||
{
|
||||
const int32_t child_x = x + x_off;
|
||||
if (child_x < 0 || child_x >= child_w)
|
||||
continue;
|
||||
|
||||
const int32_t parent_x = window.x + x + x_off;
|
||||
if (parent_x < 0 || parent_x >= parent_w)
|
||||
continue;
|
||||
|
||||
const uint32_t color = child_pix[child_y * child_w + child_x];
|
||||
if (color != COLOR_INVISIBLE)
|
||||
parent_pix[parent_y * parent_w + parent_x] = color;
|
||||
}
|
||||
invalidate_window_recursive(
|
||||
dst_window,
|
||||
dst_x - (diff_x - min_x),
|
||||
dst_y - (diff_y - min_y),
|
||||
child,
|
||||
min_x,
|
||||
min_y,
|
||||
max_x - min_x,
|
||||
max_y - min_y
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -372,68 +358,120 @@ void invalidate_window(WINDOW wid, int32_t x, int32_t y, int32_t w, int32_t h)
|
||||
{
|
||||
ASSERT(wid != g_root.windowId);
|
||||
|
||||
int32_t min_x { x }, max_x { x + w };
|
||||
int32_t min_y { y }, max_y { y + h };
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (wid == g_root.windowId)
|
||||
return;
|
||||
|
||||
auto& object = *g_objects[wid];
|
||||
ASSERT(object.type == Object::Type::Window);
|
||||
|
||||
auto& window = object.object.get<Object::Window>();
|
||||
const auto& window = g_objects[wid]->object.get<Object::Window>();
|
||||
if (!window.mapped)
|
||||
return;
|
||||
|
||||
if (min_x < 0)
|
||||
min_x = 0;
|
||||
if (min_y < 0)
|
||||
min_y = 0;
|
||||
|
||||
if (max_x > window.width)
|
||||
max_x = window.width;
|
||||
if (max_y > window.height)
|
||||
max_y = window.height;
|
||||
|
||||
if (max_x <= min_x || max_y <= min_y)
|
||||
return;
|
||||
|
||||
if (window.platform_window)
|
||||
break;
|
||||
|
||||
x += window.x;
|
||||
y += window.y;
|
||||
min_x += window.x;
|
||||
min_y += window.y;
|
||||
wid = window.parent;
|
||||
}
|
||||
|
||||
auto& object = *g_objects[wid];
|
||||
ASSERT(object.type == Object::Type::Window);
|
||||
auto& window = g_objects[wid]->object.get<Object::Window>();
|
||||
|
||||
auto& window = object.object.get<Object::Window>();
|
||||
ASSERT(window.platform_window);
|
||||
invalidate_window_recursive(
|
||||
window, min_x, min_y,
|
||||
window, min_x, min_y,
|
||||
max_x - min_x,
|
||||
max_y - min_y
|
||||
);
|
||||
|
||||
invalidate_window_recursive(wid, x, y, w, h);
|
||||
if (!window.platform_window_invalidated && g_platform_ops.begin_frame)
|
||||
g_platform_ops.begin_frame(window.platform_window.ptr());
|
||||
window.platform_window_invalidated = true;
|
||||
|
||||
const auto min_x = BAN::Math::max<int32_t>(x, 0);
|
||||
const auto min_y = BAN::Math::max<int32_t>(y, 0);
|
||||
const auto max_x = BAN::Math::min<int32_t>(x + w, window.width);
|
||||
const auto max_y = BAN::Math::min<int32_t>(y + h, window.height);
|
||||
|
||||
if (min_x >= max_x || min_y >= max_y)
|
||||
return;
|
||||
|
||||
uint32_t* pixels = window.pixels.data();
|
||||
for (auto y = min_y; y < max_y; y++)
|
||||
{
|
||||
for (auto x = min_x; x < max_x; x++)
|
||||
{
|
||||
auto& pixel = pixels[y * window.width + x];
|
||||
if (pixel == COLOR_INVISIBLE)
|
||||
pixel = 0x00000000;
|
||||
else
|
||||
pixel |= 0xFF000000;
|
||||
}
|
||||
}
|
||||
|
||||
g_platform_ops.invalidate(window.platform_window.ptr(), window.pixels.data(), min_x, min_y, max_x - min_x, max_y - min_y);
|
||||
g_platform_ops.invalidate(
|
||||
window.platform_window.ptr(),
|
||||
&window.double_buffer[min_y * window.width + min_x],
|
||||
window.width * sizeof(uint32_t),
|
||||
min_x, min_y,
|
||||
max_x - min_x,
|
||||
max_y - min_y
|
||||
);
|
||||
}
|
||||
|
||||
void send_exposure_recursive(WINDOW wid)
|
||||
BAN::ErrorOr<void> send_configure_notify(WINDOW wid)
|
||||
{
|
||||
auto& object = *g_objects[wid];
|
||||
ASSERT(object.type == Object::Type::Window);
|
||||
auto& window = g_objects[wid]->object.get<Object::Window>();
|
||||
|
||||
auto& window = object.object.get<Object::Window>();
|
||||
{
|
||||
xEvent event = { .u = {
|
||||
.configureNotify = {
|
||||
.event = wid,
|
||||
.window = wid,
|
||||
.aboveSibling = xFalse,
|
||||
.x = static_cast<INT16>(window.x),
|
||||
.y = static_cast<INT16>(window.y),
|
||||
.width = static_cast<CARD16>(window.width),
|
||||
.height = static_cast<CARD16>(window.height),
|
||||
.borderWidth = 0,
|
||||
.override = xFalse,
|
||||
}
|
||||
}};
|
||||
event.u.u.type = ConfigureNotify;
|
||||
TRY(window.send_event(event, StructureNotifyMask));
|
||||
}
|
||||
|
||||
auto& parent_object = *g_objects[window.parent];
|
||||
ASSERT(parent_object.type == Object::Type::Window);
|
||||
auto& parent_window = parent_object.object.get<Object::Window>();
|
||||
|
||||
{
|
||||
xEvent event = { .u = {
|
||||
.configureNotify = {
|
||||
.event = window.parent,
|
||||
.window = wid,
|
||||
.aboveSibling = xFalse,
|
||||
.x = static_cast<INT16>(window.x),
|
||||
.y = static_cast<INT16>(window.y),
|
||||
.width = static_cast<CARD16>(window.width),
|
||||
.height = static_cast<CARD16>(window.height),
|
||||
.borderWidth = 0,
|
||||
.override = xFalse,
|
||||
}
|
||||
}};
|
||||
event.u.u.type = ConfigureNotify;
|
||||
TRY(parent_window.send_event(event, SubstructureNotifyMask));
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> send_exposure_events_recursive(WINDOW wid)
|
||||
{
|
||||
auto& window = g_objects[wid]->object.get<Object::Window>();
|
||||
if (!window.mapped)
|
||||
return;
|
||||
return {};
|
||||
|
||||
for (auto child_wid : window.children)
|
||||
send_exposure_recursive(child_wid);
|
||||
TRY(send_exposure_events_recursive(child_wid));
|
||||
|
||||
if (window.c_class == InputOnly)
|
||||
return {};
|
||||
|
||||
xEvent event = { .u = {
|
||||
.expose = {
|
||||
@@ -445,66 +483,32 @@ void send_exposure_recursive(WINDOW wid)
|
||||
}
|
||||
}};
|
||||
event.u.u.type = Expose;
|
||||
MUST(window.send_event(event, ExposureMask));
|
||||
TRY(window.send_event(event, ExposureMask));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
struct PlatformWindowInfo
|
||||
{
|
||||
PlatformWindow* parent;
|
||||
WindowType type;
|
||||
};
|
||||
|
||||
static PlatformWindowInfo get_plaform_window_info(const Object::Window& window)
|
||||
static WindowType get_plaform_window_info(const Object::Window& window)
|
||||
{
|
||||
static const CARD32 ATOM = g_atoms_name_to_id["ATOM"_sv];
|
||||
static const CARD32 WINDOW = g_atoms_name_to_id["WINDOW"_sv];
|
||||
static const CARD32 WM_TRANSIENT_FOR = g_atoms_name_to_id["WM_TRANSIENT_FOR"_sv];
|
||||
static const CARD32 _NET_WM_WINDOW_TYPE = g_atoms_name_to_id["_NET_WM_WINDOW_TYPE"_sv];
|
||||
static const CARD32 _NET_WM_WINDOW_TYPE_DIALOG = g_atoms_name_to_id["_NET_WM_WINDOW_TYPE_DIALOG"_sv];
|
||||
static const CARD32 _NET_WM_WINDOW_TYPE_NORMAL = g_atoms_name_to_id["_NET_WM_WINDOW_TYPE_NORMAL"_sv];
|
||||
static const CARD32 _NET_WM_WINDOW_TYPE_SPLASH = g_atoms_name_to_id["_NET_WM_WINDOW_TYPE_SPLASH"_sv];
|
||||
static const CARD32 _NET_WM_WINDOW_TYPE_UTILITY = g_atoms_name_to_id["_NET_WM_WINDOW_TYPE_UTILITY"_sv];
|
||||
|
||||
PlatformWindowInfo info {
|
||||
.parent = nullptr,
|
||||
.type = WindowType::Normal,
|
||||
};
|
||||
auto it = window.properties.find(_NET_WM_WINDOW_TYPE);
|
||||
if (it == window.properties.end())
|
||||
return WindowType::Normal;
|
||||
|
||||
if (auto it = window.properties.find(_NET_WM_WINDOW_TYPE); it != window.properties.end())
|
||||
{
|
||||
if (it->value.type != ATOM || it->value.data.size() != sizeof(CARD32))
|
||||
goto wm_window_type_done;
|
||||
if (it->value.type != ATOM || it->value.data.size() != sizeof(CARD32))
|
||||
return WindowType::Normal;
|
||||
|
||||
const CARD32 type = *reinterpret_cast<const CARD32*>(it->value.data.data());
|
||||
if (type == _NET_WM_WINDOW_TYPE_NORMAL)
|
||||
info.type = WindowType::Normal;
|
||||
else if (type == _NET_WM_WINDOW_TYPE_SPLASH || type == _NET_WM_WINDOW_TYPE_DIALOG)
|
||||
info.type = WindowType::Utility;
|
||||
else
|
||||
info.type = WindowType::Popup;
|
||||
}
|
||||
wm_window_type_done:
|
||||
|
||||
if (auto it = window.properties.find(WM_TRANSIENT_FOR); it != window.properties.end())
|
||||
{
|
||||
if (it->value.type != WINDOW || it->value.data.size() != sizeof(CARD32))
|
||||
goto transitient_for_done;
|
||||
|
||||
const CARD32 wid = *reinterpret_cast<const CARD32*>(it->value.data.data());
|
||||
|
||||
auto it2 = g_objects.find(wid);
|
||||
if (it2 == g_objects.end())
|
||||
goto transitient_for_done;
|
||||
if (it2->value->type != Object::Type::Window)
|
||||
goto transitient_for_done;
|
||||
|
||||
// FIXME: support child windows
|
||||
auto& window = it2->value->object.get<Object::Window>();
|
||||
info.parent = window.platform_window.ptr();
|
||||
}
|
||||
transitient_for_done:
|
||||
|
||||
return info;
|
||||
const CARD32 type = *reinterpret_cast<const CARD32*>(it->value.data.data());
|
||||
if (type == _NET_WM_WINDOW_TYPE_NORMAL)
|
||||
return WindowType::Normal;
|
||||
if (type == _NET_WM_WINDOW_TYPE_SPLASH || type == _NET_WM_WINDOW_TYPE_DIALOG)
|
||||
return WindowType::Utility;
|
||||
return WindowType::Popup;
|
||||
}
|
||||
|
||||
static BAN::ErrorOr<void> map_window(Client& client_info, WINDOW wid)
|
||||
@@ -527,10 +531,13 @@ static BAN::ErrorOr<void> map_window(Client& client_info, WINDOW wid)
|
||||
if (window.width <= 10 || window.height <= 10)
|
||||
return {};
|
||||
|
||||
auto info = get_plaform_window_info(window);
|
||||
TRY(window.double_buffer.resize(window.width * window.height));
|
||||
for (auto& pixel : window.double_buffer)
|
||||
pixel = window.background;
|
||||
|
||||
const auto type = get_plaform_window_info(window);
|
||||
window.platform_window = TRY(g_platform_ops.create_window(
|
||||
info.parent,
|
||||
info.type,
|
||||
type,
|
||||
wid,
|
||||
window.x,
|
||||
window.y,
|
||||
@@ -574,19 +581,7 @@ static BAN::ErrorOr<void> map_window(Client& client_info, WINDOW wid)
|
||||
if (is_visible(window.parent))
|
||||
TRY(send_visibility_events_recursively(client_info, wid, true));
|
||||
|
||||
{
|
||||
xEvent event = { .u = {
|
||||
.expose = {
|
||||
.window = wid,
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
.width = static_cast<CARD16>(window.width),
|
||||
.height = static_cast<CARD16>(window.height),
|
||||
}
|
||||
}};
|
||||
event.u.u.type = Expose;
|
||||
TRY(window.send_event(event, ExposureMask));
|
||||
}
|
||||
TRY(send_exposure_events_recursive(wid));
|
||||
|
||||
return {};
|
||||
}
|
||||
@@ -602,8 +597,8 @@ static BAN::ErrorOr<void> unmap_window(Client& client_info, WINDOW wid)
|
||||
|
||||
window.mapped = false;
|
||||
|
||||
if (window.platform_window)
|
||||
window.platform_window.clear();
|
||||
window.double_buffer.clear();
|
||||
window.platform_window.clear();
|
||||
|
||||
if (is_visible(window.parent))
|
||||
TRY(send_visibility_events_recursively(client_info, wid, false));
|
||||
@@ -755,7 +750,7 @@ void update_cursor(WINDOW wid, int32_t x, int32_t y)
|
||||
if (wid == None)
|
||||
return;
|
||||
|
||||
const CURSOR cid = [&wid]() -> CURSOR {
|
||||
const CURSOR cid = [](WINDOW wid) -> CURSOR {
|
||||
for (;;)
|
||||
{
|
||||
const auto& window = g_objects[wid]->object.get<Object::Window>();
|
||||
@@ -763,7 +758,7 @@ void update_cursor(WINDOW wid, int32_t x, int32_t y)
|
||||
return window.cursor;
|
||||
wid = window.parent;
|
||||
}
|
||||
}();
|
||||
}(wid);
|
||||
|
||||
static CURSOR active_cid = None;
|
||||
if (cid == active_cid)
|
||||
@@ -861,8 +856,8 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
||||
|
||||
dprintln("CreateWindow");
|
||||
dprintln(" depth: {}", request.depth);
|
||||
dprintln(" wid: {}", request.wid);
|
||||
dprintln(" parent: {}", request.parent);
|
||||
dprintln(" wid: {h}", request.wid);
|
||||
dprintln(" parent: {h}", request.parent);
|
||||
dprintln(" x: {}", request.x);
|
||||
dprintln(" y: {}", request.y);
|
||||
dprintln(" width: {}", request.width);
|
||||
@@ -988,7 +983,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
||||
auto request = decode<xChangeWindowAttributesReq>(packet).value();
|
||||
|
||||
dprintln("ChangeWindowAttributes");
|
||||
dprintln(" window: {}", request.window);
|
||||
dprintln(" window: {h}", request.window);
|
||||
dprintln(" valueMask: {8h}", request.valueMask);
|
||||
|
||||
auto& window = TRY_REF(get_window(client_info, request.window, opcode));
|
||||
@@ -1047,7 +1042,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
||||
const CARD32 wid = packet.as_span<const uint32_t>()[1];
|
||||
|
||||
dprintln("GetWindowAttributes");
|
||||
dprintln(" window: {}", wid);
|
||||
dprintln(" window: {h}", wid);
|
||||
|
||||
const auto& window = TRY_REF(get_window(client_info, wid, opcode));
|
||||
|
||||
@@ -1084,7 +1079,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
||||
const CARD32 wid = packet.as_span<const uint32_t>()[1];
|
||||
|
||||
dprintln("DestroyWinow");
|
||||
dprintln(" window: {}", wid);
|
||||
dprintln(" window: {h}", wid);
|
||||
|
||||
(void)TRY_REF(get_window(client_info, wid, opcode));
|
||||
TRY(destroy_window(client_info, wid));
|
||||
@@ -1096,8 +1091,8 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
||||
auto request = decode<xReparentWindowReq>(packet).value();
|
||||
|
||||
dprintln("ReparentWinow");
|
||||
dprintln(" window: {}", request.window);
|
||||
dprintln(" parent: {}", request.parent);
|
||||
dprintln(" window: {h}", request.window);
|
||||
dprintln(" parent: {h}", request.parent);
|
||||
dprintln(" x: {}", request.x);
|
||||
dprintln(" y: {}", request.y);
|
||||
|
||||
@@ -1167,7 +1162,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
||||
const CARD32 wid = packet.as_span<const uint32_t>()[1];
|
||||
|
||||
dprintln("MapWindow");
|
||||
dprintln(" window: {}", wid);
|
||||
dprintln(" window: {h}", wid);
|
||||
|
||||
(void)TRY_REF(get_window(client_info, wid, opcode));
|
||||
TRY(map_window(client_info, wid));
|
||||
@@ -1179,7 +1174,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
||||
const CARD32 wid = packet.as_span<const uint32_t>()[1];
|
||||
|
||||
dprintln("MapSubwindows");
|
||||
dprintln(" window: {}", wid);
|
||||
dprintln(" window: {h}", wid);
|
||||
|
||||
const auto& window = TRY_REF(get_window(client_info, wid, opcode));
|
||||
for (auto child_wid : window.children)
|
||||
@@ -1192,7 +1187,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
||||
const CARD32 wid = packet.as_span<const uint32_t>()[1];
|
||||
|
||||
dprintln("UnmapWindow");
|
||||
dprintln(" window: {}", wid);
|
||||
dprintln(" window: {h}", wid);
|
||||
|
||||
(void)TRY_REF(get_window(client_info, wid, opcode));
|
||||
TRY(unmap_window(client_info, wid));
|
||||
@@ -1204,7 +1199,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
||||
const CARD32 wid = packet.as_span<const uint32_t>()[1];
|
||||
|
||||
dprintln("UnmapSubwindows");
|
||||
dprintln(" window: {}", wid);
|
||||
dprintln(" window: {h}", wid);
|
||||
|
||||
const auto& window = TRY_REF(get_window(client_info, wid, opcode));
|
||||
for (auto child_wid : window.children)
|
||||
@@ -1217,7 +1212,8 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
||||
auto request = decode<xConfigureWindowReq>(packet).value();
|
||||
|
||||
dprintln("ConfigureWindow");
|
||||
dprintln(" window: {}", request.window);
|
||||
dprintln(" window: {h}", request.window);
|
||||
dprintln(" mask: {4h}", request.mask);
|
||||
|
||||
auto& window = TRY_REF(get_window(client_info, request.window, opcode));
|
||||
|
||||
@@ -1226,7 +1222,6 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
||||
uint32_t new_width = window.width;
|
||||
uint32_t new_height = window.height;
|
||||
|
||||
dprintln(" mask:");
|
||||
for (size_t i = 0; i < 7; i++)
|
||||
{
|
||||
if (!(request.mask & (1 << i)))
|
||||
@@ -1238,15 +1233,19 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
||||
{
|
||||
case 0:
|
||||
new_x = value;
|
||||
dprintln(" x: {}", value);
|
||||
break;
|
||||
case 1:
|
||||
new_y = value;
|
||||
dprintln(" y: {}", value);
|
||||
break;
|
||||
case 2:
|
||||
new_width = value;
|
||||
dprintln(" w: {}", value);
|
||||
break;
|
||||
case 3:
|
||||
new_height = value;
|
||||
dprintln(" h: {}", value);
|
||||
break;
|
||||
default:
|
||||
dprintln(" {4h}: {4h}", 1 << i, value);
|
||||
@@ -1254,7 +1253,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
||||
}
|
||||
}
|
||||
|
||||
bool send_configure = false;
|
||||
bool should_send_configure_notify = false;
|
||||
|
||||
if (new_x != window.x || new_y != window.y)
|
||||
{
|
||||
@@ -1267,7 +1266,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
||||
{
|
||||
window.x = new_x;
|
||||
window.y = new_y;
|
||||
send_configure = true;
|
||||
should_send_configure_notify = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1286,52 +1285,17 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
||||
|
||||
window.width = new_width;
|
||||
window.height = new_height;
|
||||
send_configure = true;
|
||||
should_send_configure_notify = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!send_configure)
|
||||
if (!should_send_configure_notify)
|
||||
break;
|
||||
|
||||
{
|
||||
xEvent event = { .u = {
|
||||
.configureNotify = {
|
||||
.event = request.window,
|
||||
.window = request.window,
|
||||
.aboveSibling = xFalse,
|
||||
.x = static_cast<INT16>(window.x),
|
||||
.y = static_cast<INT16>(window.y),
|
||||
.width = static_cast<CARD16>(window.width),
|
||||
.height = static_cast<CARD16>(window.height),
|
||||
.borderWidth = 0,
|
||||
.override = xFalse,
|
||||
}
|
||||
}};
|
||||
event.u.u.type = ConfigureNotify;
|
||||
TRY(window.send_event(event, StructureNotifyMask));
|
||||
}
|
||||
TRY(send_configure_notify(request.window));
|
||||
|
||||
auto& parent_object = *g_objects[window.parent];
|
||||
ASSERT(parent_object.type == Object::Type::Window);
|
||||
auto& parent_window = parent_object.object.get<Object::Window>();
|
||||
|
||||
{
|
||||
xEvent event = { .u = {
|
||||
.configureNotify = {
|
||||
.event = window.parent,
|
||||
.window = request.window,
|
||||
.aboveSibling = xFalse,
|
||||
.x = static_cast<INT16>(window.x),
|
||||
.y = static_cast<INT16>(window.y),
|
||||
.width = static_cast<CARD16>(window.width),
|
||||
.height = static_cast<CARD16>(window.height),
|
||||
.borderWidth = 0,
|
||||
.override = xFalse,
|
||||
}
|
||||
}};
|
||||
event.u.u.type = ConfigureNotify;
|
||||
TRY(parent_window.send_event(event, SubstructureNotifyMask));
|
||||
}
|
||||
if (is_visible(request.window))
|
||||
TRY(send_exposure_events_recursive(request.window));
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -1340,7 +1304,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
||||
const CARD32 drawable_id = packet.as_span<const uint32_t>()[1];
|
||||
|
||||
dprintln("GetGeometry");
|
||||
dprintln(" drawable: {}", drawable_id);
|
||||
dprintln(" drawable: {h}", drawable_id);
|
||||
|
||||
auto it = g_objects.find(drawable_id);
|
||||
if (it == g_objects.end() || (it->value->type != Object::Type::Window && it->value->type != Object::Type::Pixmap))
|
||||
@@ -1363,15 +1327,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
||||
CARD16 width, height;
|
||||
CARD8 depth;
|
||||
|
||||
if (drawable_id == g_root.windowId)
|
||||
{
|
||||
width = g_root.pixWidth;
|
||||
height = g_root.pixHeight;
|
||||
depth = g_root.rootDepth;
|
||||
x = 0;
|
||||
y = 0;
|
||||
}
|
||||
else if (drawable.type == Object::Type::Window)
|
||||
if (drawable.type == Object::Type::Window)
|
||||
{
|
||||
const auto& window = drawable.object.get<Object::Window>();
|
||||
width = window.width;
|
||||
@@ -1415,7 +1371,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
||||
const auto wid = packet.as_span<const CARD32>()[1];
|
||||
|
||||
dprintln("QueryTree");
|
||||
dprintln(" window: {}", wid);
|
||||
dprintln(" window: {h}", wid);
|
||||
|
||||
const auto& window = TRY_REF(get_window(client_info, wid, opcode));
|
||||
|
||||
@@ -1499,7 +1455,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
||||
|
||||
dprintln("ChangeProperty");
|
||||
dprintln(" mode: {}", request.mode);
|
||||
dprintln(" window: {}", request.window);
|
||||
dprintln(" window: {h}", request.window);
|
||||
dprintln(" property: {}", g_atoms_id_to_name[request.property]);
|
||||
dprintln(" type: {}", g_atoms_id_to_name[request.type]);
|
||||
dprintln(" format: {}", request.format);
|
||||
@@ -1564,7 +1520,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
||||
auto request = decode<xDeletePropertyReq>(packet).value();
|
||||
|
||||
dprintln("DeleteProperty");
|
||||
dprintln(" window: {}", request.window);
|
||||
dprintln(" window: {h}", request.window);
|
||||
dprintln(" property: {}", g_atoms_id_to_name[request.property]);
|
||||
|
||||
auto& window = TRY_REF(get_window(client_info, request.window, opcode));
|
||||
@@ -1594,7 +1550,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
||||
|
||||
dprintln("GetProperty");
|
||||
dprintln(" c_delete: {}", request.c_delete);
|
||||
dprintln(" window: {}", request.window);
|
||||
dprintln(" window: {h}", request.window);
|
||||
dprintln(" property: {}", g_atoms_id_to_name[request.property]);
|
||||
dprintln(" type: {}", request.type);
|
||||
dprintln(" longOffset: {}", request.longOffset);
|
||||
@@ -1677,7 +1633,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
||||
const CARD32 wid = packet.as_span<const uint32_t>()[1];
|
||||
|
||||
dprintln("ListProperties");
|
||||
dprintln(" window: {}", wid);
|
||||
dprintln(" window: {h}", wid);
|
||||
|
||||
const auto& window = TRY_REF(get_window(client_info, wid, opcode));
|
||||
|
||||
@@ -1701,7 +1657,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
||||
auto request = decode<xSetSelectionOwnerReq>(packet).value();
|
||||
|
||||
dprintln("SetSelectionOwner");
|
||||
dprintln(" window: {}", request.window);
|
||||
dprintln(" window: {h}", request.window);
|
||||
dprintln(" selection: {}", g_atoms_id_to_name[request.selection]);
|
||||
dprintln(" time: {}", request.time);
|
||||
|
||||
@@ -1757,7 +1713,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
||||
auto request = decode<xConvertSelectionReq>(packet).value();
|
||||
|
||||
dprintln("ConvertSelection");
|
||||
dprintln(" requestor: {}", request.requestor);
|
||||
dprintln(" requestor: {h}", request.requestor);
|
||||
dprintln(" selection: {}", get_atom_name_safe(request.selection));
|
||||
dprintln(" target: {}", get_atom_name_safe(request.target));
|
||||
dprintln(" property: {}", get_atom_name_safe(request.property));
|
||||
@@ -1844,8 +1800,8 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
||||
|
||||
dprintln("GrabPointer");
|
||||
dprintln(" ownerEvents: {}", request.ownerEvents);
|
||||
dprintln(" grabWindow: {}", request.grabWindow);
|
||||
dprintln(" eventMask: {}", request.eventMask);
|
||||
dprintln(" grabWindow: {h}", request.grabWindow);
|
||||
dprintln(" eventMask: {h}", request.eventMask);
|
||||
dprintln(" pointerMode: {}", request.pointerMode);
|
||||
dprintln(" keyboardMode: {}", request.keyboardMode);
|
||||
dprintln(" confineTo: {}", request.confineTo);
|
||||
@@ -1911,7 +1867,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
||||
|
||||
dprintln("GrabKeyboard");
|
||||
dprintln(" ownerEvents: {}", request.ownerEvents);
|
||||
dprintln(" grabWindow: {}", request.grabWindow);
|
||||
dprintln(" grabWindow: {h}", request.grabWindow);
|
||||
dprintln(" pointerMode: {}", request.pointerMode);
|
||||
dprintln(" keyboardMode: {}", request.keyboardMode);
|
||||
dprintln(" time: {}", request.time);
|
||||
@@ -1986,7 +1942,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
||||
const CARD32 wid = packet.as_span<const uint32_t>()[1];
|
||||
|
||||
dprintln("QueryPointer");
|
||||
dprintln(" window: {}", wid);
|
||||
dprintln(" window: {h}", wid);
|
||||
|
||||
const auto& window = TRY_REF(get_window(client_info, wid, opcode));
|
||||
|
||||
@@ -2033,8 +1989,8 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
||||
auto request = decode<xTranslateCoordsReq>(packet).value();
|
||||
|
||||
dprintln("TranslateCoords");
|
||||
dprintln(" src_wid: {}", request.srcWid);
|
||||
dprintln(" dst_wid: {}", request.dstWid);
|
||||
dprintln(" src_wid: {h}", request.srcWid);
|
||||
dprintln(" dst_wid: {h}", request.dstWid);
|
||||
dprintln(" src_x: {}", request.srcX);
|
||||
dprintln(" src_y: {}", request.srcY);
|
||||
|
||||
@@ -2062,12 +2018,12 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
||||
auto request = decode<xWarpPointerReq>(packet).value();
|
||||
|
||||
dprintln("WarpPointer");
|
||||
dprintln(" src_wid: {}", request.srcWid);
|
||||
dprintln(" src_wid: {h}", request.srcWid);
|
||||
dprintln(" src_x: {}", request.srcX);
|
||||
dprintln(" src_y: {}", request.srcY);
|
||||
dprintln(" src_w: {}", request.srcWidth);
|
||||
dprintln(" src_h: {}", request.srcHeight);
|
||||
dprintln(" dst_wid: {}", request.dstWid);
|
||||
dprintln(" dst_wid: {h}", request.dstWid);
|
||||
dprintln(" dst_x: {}", request.dstX);
|
||||
dprintln(" dst_y: {}", request.dstY);
|
||||
|
||||
@@ -2137,8 +2093,8 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
||||
|
||||
dprintln("CreatePixmap");
|
||||
dprintln(" depth: {}", request.depth);
|
||||
dprintln(" pid: {}", request.pid);
|
||||
dprintln(" drawable: {}", request.drawable);
|
||||
dprintln(" pid: {h}", request.pid);
|
||||
dprintln(" drawable: {h}", request.drawable);
|
||||
dprintln(" width: {}", request.width);
|
||||
dprintln(" height: {}", request.height);
|
||||
|
||||
@@ -2172,7 +2128,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
||||
const CARD32 pid = packet.as_span<const uint32_t>()[1];
|
||||
|
||||
dprintln("FreePixmap");
|
||||
dprintln(" pixmap: {}", pid);
|
||||
dprintln(" pixmap: {h}", pid);
|
||||
|
||||
(void)TRY_REF(get_pixmap(client_info, pid, opcode));
|
||||
client_info.objects.remove(pid);
|
||||
@@ -2185,14 +2141,14 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
||||
auto request = decode<xCreateGCReq>(packet).value();
|
||||
|
||||
dprintln("CreateGC");
|
||||
dprintln(" drawable {}", request.drawable);
|
||||
dprintln(" drawable {h}", request.drawable);
|
||||
dprintln(" gc {}", request.gc);
|
||||
dprintln(" mask {8h}", request.mask);
|
||||
|
||||
// TODO: support invisible background
|
||||
|
||||
uint32_t foreground = 0x000000;
|
||||
uint32_t background = 0x000000;
|
||||
uint32_t background = 0xFFFFFF;
|
||||
uint16_t line_width = 0;
|
||||
uint32_t font = None;
|
||||
bool graphics_exposures = true;
|
||||
@@ -2267,7 +2223,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
||||
auto request = decode<xChangeGCReq>(packet).value();
|
||||
|
||||
dprintln("ChangeGC");
|
||||
dprintln(" gc: {}", request.gc);
|
||||
dprintln(" gc: {h}", request.gc);
|
||||
dprintln(" mask: {8h}", request.mask);
|
||||
|
||||
auto& object = *g_objects[request.gc];
|
||||
@@ -2331,7 +2287,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
||||
auto request = decode<xSetClipRectanglesReq>(packet).value();
|
||||
|
||||
dprintln("SetClipRectangles");
|
||||
dprintln(" gc: {}", request.gc);
|
||||
dprintln(" gc: {h}", request.gc);
|
||||
dprintln(" ordering: {}", request.ordering);
|
||||
dprintln(" xOrigin: {}", request.xOrigin);
|
||||
dprintln(" yOrigin: {}", request.yOrigin);
|
||||
@@ -2359,7 +2315,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
||||
const CARD32 gc = packet.as_span<const uint32_t>()[1];
|
||||
|
||||
dprintln("FreeGC");
|
||||
dprintln(" gc: {}", gc);
|
||||
dprintln(" gc: {h}", gc);
|
||||
|
||||
(void)TRY_REF(get_gc(client_info, gc, opcode));
|
||||
client_info.objects.remove(gc);
|
||||
@@ -2373,7 +2329,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
||||
|
||||
dprintln("ClearArea");
|
||||
dprintln(" exposures: {}", request.exposures);
|
||||
dprintln(" window: {}", request.window);
|
||||
dprintln(" window: {h}", request.window);
|
||||
dprintln(" x: {}", request.x);
|
||||
dprintln(" y: {}", request.y);
|
||||
dprintln(" width: {}", request.width);
|
||||
@@ -2407,9 +2363,9 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
||||
auto request = decode<xCopyAreaReq>(packet).value();
|
||||
|
||||
dprintln("CopyArea");
|
||||
dprintln(" srcDrawable: {}", request.srcDrawable);
|
||||
dprintln(" dstDrawable: {}", request.dstDrawable);
|
||||
dprintln(" gc: {}", request.gc);
|
||||
dprintln(" srcDrawable: {h}", request.srcDrawable);
|
||||
dprintln(" dstDrawable: {h}", request.dstDrawable);
|
||||
dprintln(" gc: {h}", request.gc);
|
||||
dprintln(" srcX: {}", request.srcX);
|
||||
dprintln(" srcY: {}", request.srcY);
|
||||
dprintln(" dstX: {}", request.dstX);
|
||||
@@ -2502,8 +2458,8 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
||||
auto request = decode<xPutImageReq>(packet).value();
|
||||
|
||||
dprintln("PutImage");
|
||||
dprintln(" drawable: {}", request.drawable);
|
||||
dprintln(" gc: {}", request.gc);
|
||||
dprintln(" drawable: {h}", request.drawable);
|
||||
dprintln(" gc: {h}", request.gc);
|
||||
dprintln(" format: {}", request.format);
|
||||
dprintln(" depth: {}", request.depth);
|
||||
dprintln(" dstX: {}", request.dstX);
|
||||
@@ -2551,7 +2507,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
||||
auto request = decode<xGetImageReq>(packet).value();
|
||||
|
||||
dprintln("GetImage");
|
||||
dprintln(" drawable: {}", request.drawable);
|
||||
dprintln(" drawable: {h}", request.drawable);
|
||||
dprintln(" format: {}", request.format);
|
||||
dprintln(" x: {}", request.x);
|
||||
dprintln(" y: {}", request.y);
|
||||
@@ -2722,7 +2678,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
||||
auto request = decode<xCreateCursorReq>(packet).value();
|
||||
|
||||
dprintln("CreateCursor");
|
||||
dprintln(" cid: {}", request.cid);
|
||||
dprintln(" cid: {h}", request.cid);
|
||||
dprintln(" source: {}", request.source);
|
||||
dprintln(" mask: {}", request.mask);
|
||||
dprintln(" foreRed: {}", request.foreRed);
|
||||
@@ -2793,7 +2749,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
||||
const auto cid = packet.as_span<const uint32_t>()[1];
|
||||
|
||||
dprintln("FreeCursor");
|
||||
dprintln(" cid: {}", cid);
|
||||
dprintln(" cid: {h}", cid);
|
||||
|
||||
client_info.objects.remove(cid);
|
||||
g_objects.remove(cid);
|
||||
@@ -2806,7 +2762,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
||||
|
||||
dprintln("QueryBestSize");
|
||||
dprintln(" class: {}", request.c_class);
|
||||
dprintln(" drawable: {}", request.drawable);
|
||||
dprintln(" drawable: {h}", request.drawable);
|
||||
dprintln(" width: {}", request.width);
|
||||
dprintln(" height: {}", request.height);
|
||||
|
||||
|
||||
@@ -6,7 +6,9 @@ BAN::ErrorOr<void> setup_client_conneciton(Client& client_info, const xConnClien
|
||||
BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet);
|
||||
|
||||
void invalidate_window(WINDOW wid, int32_t x, int32_t y, int32_t w, int32_t h);
|
||||
void send_exposure_recursive(WINDOW wid);
|
||||
|
||||
BAN::ErrorOr<void> send_configure_notify(WINDOW wid);
|
||||
BAN::ErrorOr<void> send_exposure_events_recursive(WINDOW wid);
|
||||
|
||||
void update_cursor(WINDOW wid, int32_t x, int32_t y);
|
||||
|
||||
@@ -16,7 +18,8 @@ WINDOW find_child_window(WINDOW wid, int32_t& x, int32_t& y);
|
||||
|
||||
xPoint get_window_position(WINDOW wid);
|
||||
|
||||
static constexpr uint32_t COLOR_INVISIBLE = 0x69000000;
|
||||
// random number with alpha 0 :D
|
||||
static constexpr uint32_t COLOR_INVISIBLE = 0x00b205AF;
|
||||
|
||||
extern CARD16 g_keymask;
|
||||
extern CARD16 g_butmask;
|
||||
|
||||
@@ -13,6 +13,8 @@ set(XBANAN_SOURCES
|
||||
SafeGetters.cpp
|
||||
)
|
||||
|
||||
set(FONT_PATH ${CMAKE_SOURCE_DIR}/fonts CACHE STRING "path to X11 fonts")
|
||||
|
||||
option(ENABLE_GLX "enable glx extension" ON)
|
||||
if(ENABLE_GLX)
|
||||
list(APPEND XBANAN_SOURCES ExtGLX.cpp)
|
||||
@@ -23,13 +25,6 @@ if(ENABLE_SHM)
|
||||
list(APPEND XBANAN_SOURCES ExtSHM.cpp)
|
||||
endif()
|
||||
|
||||
set(PLATFORM "banan-os" CACHE STRING "target platform")
|
||||
|
||||
set(VALID_PLATFORMS "banan-os" "SDL3")
|
||||
if(NOT PLATFORM IN_LIST VALID_PLATFORMS)
|
||||
message(FATAL_ERROR "platform \"${PLATFORM}\" not known, valid platforms are ${VALID_PLATFORMS}")
|
||||
endif()
|
||||
|
||||
if(PLATFORM STREQUAL "banan-os")
|
||||
list(APPEND XBANAN_SOURCES banan-os/banan-os.cpp)
|
||||
elseif(PLATFORM STREQUAL "SDL3")
|
||||
@@ -40,6 +35,8 @@ add_executable(xbanan ${XBANAN_SOURCES})
|
||||
banan_link_library(xbanan ban)
|
||||
banan_link_library(xbanan libdeflate)
|
||||
|
||||
target_compile_definitions(xbanan PRIVATE FONT_PATH="${FONT_PATH}")
|
||||
|
||||
if(PLATFORM STREQUAL "banan-os")
|
||||
banan_link_library(xbanan libgui)
|
||||
banan_link_library(xbanan libinput)
|
||||
@@ -56,7 +53,4 @@ target_compile_options(xbanan PRIVATE
|
||||
-Wno-unused-but-set-variable
|
||||
)
|
||||
|
||||
#target_compile_options(xbanan PRIVATE -fsanitize=address)
|
||||
#target_link_options(xbanan PRIVATE -fsanitize=address)
|
||||
|
||||
install(TARGETS xbanan OPTIONAL)
|
||||
|
||||
@@ -66,8 +66,11 @@ struct Object
|
||||
|
||||
uint32_t background { 0 };
|
||||
|
||||
bool platform_window_invalidated { false };
|
||||
BAN::UniqPtr<PlatformWindow> platform_window;
|
||||
|
||||
BAN::Vector<uint32_t> double_buffer;
|
||||
|
||||
BAN::HashMap<Client*, uint32_t> event_masks;
|
||||
|
||||
BAN::HashMap<ATOM, Property> properties;
|
||||
@@ -161,6 +164,12 @@ struct EpollThingy
|
||||
BAN::Variant<Client, void*> value;
|
||||
};
|
||||
|
||||
struct DisplayInfo
|
||||
{
|
||||
int32_t x, y;
|
||||
uint32_t w, h;
|
||||
};
|
||||
|
||||
extern const xPixmapFormat g_formats[6];
|
||||
extern const xDepth g_depth;
|
||||
extern const xVisualType g_visual;
|
||||
@@ -176,3 +185,7 @@ extern int g_epoll_fd;
|
||||
extern BAN::HashMap<int, EpollThingy> g_epoll_thingies;
|
||||
|
||||
extern int g_server_grabber_fd;
|
||||
|
||||
extern BAN::Vector<DisplayInfo> g_displays;
|
||||
|
||||
extern CARD32 g_next_global_id;
|
||||
|
||||
@@ -107,7 +107,7 @@ BAN::ErrorOr<void> poly_line(Client& client_info, BAN::ConstByteSpan packet)
|
||||
auto request = decode<xPolyLineReq>(packet).value();
|
||||
|
||||
dprintln("PolyLine");
|
||||
dprintln(" drawable: {}", request.drawable);
|
||||
dprintln(" drawable: {h}", request.drawable);
|
||||
dprintln(" gc: {}", request.gc);
|
||||
dprintln(" coordMode: {}", request.coordMode);
|
||||
|
||||
@@ -161,7 +161,7 @@ BAN::ErrorOr<void> poly_segment(Client& client_info, BAN::ConstByteSpan packet)
|
||||
auto request = decode<xPolySegmentReq>(packet).value();
|
||||
|
||||
dprintln("PolySegment");
|
||||
dprintln(" drawable: {}", request.drawable);
|
||||
dprintln(" drawable: {h}", request.drawable);
|
||||
dprintln(" gc: {}", request.gc);
|
||||
|
||||
auto [out_data_u32, out_w, out_h, _] = TRY(get_drawable_info(client_info, request.drawable, X_PolySegment));
|
||||
@@ -203,7 +203,7 @@ BAN::ErrorOr<void> fill_poly(Client& client_info, BAN::ConstByteSpan packet)
|
||||
auto request = decode<xFillPolyReq>(packet).value();
|
||||
|
||||
dprintln("FillPoly");
|
||||
dprintln(" drawable: {}", request.drawable);
|
||||
dprintln(" drawable: {h}", request.drawable);
|
||||
dprintln(" gc: {}", request.gc);
|
||||
dprintln(" shape: {}", request.shape);
|
||||
dprintln(" coordMode: {}", request.coordMode);
|
||||
@@ -278,7 +278,7 @@ BAN::ErrorOr<void> poly_fill_rectangle(Client& client_info, BAN::ConstByteSpan p
|
||||
auto request = decode<xPolyFillRectangleReq>(packet).value();
|
||||
|
||||
dprintln("PolyFillRectangle");
|
||||
dprintln(" drawable: {}", request.drawable);
|
||||
dprintln(" drawable: {h}", request.drawable);
|
||||
dprintln(" gc: {}", request.gc);
|
||||
|
||||
auto [out_data_u32, out_w, out_h, _] = TRY(get_drawable_info(client_info, request.drawable, X_PolyFillRectangle));
|
||||
@@ -320,7 +320,7 @@ BAN::ErrorOr<void> poly_fill_arc(Client& client_info, BAN::ConstByteSpan packet)
|
||||
auto request = decode<xPolyFillArcReq>(packet).value();
|
||||
|
||||
dprintln("PolyFillArc");
|
||||
dprintln(" drawable: {}", request.drawable);
|
||||
dprintln(" drawable: {h}", request.drawable);
|
||||
dprintln(" gc: {}", request.gc);
|
||||
|
||||
auto [out_data_32, out_w, out_h, _] = TRY(get_drawable_info(client_info, request.drawable, X_PolyFillArc));
|
||||
|
||||
@@ -75,69 +75,26 @@ void on_window_close_event(WINDOW wid)
|
||||
}
|
||||
}
|
||||
|
||||
static void send_window_configure(WINDOW wid, Object::Window& window)
|
||||
{
|
||||
{
|
||||
xEvent event = { .u = {
|
||||
.configureNotify = {
|
||||
.event = wid,
|
||||
.window = wid,
|
||||
.aboveSibling = xFalse,
|
||||
.x = static_cast<INT16>(window.x),
|
||||
.y = static_cast<INT16>(window.y),
|
||||
.width = static_cast<CARD16>(window.width),
|
||||
.height = static_cast<CARD16>(window.height),
|
||||
.borderWidth = 0,
|
||||
.override = xFalse,
|
||||
}
|
||||
}};
|
||||
event.u.u.type = ConfigureNotify;
|
||||
MUST(window.send_event(event, StructureNotifyMask));
|
||||
}
|
||||
|
||||
auto& parent_object = *g_objects[window.parent];
|
||||
ASSERT(parent_object.type == Object::Type::Window);
|
||||
auto& parent_window = parent_object.object.get<Object::Window>();
|
||||
|
||||
{
|
||||
xEvent event = { .u = {
|
||||
.configureNotify = {
|
||||
.event = window.parent,
|
||||
.window = wid,
|
||||
.aboveSibling = xFalse,
|
||||
.x = static_cast<INT16>(window.x),
|
||||
.y = static_cast<INT16>(window.y),
|
||||
.width = static_cast<CARD16>(window.width),
|
||||
.height = static_cast<CARD16>(window.height),
|
||||
.borderWidth = 0,
|
||||
.override = xFalse,
|
||||
}
|
||||
}};
|
||||
event.u.u.type = ConfigureNotify;
|
||||
MUST(parent_window.send_event(event, SubstructureNotifyMask));
|
||||
}
|
||||
}
|
||||
|
||||
void on_window_resize_event(WINDOW wid, uint32_t new_width, uint32_t new_height)
|
||||
{
|
||||
auto& object = *g_objects[wid];
|
||||
ASSERT(object.type == Object::Type::Window);
|
||||
auto& window = object.object.get<Object::Window>();
|
||||
|
||||
{
|
||||
window.width = new_width;
|
||||
window.height = new_height;
|
||||
window.width = new_width;
|
||||
window.height = new_height;
|
||||
|
||||
MUST(window.pixels.resize(new_width * new_height));
|
||||
for (auto& pixel : window.pixels)
|
||||
pixel = window.background;
|
||||
}
|
||||
MUST(window.pixels.resize(new_width * new_height));
|
||||
for (auto& pixel : window.pixels)
|
||||
pixel = window.background;
|
||||
|
||||
send_window_configure(wid, window);
|
||||
MUST(window.double_buffer.resize(new_width * new_height));
|
||||
for (auto& pixel : window.double_buffer)
|
||||
pixel = window.background;
|
||||
|
||||
send_exposure_recursive(wid);
|
||||
MUST(send_configure_notify(wid));
|
||||
|
||||
invalidate_window(wid, 0, 0, window.width, window.height);
|
||||
MUST(send_exposure_events_recursive(wid));
|
||||
}
|
||||
|
||||
void on_window_move_event(WINDOW wid, int32_t x, int32_t y)
|
||||
@@ -149,7 +106,7 @@ void on_window_move_event(WINDOW wid, int32_t x, int32_t y)
|
||||
window.x = x;
|
||||
window.y = y;
|
||||
|
||||
send_window_configure(wid, window);
|
||||
MUST(send_configure_notify(wid));
|
||||
}
|
||||
|
||||
void on_window_focus_event(WINDOW wid, bool focused)
|
||||
|
||||
@@ -6,12 +6,64 @@
|
||||
|
||||
#include <time.h>
|
||||
|
||||
struct RANDRDisplay
|
||||
{
|
||||
CARD32 crtc_id;
|
||||
CARD32 output_id;
|
||||
CARD32 mode_id;
|
||||
ATOM name_atom;
|
||||
BAN::String output_str;
|
||||
BAN::String mode_str;
|
||||
const DisplayInfo& info;
|
||||
};
|
||||
|
||||
static BAN::Vector<RANDRDisplay> s_randr_displays;
|
||||
static CARD32 s_timestamp { 0 };
|
||||
|
||||
static void initialize_displays()
|
||||
{
|
||||
for (size_t i = 0; i < g_displays.size(); i++)
|
||||
{
|
||||
auto name = MUST(BAN::String::formatted("B-OUT-{}", i));
|
||||
|
||||
const auto name_atom = g_atom_value++;
|
||||
MUST(g_atoms_name_to_id.insert(name, name_atom));
|
||||
MUST(g_atoms_id_to_name.insert(name_atom, name));
|
||||
|
||||
MUST(s_randr_displays.push_back({
|
||||
.crtc_id = g_next_global_id++,
|
||||
.output_id = g_next_global_id++,
|
||||
.mode_id = g_next_global_id++,
|
||||
.name_atom = name_atom,
|
||||
.output_str = BAN::move(name),
|
||||
.mode_str = MUST(BAN::String::formatted("{}x{}", g_displays[i].w, g_displays[i].h)),
|
||||
.info = g_displays[i],
|
||||
}));
|
||||
}
|
||||
|
||||
s_timestamp = time(nullptr);
|
||||
}
|
||||
|
||||
static const RANDRDisplay& find_display_by_output(CARD32 output)
|
||||
{
|
||||
for (const auto& display : s_randr_displays)
|
||||
if (display.output_id == output)
|
||||
return display;
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
static const RANDRDisplay& find_display_by_crtc(CARD32 crtc)
|
||||
{
|
||||
for (const auto& display : s_randr_displays)
|
||||
if (display.crtc_id == crtc)
|
||||
return display;
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
static BAN::ErrorOr<void> extension_randr(Client& client_info, BAN::ConstByteSpan packet)
|
||||
{
|
||||
static CARD32 crtc_id = 5;
|
||||
static CARD32 output_id = 6;
|
||||
static CARD32 mode_id = 7;
|
||||
static CARD32 timestamp = time(nullptr);
|
||||
if (s_randr_displays.empty())
|
||||
initialize_displays();
|
||||
|
||||
static xRenderTransform transform {
|
||||
1 << 16, 0, 0,
|
||||
@@ -61,14 +113,14 @@ static BAN::ErrorOr<void> extension_randr(Client& client_info, BAN::ConstByteSpa
|
||||
.setOfRotations = RR_Rotate_0,
|
||||
.sequenceNumber = client_info.sequence,
|
||||
.length = 3,
|
||||
.root = g_root.windowId,
|
||||
.timestamp = timestamp,
|
||||
.configTimestamp = timestamp,
|
||||
.nSizes = 1,
|
||||
.sizeID = 0,
|
||||
.rotation = RR_Rotate_0,
|
||||
.rate = 60,
|
||||
.nrateEnts = 1,
|
||||
.root = g_root.windowId,
|
||||
.timestamp = s_timestamp,
|
||||
.configTimestamp = s_timestamp,
|
||||
.nSizes = 1,
|
||||
.sizeID = 0,
|
||||
.rotation = RR_Rotate_0,
|
||||
.rate = 60,
|
||||
.nrateEnts = 1,
|
||||
};
|
||||
TRY(encode(client_info.output_buffer, reply));
|
||||
|
||||
@@ -115,55 +167,63 @@ static BAN::ErrorOr<void> extension_randr(Client& client_info, BAN::ConstByteSpa
|
||||
dprintln("RRGetScreenResources{}", current ? "Current" : "");
|
||||
dprintln(" window: {}", request.window);
|
||||
|
||||
const auto mode_name = TRY(BAN::String::formatted("{}x{}", g_root.pixWidth, g_root.pixHeight));
|
||||
size_t mode_name_bytes = 0;
|
||||
for (const auto& display : s_randr_displays)
|
||||
mode_name_bytes += display.mode_str.size();
|
||||
|
||||
xRRGetScreenResourcesReply reply {
|
||||
.type = X_Reply,
|
||||
.sequenceNumber = client_info.sequence,
|
||||
.length = static_cast<CARD32>(1 + 1 + 8 + (mode_name.size() + 3) / 4),
|
||||
.timestamp = timestamp,
|
||||
.configTimestamp = timestamp,
|
||||
.nCrtcs = 1,
|
||||
.nOutputs = 1,
|
||||
.nModes = 1,
|
||||
.nbytesNames = static_cast<CARD16>(mode_name.size()),
|
||||
.length = static_cast<CARD32>(s_randr_displays.size() * (1 + 1 + 8) + (mode_name_bytes + 3) / 4),
|
||||
.timestamp = s_timestamp,
|
||||
.configTimestamp = s_timestamp,
|
||||
.nCrtcs = static_cast<CARD16>(s_randr_displays.size()),
|
||||
.nOutputs = static_cast<CARD16>(s_randr_displays.size()),
|
||||
.nModes = static_cast<CARD16>(s_randr_displays.size()),
|
||||
.nbytesNames = static_cast<CARD16>(mode_name_bytes),
|
||||
};
|
||||
TRY(encode(client_info.output_buffer, reply));
|
||||
|
||||
TRY(encode(client_info.output_buffer, crtc_id));
|
||||
for (const auto& display : s_randr_displays)
|
||||
TRY(encode(client_info.output_buffer, display.crtc_id));
|
||||
|
||||
TRY(encode(client_info.output_buffer, output_id));
|
||||
for (const auto& display : s_randr_displays)
|
||||
TRY(encode(client_info.output_buffer, display.output_id));
|
||||
|
||||
const CARD16 hsync_start = g_root.pixWidth;
|
||||
const CARD16 hsync_end = g_root.pixWidth + 1;
|
||||
const CARD16 htotal = g_root.pixWidth + 1;
|
||||
for (const auto& display : s_randr_displays)
|
||||
{
|
||||
const CARD16 hsync_start = display.info.w;
|
||||
const CARD16 hsync_end = display.info.w + 1;
|
||||
const CARD16 htotal = display.info.w + 1;
|
||||
|
||||
const CARD16 vsync_start = g_root.pixHeight;
|
||||
const CARD16 vsync_end = g_root.pixHeight + 1;
|
||||
const CARD16 vtotal = g_root.pixHeight + 1;
|
||||
const CARD16 vsync_start = display.info.h;
|
||||
const CARD16 vsync_end = display.info.h + 1;
|
||||
const CARD16 vtotal = display.info.h + 1;
|
||||
|
||||
const CARD32 clock = htotal * vtotal * 60;
|
||||
const CARD32 clock = htotal * vtotal * 60;
|
||||
|
||||
xRRModeInfo mode_info {
|
||||
.id = mode_id,
|
||||
.width = g_root.pixWidth,
|
||||
.height = g_root.pixHeight,
|
||||
.dotClock = clock,
|
||||
.hSyncStart = hsync_start,
|
||||
.hSyncEnd = hsync_end,
|
||||
.hTotal = htotal,
|
||||
.hSkew = 0,
|
||||
.vSyncStart = vsync_start,
|
||||
.vSyncEnd = vsync_end,
|
||||
.vTotal = vtotal,
|
||||
.nameLength = static_cast<CARD16>(mode_name.size()),
|
||||
.modeFlags = RR_HSyncPositive | RR_VSyncPositive,
|
||||
};
|
||||
TRY(encode(client_info.output_buffer, mode_info));
|
||||
xRRModeInfo mode_info {
|
||||
.id = display.mode_id,
|
||||
.width = static_cast<CARD16>(display.info.w),
|
||||
.height = static_cast<CARD16>(display.info.h),
|
||||
.dotClock = clock,
|
||||
.hSyncStart = hsync_start,
|
||||
.hSyncEnd = hsync_end,
|
||||
.hTotal = htotal,
|
||||
.hSkew = 0,
|
||||
.vSyncStart = vsync_start,
|
||||
.vSyncEnd = vsync_end,
|
||||
.vTotal = vtotal,
|
||||
.nameLength = static_cast<CARD16>(display.mode_str.size()),
|
||||
.modeFlags = RR_HSyncPositive | RR_VSyncPositive,
|
||||
};
|
||||
TRY(encode(client_info.output_buffer, mode_info));
|
||||
}
|
||||
|
||||
TRY(encode(client_info.output_buffer, mode_name));
|
||||
for (size_t i = 0; (mode_name.size() + i) % 4; i++)
|
||||
TRY(encode(client_info.output_buffer, '\0'));
|
||||
for (const auto& display : s_randr_displays)
|
||||
TRY(encode(client_info.output_buffer, display.mode_str));
|
||||
while (client_info.output_buffer.size() % 4)
|
||||
TRY(encode<BYTE>(client_info.output_buffer, 0));
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -175,27 +235,31 @@ static BAN::ErrorOr<void> extension_randr(Client& client_info, BAN::ConstByteSpa
|
||||
dprintln(" output: {}", request.output);
|
||||
dprintln(" configTimestamp: {}", request.configTimestamp);
|
||||
|
||||
const auto& display = find_display_by_output(request.output);
|
||||
|
||||
xRRGetOutputInfoReply reply {
|
||||
.type = X_Reply,
|
||||
.status = Success,
|
||||
.sequenceNumber = client_info.sequence,
|
||||
.length = 1 + 1 + 1 + 2,
|
||||
.timestamp = timestamp,
|
||||
.crtc = crtc_id,
|
||||
.mmWidth = g_root.mmWidth,
|
||||
.mmHeight = g_root.mmHeight,
|
||||
.connection = RR_Connected,
|
||||
.subpixelOrder = SubPixelUnknown,
|
||||
.nCrtcs = 1,
|
||||
.nModes = 1,
|
||||
.nPreferred = 1,
|
||||
.nClones = 0,
|
||||
.nameLength = 5,
|
||||
.type = X_Reply,
|
||||
.status = Success,
|
||||
.sequenceNumber = client_info.sequence,
|
||||
.length = static_cast<CARD32>(1 + 1 + 1 + (display.output_str.size() + 3) / 4),
|
||||
.timestamp = s_timestamp,
|
||||
.crtc = display.crtc_id,
|
||||
.mmWidth = display.info.w * 254 / 960, // 96 DPI
|
||||
.mmHeight = display.info.h * 254 / 960, // 96 DPI
|
||||
.connection = RR_Connected,
|
||||
.subpixelOrder = SubPixelUnknown,
|
||||
.nCrtcs = 1,
|
||||
.nModes = 1,
|
||||
.nPreferred = 1,
|
||||
.nClones = 0,
|
||||
.nameLength = static_cast<CARD16>(display.output_str.size()),
|
||||
};
|
||||
TRY(encode(client_info.output_buffer, reply));
|
||||
TRY(encode(client_info.output_buffer, crtc_id));
|
||||
TRY(encode(client_info.output_buffer, mode_id));
|
||||
TRY(encode(client_info.output_buffer, "B-OUT\0\0\0"_sv));
|
||||
TRY(encode(client_info.output_buffer, display.crtc_id));
|
||||
TRY(encode(client_info.output_buffer, display.mode_id));
|
||||
TRY(encode(client_info.output_buffer, display.output_str));
|
||||
while (client_info.output_buffer.size() % 4)
|
||||
TRY(encode<BYTE>(client_info.output_buffer, 0));
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -250,25 +314,27 @@ static BAN::ErrorOr<void> extension_randr(Client& client_info, BAN::ConstByteSpa
|
||||
dprintln(" crtc: {}", request.crtc);
|
||||
dprintln(" configTimestamp: {}", request.configTimestamp);
|
||||
|
||||
const auto& display = find_display_by_crtc(request.crtc);
|
||||
|
||||
xRRGetCrtcInfoReply reply {
|
||||
.type = X_Reply,
|
||||
.status = Success,
|
||||
.sequenceNumber = client_info.sequence,
|
||||
.length = 2,
|
||||
.timestamp = timestamp,
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
.width = g_root.pixWidth,
|
||||
.height = g_root.pixHeight,
|
||||
.mode = mode_id,
|
||||
.timestamp = s_timestamp,
|
||||
.x = static_cast<INT16>(display.info.x),
|
||||
.y = static_cast<INT16>(display.info.y),
|
||||
.width = static_cast<CARD16>(display.info.w),
|
||||
.height = static_cast<CARD16>(display.info.h),
|
||||
.mode = display.mode_id,
|
||||
.rotation = RR_Rotate_0,
|
||||
.rotations = RR_Rotate_0,
|
||||
.nOutput = 1,
|
||||
.nPossibleOutput = 1,
|
||||
};
|
||||
TRY(encode(client_info.output_buffer, reply));
|
||||
TRY(encode(client_info.output_buffer, output_id));
|
||||
TRY(encode(client_info.output_buffer, output_id));
|
||||
TRY(encode(client_info.output_buffer, display.output_id));
|
||||
TRY(encode(client_info.output_buffer, display.output_id));
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -285,13 +351,13 @@ static BAN::ErrorOr<void> extension_randr(Client& client_info, BAN::ConstByteSpa
|
||||
dprintln(" mode: {}", request.mode);
|
||||
dprintln(" rotation: {}", request.rotation);
|
||||
|
||||
timestamp = time(nullptr);
|
||||
s_timestamp = time(nullptr);
|
||||
xRRSetCrtcConfigReply reply {
|
||||
.type = X_Reply,
|
||||
.status = Success,
|
||||
.sequenceNumber = client_info.sequence,
|
||||
.length = 0,
|
||||
.newTimestamp = timestamp,
|
||||
.newTimestamp = s_timestamp,
|
||||
};
|
||||
TRY(encode(client_info.output_buffer, reply));
|
||||
|
||||
@@ -301,15 +367,15 @@ static BAN::ErrorOr<void> extension_randr(Client& client_info, BAN::ConstByteSpa
|
||||
{
|
||||
auto request = decode<xRRGetCrtcGammaSizeReq>(packet).value();
|
||||
|
||||
dprintln("RRGetCrtcGammaSize");
|
||||
dprintln(" crtc: {}", request.crtc);
|
||||
dwarnln("RRGetCrtcGammaSize");
|
||||
dwarnln(" crtc: {}", request.crtc);
|
||||
|
||||
xRRGetCrtcGammaSizeReply reply {
|
||||
.type = X_Reply,
|
||||
.status = Success,
|
||||
.sequenceNumber = client_info.sequence,
|
||||
.length = 0,
|
||||
.size = 1,
|
||||
.type = X_Reply,
|
||||
.status = Success,
|
||||
.sequenceNumber = client_info.sequence,
|
||||
.length = 0,
|
||||
.size = 256,
|
||||
};
|
||||
TRY(encode(client_info.output_buffer, reply));
|
||||
|
||||
@@ -323,17 +389,16 @@ static BAN::ErrorOr<void> extension_randr(Client& client_info, BAN::ConstByteSpa
|
||||
dprintln(" crtc: {}", request.crtc);
|
||||
|
||||
xRRGetCrtcGammaReply reply {
|
||||
.type = X_Reply,
|
||||
.status = Success,
|
||||
.sequenceNumber = client_info.sequence,
|
||||
.length = 2,
|
||||
.size = 1,
|
||||
.type = X_Reply,
|
||||
.status = Success,
|
||||
.sequenceNumber = client_info.sequence,
|
||||
.length = (6 * 256) / 4,
|
||||
.size = 256,
|
||||
};
|
||||
TRY(encode(client_info.output_buffer, reply));
|
||||
TRY(encode<CARD16>(client_info.output_buffer, 1));
|
||||
TRY(encode<CARD16>(client_info.output_buffer, 1));
|
||||
TRY(encode<CARD16>(client_info.output_buffer, 1));
|
||||
TRY(encode<CARD16>(client_info.output_buffer, 0));
|
||||
for (size_t i = 0; i < 3; i++)
|
||||
for (size_t j = 0; j < 256; j++)
|
||||
TRY(encode<CARD16>(client_info.output_buffer, j * 65535 / 255));
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -345,17 +410,17 @@ static BAN::ErrorOr<void> extension_randr(Client& client_info, BAN::ConstByteSpa
|
||||
dprintln(" crtc: {}", request.crtc);
|
||||
|
||||
xRRGetCrtcTransformReply reply {
|
||||
.type = X_Reply,
|
||||
.status = Success,
|
||||
.sequenceNumber = client_info.sequence,
|
||||
.length = 16,
|
||||
.pendingTransform = transform,
|
||||
.hasTransforms = xFalse,
|
||||
.currentTransform = transform,
|
||||
.pendingNbytesFilter = 0,
|
||||
.pendingNparamsFilter = 0,
|
||||
.currentNbytesFilter = 0,
|
||||
.currentNparamsFilter = 0,
|
||||
.type = X_Reply,
|
||||
.status = Success,
|
||||
.sequenceNumber = client_info.sequence,
|
||||
.length = 16,
|
||||
.pendingTransform = transform,
|
||||
.hasTransforms = xFalse,
|
||||
.currentTransform = transform,
|
||||
.pendingNbytesFilter = 0,
|
||||
.pendingNparamsFilter = 0,
|
||||
.currentNbytesFilter = 0,
|
||||
.currentNparamsFilter = 0,
|
||||
};
|
||||
TRY(encode(client_info.output_buffer, reply));
|
||||
|
||||
@@ -369,23 +434,23 @@ static BAN::ErrorOr<void> extension_randr(Client& client_info, BAN::ConstByteSpa
|
||||
dprintln(" crtc: {}", request.crtc);
|
||||
|
||||
xRRGetPanningReply reply {
|
||||
.type = X_Reply,
|
||||
.status = Success,
|
||||
.sequenceNumber = client_info.sequence,
|
||||
.length = 1,
|
||||
.timestamp = timestamp,
|
||||
.left = 0,
|
||||
.top = 0,
|
||||
.width = 0,
|
||||
.height = 0,
|
||||
.track_left = 0,
|
||||
.track_top = 0,
|
||||
.track_width = 0,
|
||||
.track_height = 0,
|
||||
.border_left = 0,
|
||||
.border_top = 0,
|
||||
.border_right = 0,
|
||||
.border_bottom = 0,
|
||||
.type = X_Reply,
|
||||
.status = Success,
|
||||
.sequenceNumber = client_info.sequence,
|
||||
.length = 1,
|
||||
.timestamp = s_timestamp,
|
||||
.left = 0,
|
||||
.top = 0,
|
||||
.width = 0,
|
||||
.height = 0,
|
||||
.track_left = 0,
|
||||
.track_top = 0,
|
||||
.track_width = 0,
|
||||
.track_height = 0,
|
||||
.border_left = 0,
|
||||
.border_top = 0,
|
||||
.border_right = 0,
|
||||
.border_bottom = 0,
|
||||
};
|
||||
TRY(encode(client_info.output_buffer, reply));
|
||||
|
||||
@@ -399,10 +464,10 @@ static BAN::ErrorOr<void> extension_randr(Client& client_info, BAN::ConstByteSpa
|
||||
dprintln(" window: {}", request.window);
|
||||
|
||||
xRRGetOutputPrimaryReply reply {
|
||||
.type = X_Reply,
|
||||
.sequenceNumber = client_info.sequence,
|
||||
.length = 0,
|
||||
.output = output_id,
|
||||
.type = X_Reply,
|
||||
.sequenceNumber = client_info.sequence,
|
||||
.length = 0,
|
||||
.output = s_randr_displays.front().output_id,
|
||||
};
|
||||
TRY(encode(client_info.output_buffer, reply));
|
||||
|
||||
@@ -416,10 +481,10 @@ static BAN::ErrorOr<void> extension_randr(Client& client_info, BAN::ConstByteSpa
|
||||
dprintln(" window: {}", request.window);
|
||||
|
||||
xRRGetProvidersReply reply {
|
||||
.type = X_Reply,
|
||||
.sequenceNumber = client_info.sequence,
|
||||
.length = 0,
|
||||
.timestamp = timestamp,
|
||||
.type = X_Reply,
|
||||
.sequenceNumber = client_info.sequence,
|
||||
.length = 0,
|
||||
.timestamp = s_timestamp,
|
||||
.nProviders = 0,
|
||||
};
|
||||
TRY(encode(client_info.output_buffer, reply));
|
||||
@@ -435,31 +500,33 @@ static BAN::ErrorOr<void> extension_randr(Client& client_info, BAN::ConstByteSpa
|
||||
dprintln(" get_active: {}", request.get_active);
|
||||
|
||||
xRRGetMonitorsReply reply {
|
||||
.type = X_Reply,
|
||||
.type = X_Reply,
|
||||
.status = Success,
|
||||
.sequenceNumber = client_info.sequence,
|
||||
.length = 6 + 1,
|
||||
.timestamp = timestamp,
|
||||
.nmonitors = 1,
|
||||
.noutputs = 1,
|
||||
.sequenceNumber = client_info.sequence,
|
||||
.length = static_cast<CARD32>(6 * s_randr_displays.size() + s_randr_displays.size()),
|
||||
.timestamp = s_timestamp,
|
||||
.nmonitors = static_cast<CARD32>(s_randr_displays.size()),
|
||||
.noutputs = static_cast<CARD32>(s_randr_displays.size()),
|
||||
};
|
||||
TRY(encode(client_info.output_buffer, reply));
|
||||
|
||||
xRRMonitorInfo monitor {
|
||||
.name = None,
|
||||
.primary = xTrue,
|
||||
.automatic = xTrue,
|
||||
.noutput = 1,
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
.width = g_root.pixWidth,
|
||||
.height = g_root.pixHeight,
|
||||
.widthInMillimeters = g_root.mmWidth,
|
||||
.heightInMillimeters = g_root.mmHeight,
|
||||
};
|
||||
TRY(encode(client_info.output_buffer, monitor));
|
||||
|
||||
TRY(encode(client_info.output_buffer, output_id));
|
||||
for (const auto& display : s_randr_displays)
|
||||
{
|
||||
xRRMonitorInfo monitor {
|
||||
.name = display.name_atom,
|
||||
.primary = (&display == &s_randr_displays.front()),
|
||||
.automatic = xTrue,
|
||||
.noutput = 1,
|
||||
.x = static_cast<INT16>(display.info.x),
|
||||
.y = static_cast<INT16>(display.info.y),
|
||||
.width = static_cast<CARD16>(display.info.w),
|
||||
.height = static_cast<CARD16>(display.info.h),
|
||||
.widthInMillimeters = display.info.w * 254 / 96, // 96 DPI
|
||||
.heightInMillimeters = display.info.h * 254 / 96, // 96 DPI
|
||||
};
|
||||
TRY(encode(client_info.output_buffer, monitor));
|
||||
TRY(encode(client_info.output_buffer, display.output_id));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -7,12 +7,12 @@
|
||||
template<typename F>
|
||||
static BAN::ErrorOr<void> for_each_client(uint32_t target_spec, const F& callback)
|
||||
{
|
||||
for (auto [fd, thingy] : g_epoll_thingies)
|
||||
for (const auto& [fd, thingy] : g_epoll_thingies)
|
||||
{
|
||||
if (thingy.type != EpollThingy::Type::Client)
|
||||
continue;
|
||||
|
||||
Client& client_info = thingy.value.get<Client>();
|
||||
const auto& client_info = thingy.value.get<Client>();
|
||||
if (target_spec && (target_spec >> 20) != client_info.fd)
|
||||
continue;
|
||||
|
||||
@@ -33,8 +33,8 @@ BAN::ErrorOr<void> extension_xres(Client& client_info, BAN::ConstByteSpan packet
|
||||
auto request = decode<xXResQueryVersionReq>(packet).value();
|
||||
|
||||
dprintln("XResQueryVersion");
|
||||
dprintln(" clientMajor: {}", reqType.client_major);
|
||||
dprintln(" clientMinor: {}", reqType.client_minor);
|
||||
dprintln(" clientMajor: {}", request.client_major);
|
||||
dprintln(" clientMinor: {}", request.client_minor);
|
||||
|
||||
xXResQueryVersionReply reply {
|
||||
.type = X_Reply,
|
||||
@@ -61,7 +61,7 @@ BAN::ErrorOr<void> extension_xres(Client& client_info, BAN::ConstByteSpan packet
|
||||
{
|
||||
auto spec = decode<xXResClientIdSpec>(packet).value();
|
||||
|
||||
TRY(for_each_client(spec.client, [&](Client& client_info, uint32_t client_spec) -> BAN::ErrorOr<void> {
|
||||
TRY(for_each_client(spec.client, [&](const Client& client_info, uint32_t client_spec) -> BAN::ErrorOr<void> {
|
||||
if (spec.mask == None || (spec.mask & X_XResClientXIDMask))
|
||||
{
|
||||
xXResClientIdValue value {
|
||||
|
||||
@@ -385,7 +385,7 @@ static BAN::ErrorOr<BAN::RefPtr<PCFFont>> parse_font(const BAN::String& path)
|
||||
font->font_ascent = font->max_bounds.ascent;
|
||||
font->font_descent = font->max_bounds.descent;
|
||||
|
||||
font->is_cursor_font = (path == "fonts/misc/cursor.pcf.gz"_sv);
|
||||
font->is_cursor_font = (path == FONT_PATH "/misc/cursor.pcf.gz"_sv);
|
||||
|
||||
return font;
|
||||
}
|
||||
@@ -393,7 +393,7 @@ static BAN::ErrorOr<BAN::RefPtr<PCFFont>> parse_font(const BAN::String& path)
|
||||
__attribute__((constructor))
|
||||
static void initialize_fonts()
|
||||
{
|
||||
const char* font_path = "fonts/misc";
|
||||
const char* font_path = FONT_PATH "/misc";
|
||||
|
||||
do
|
||||
{
|
||||
|
||||
@@ -42,17 +42,23 @@ enum class SystemCursorType
|
||||
ResizeHorizontal,
|
||||
};
|
||||
|
||||
// initialize, poll_events, create_window and invalidate are required
|
||||
// initialize, create_window and invalidate are required
|
||||
// poll_events is required when an event fd is registered
|
||||
struct PlatformOps
|
||||
{
|
||||
/* Do platform initialization */
|
||||
bool (*initialize)(uint32_t* width, uint32_t* height);
|
||||
bool (*initialize)();
|
||||
/* Handle pending events */
|
||||
void (*poll_events)(void*);
|
||||
/* Create a window with given size */
|
||||
BAN::ErrorOr<BAN::UniqPtr<PlatformWindow>> (*create_window)(PlatformWindow* parent, WindowType, WINDOW wid, int32_t x, int32_t y, uint32_t width, uint32_t height);
|
||||
/* Invaldate part of a window */
|
||||
void (*invalidate)(PlatformWindow*, const uint32_t* pixels, uint32_t x, uint32_t y, uint32_t width, uint32_t height);
|
||||
BAN::ErrorOr<BAN::UniqPtr<PlatformWindow>> (*create_window)(WindowType, WINDOW wid, int32_t x, int32_t y, uint32_t width, uint32_t height);
|
||||
/* All invalidate calls during one frame happen between calls to begin_frame and end_frame. pixels is in ARGB8888
|
||||
* invalidate should update the underlying textures
|
||||
* begin_frame should do any necessary preparations to update a frame
|
||||
* end_frame should flush the updated texturee to the window */
|
||||
void (*invalidate)(PlatformWindow*, const void* pixels, uint32_t pitch, uint32_t x, uint32_t y, uint32_t width, uint32_t height);
|
||||
void (*begin_frame)(PlatformWindow*);
|
||||
void (*end_frame)(PlatformWindow*);
|
||||
/* Request resize of a window, can be async */
|
||||
void (*request_resize)(PlatformWindow*, uint32_t width, uint32_t height);
|
||||
/* Request window repositioning */
|
||||
@@ -73,3 +79,5 @@ struct PlatformOps
|
||||
void (*set_cursor)(PlatformWindow*, PlatformCursor*);
|
||||
};
|
||||
extern PlatformOps g_platform_ops;
|
||||
|
||||
void register_display(int32_t x, int32_t y, uint32_t width, uint32_t height);
|
||||
|
||||
@@ -69,7 +69,7 @@ static void* sdl3_thread(void*)
|
||||
|
||||
static void sdl3_initialize_keymap();
|
||||
|
||||
static bool sdl3_initialize(uint32_t* display_w, uint32_t* display_h)
|
||||
static bool sdl3_initialize()
|
||||
{
|
||||
if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS))
|
||||
{
|
||||
@@ -77,15 +77,16 @@ static bool sdl3_initialize(uint32_t* display_w, uint32_t* display_h)
|
||||
return false;
|
||||
}
|
||||
|
||||
*display_w = *display_h = 0;
|
||||
|
||||
const SDL_DisplayID* display_ids = SDL_GetDisplays(nullptr);
|
||||
for (int i = 0; display_ids[i]; i++)
|
||||
{
|
||||
SDL_Rect rect;
|
||||
SDL_GetDisplayBounds(display_ids[i], &rect);
|
||||
*display_w = BAN::Math::max<uint32_t>(*display_w, rect.x + rect.w);
|
||||
*display_h = BAN::Math::max<uint32_t>(*display_h, rect.y + rect.h);
|
||||
if (!SDL_GetDisplayBounds(display_ids[i], &rect))
|
||||
{
|
||||
dwarnln("Could not display {} bounds: {}", SDL_GetError());
|
||||
continue;
|
||||
}
|
||||
register_display(rect.x, rect.y, rect.w, rect.h);
|
||||
}
|
||||
|
||||
sdl3_initialize_keymap();
|
||||
@@ -107,7 +108,7 @@ static bool sdl3_initialize(uint32_t* display_w, uint32_t* display_h)
|
||||
return true;
|
||||
}
|
||||
|
||||
static BAN::ErrorOr<BAN::UniqPtr<PlatformWindow>> sdl3_create_window(PlatformWindow* parent, WindowType type, WINDOW wid, int32_t x, int32_t y, uint32_t width, uint32_t height)
|
||||
static BAN::ErrorOr<BAN::UniqPtr<PlatformWindow>> sdl3_create_window(WindowType type, WINDOW wid, int32_t x, int32_t y, uint32_t width, uint32_t height)
|
||||
{
|
||||
auto window = TRY(BAN::UniqPtr<SDLWindow>::create());
|
||||
|
||||
@@ -119,29 +120,19 @@ static BAN::ErrorOr<BAN::UniqPtr<PlatformWindow>> sdl3_create_window(PlatformWin
|
||||
switch (type)
|
||||
{
|
||||
case WindowType::Normal:
|
||||
case WindowType::Utility:
|
||||
flags = SDL_WINDOW_RESIZABLE;
|
||||
break;
|
||||
case WindowType::Utility:
|
||||
flags = SDL_WINDOW_RESIZABLE | SDL_WINDOW_UTILITY;
|
||||
break;
|
||||
case WindowType::Popup:
|
||||
flags = SDL_WINDOW_BORDERLESS;
|
||||
flags = SDL_WINDOW_BORDERLESS | SDL_WINDOW_UTILITY;
|
||||
break;
|
||||
}
|
||||
|
||||
if (parent == nullptr || type != WindowType::Popup)
|
||||
{
|
||||
if (type != WindowType::Normal)
|
||||
flags |= SDL_WINDOW_UTILITY;
|
||||
window->window = SDL_CreateWindow("", width, height, flags);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto& sdl_parent = *static_cast<SDLWindow*>(parent);
|
||||
flags |= SDL_WINDOW_TRANSPARENT;
|
||||
|
||||
int parent_x, parent_y;
|
||||
SDL_GetWindowPosition(sdl_parent.window, &parent_x, &parent_y);
|
||||
|
||||
window->window = SDL_CreatePopupWindow(sdl_parent.window, x - parent_x, y - parent_y, width, height, flags | SDL_WINDOW_POPUP_MENU);
|
||||
}
|
||||
window->window = SDL_CreateWindow("", width, height, flags);
|
||||
|
||||
if (window->window == nullptr)
|
||||
{
|
||||
@@ -149,6 +140,9 @@ static BAN::ErrorOr<BAN::UniqPtr<PlatformWindow>> sdl3_create_window(PlatformWin
|
||||
return BAN::Error::from_errno(EFAULT);
|
||||
}
|
||||
|
||||
if (x != 0 || y != 0)
|
||||
SDL_SetWindowPosition(window->window, x, y);
|
||||
|
||||
window->renderer = SDL_CreateRenderer(window->window, nullptr);
|
||||
if (window->renderer == nullptr)
|
||||
{
|
||||
@@ -156,6 +150,8 @@ static BAN::ErrorOr<BAN::UniqPtr<PlatformWindow>> sdl3_create_window(PlatformWin
|
||||
return BAN::Error::from_errno(EFAULT);
|
||||
}
|
||||
|
||||
SDL_SetRenderDrawColor(window->renderer, 0, 0, 0, 0);
|
||||
|
||||
window->texture = SDL_CreateTexture(window->renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, width, height);
|
||||
if (window->texture == nullptr)
|
||||
{
|
||||
@@ -291,7 +287,7 @@ static void sdl3_poll_events(void*)
|
||||
}
|
||||
}
|
||||
|
||||
static void sdl3_invalidate(PlatformWindow* window, const uint32_t* src_pixels, uint32_t x, uint32_t y, uint32_t width, uint32_t height)
|
||||
static void sdl3_invalidate(PlatformWindow* window, const void* src_pixels, uint32_t src_pitch, uint32_t x, uint32_t y, uint32_t width, uint32_t height)
|
||||
{
|
||||
auto& sdl_window = *static_cast<SDLWindow*>(window);
|
||||
|
||||
@@ -316,16 +312,20 @@ static void sdl3_invalidate(PlatformWindow* window, const uint32_t* src_pixels,
|
||||
for (int32_t y_off = 0; y_off < rect.h; y_off++)
|
||||
{
|
||||
memcpy(
|
||||
static_cast<uint8_t*>(dst_pixels) + y_off * dst_pitch,
|
||||
&src_pixels[(rect.y + y_off) * sdl_window.width + rect.x],
|
||||
static_cast< uint8_t*>(dst_pixels) + y_off * dst_pitch,
|
||||
static_cast<const uint8_t*>(src_pixels) + y_off * src_pitch,
|
||||
rect.w * sizeof(uint32_t)
|
||||
);
|
||||
}
|
||||
|
||||
SDL_UnlockTexture(sdl_window.texture);
|
||||
}
|
||||
|
||||
static void sdl3_end_frame(PlatformWindow* window)
|
||||
{
|
||||
auto& sdl_window = *static_cast<SDLWindow*>(window);
|
||||
SDL_RenderClear(sdl_window.renderer);
|
||||
SDL_RenderTexture(sdl_window.renderer, sdl_window.texture, NULL, NULL);
|
||||
SDL_RenderTexture(sdl_window.renderer, sdl_window.texture, nullptr, nullptr);
|
||||
SDL_RenderPresent(sdl_window.renderer);
|
||||
}
|
||||
|
||||
@@ -438,6 +438,8 @@ PlatformOps g_platform_ops = {
|
||||
.poll_events = sdl3_poll_events,
|
||||
.create_window = sdl3_create_window,
|
||||
.invalidate = sdl3_invalidate,
|
||||
.begin_frame = nullptr,
|
||||
.end_frame = sdl3_end_frame,
|
||||
.request_resize = sdl3_request_resize,
|
||||
.request_reposition = sdl3_request_reposition,
|
||||
.request_fullscreen = sdl3_request_fullscreen,
|
||||
@@ -505,9 +507,9 @@ static uint32_t sdl3_keycode_to_x_keysym(SDL_Keycode keycode)
|
||||
{
|
||||
if (iswprint(keycode))
|
||||
{
|
||||
if ((keycode >= 0x20 && keycode <= 0x7E) || (keycode >= 0xA0 && keycode <= 0xFF))
|
||||
return keycode;
|
||||
return 0x01000000 | keycode;
|
||||
if (keycode >= 0x100)
|
||||
keycode |= 0x01000000;
|
||||
return keycode;
|
||||
}
|
||||
|
||||
switch (keycode)
|
||||
|
||||
@@ -26,9 +26,11 @@ struct BananCursor final : public PlatformCursor
|
||||
int32_t origin_y;
|
||||
};
|
||||
|
||||
static BAN::UniqPtr<LibGUI::Window> s_dummy_window;
|
||||
|
||||
static BAN::ErrorOr<void> bananos_initialize_keymap();
|
||||
|
||||
static bool bananos_initialize(uint32_t* display_w, uint32_t* display_h)
|
||||
static bool bananos_initialize()
|
||||
{
|
||||
auto attributes = LibGUI::Window::default_attributes;
|
||||
attributes.shown = false;
|
||||
@@ -40,8 +42,9 @@ static bool bananos_initialize(uint32_t* display_w, uint32_t* display_h)
|
||||
return false;
|
||||
}
|
||||
|
||||
*display_w = dummy_or_error.value()->width();
|
||||
*display_h = dummy_or_error.value()->height();
|
||||
s_dummy_window = dummy_or_error.release_value();
|
||||
|
||||
register_display(0, 0, s_dummy_window->width(), s_dummy_window->height());
|
||||
|
||||
if (auto ret = bananos_initialize_keymap(); ret.is_error())
|
||||
{
|
||||
@@ -58,12 +61,9 @@ static void bananos_poll_events(void* window)
|
||||
banan_window.window->poll_events();
|
||||
}
|
||||
|
||||
static BAN::ErrorOr<BAN::UniqPtr<PlatformWindow>> bananos_create_window(PlatformWindow* parent, WindowType type, WINDOW wid, int32_t x, int32_t y, uint32_t width, uint32_t height)
|
||||
static BAN::ErrorOr<BAN::UniqPtr<PlatformWindow>> bananos_create_window(WindowType type, WINDOW wid, int32_t x, int32_t y, uint32_t width, uint32_t height)
|
||||
{
|
||||
(void)parent;
|
||||
(void)type;
|
||||
(void)x;
|
||||
(void)y;
|
||||
|
||||
auto window = TRY(BAN::UniqPtr<BananWindow>::create());
|
||||
|
||||
@@ -71,10 +71,14 @@ static BAN::ErrorOr<BAN::UniqPtr<PlatformWindow>> bananos_create_window(Platform
|
||||
attributes.shown = true;
|
||||
attributes.title_bar = false;
|
||||
attributes.resizable = true;
|
||||
attributes.alpha_channel = true;
|
||||
|
||||
auto gui_window = TRY(LibGUI::Window::create(width, height, ""_sv, attributes));
|
||||
auto* winp = gui_window.ptr();
|
||||
|
||||
if (x != 0 || y != 0)
|
||||
gui_window->set_position(x, y);
|
||||
|
||||
gui_window->set_close_window_event_callback([wid] {
|
||||
on_window_close_event(wid);
|
||||
});
|
||||
@@ -87,6 +91,9 @@ static BAN::ErrorOr<BAN::UniqPtr<PlatformWindow>> bananos_create_window(Platform
|
||||
gui_window->set_window_fullscreen_event_callback([wid](auto event) {
|
||||
on_window_fullscreen_event(wid, event.fullscreen);
|
||||
});
|
||||
gui_window->set_window_move_event_callback([wid](auto event) {
|
||||
on_window_move_event(wid, event.x, event.y);
|
||||
});
|
||||
gui_window->set_mouse_move_event_callback([wid](auto event) {
|
||||
on_mouse_move_event(wid, event.x, event.y);
|
||||
});
|
||||
@@ -133,18 +140,34 @@ static void bananos_request_resize(PlatformWindow* window, uint32_t width, uint3
|
||||
banan_window.window->request_resize(width, height);
|
||||
}
|
||||
|
||||
static void bananos_invalidate(PlatformWindow* window, const uint32_t* pixels, uint32_t x, uint32_t y, uint32_t width, uint32_t height)
|
||||
static void bananos_request_reposition(PlatformWindow* window, int32_t x, int32_t y)
|
||||
{
|
||||
auto& banan_window = *static_cast<BananWindow*>(window);
|
||||
banan_window.window->set_position(x, y);
|
||||
}
|
||||
|
||||
static void bananos_invalidate(PlatformWindow* window, const void* src_pixels, uint32_t src_pitch, uint32_t x, uint32_t y, uint32_t width, uint32_t height)
|
||||
{
|
||||
auto& banan_window = *static_cast<BananWindow*>(window);
|
||||
|
||||
const uint32_t win_width = banan_window.window->width();
|
||||
auto& texture = banan_window.window->texture();
|
||||
void* dst_pixels = &texture.pixels()[y * texture.width() + x];
|
||||
const uint32_t dst_pitch = texture.width() * sizeof(uint32_t);
|
||||
|
||||
auto* out_pixels = banan_window.window->texture().pixels().data();
|
||||
for (uint32_t y_off = 0; y_off < height; y_off++)
|
||||
for (uint32_t x_off = 0; x_off < width; x_off++)
|
||||
out_pixels[(y + y_off) * win_width + (x + x_off)] = pixels[(y + y_off) * win_width + (x + x_off)];
|
||||
{
|
||||
memcpy(
|
||||
static_cast< uint8_t*>(dst_pixels) + y_off * dst_pitch,
|
||||
static_cast<const uint8_t*>(src_pixels) + y_off * src_pitch,
|
||||
width * sizeof(uint32_t)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
banan_window.window->invalidate(x, y, width, height);
|
||||
static void bananos_end_frame(PlatformWindow* window)
|
||||
{
|
||||
auto& banan_window = *static_cast<BananWindow*>(window);
|
||||
banan_window.window->invalidate();
|
||||
}
|
||||
|
||||
static void bananos_request_fullscreen(PlatformWindow* window, bool fullscreen)
|
||||
@@ -153,6 +176,26 @@ static void bananos_request_fullscreen(PlatformWindow* window, bool fullscreen)
|
||||
banan_window.window->set_fullscreen(fullscreen);
|
||||
}
|
||||
|
||||
static void bananos_query_ponter(int32_t* x, int32_t* y)
|
||||
{
|
||||
s_dummy_window->query_cursor_position();
|
||||
|
||||
bool queried { false };
|
||||
s_dummy_window->set_query_pointer_event_callback([&](auto event) {
|
||||
*x = event.x;
|
||||
*y = event.y;
|
||||
queried = true;
|
||||
});
|
||||
|
||||
while (!queried)
|
||||
{
|
||||
s_dummy_window->wait_events();
|
||||
s_dummy_window->poll_events();
|
||||
}
|
||||
|
||||
s_dummy_window->set_query_pointer_event_callback({});
|
||||
}
|
||||
|
||||
static BAN::ErrorOr<BAN::UniqPtr<PlatformCursor>> bananos_create_bitmap_cursor(const uint32_t* pixels, uint32_t width, uint32_t height, int32_t origin_x, int32_t origin_y)
|
||||
{
|
||||
auto cursor = TRY(BAN::UniqPtr<BananCursor>::create());
|
||||
@@ -187,11 +230,13 @@ PlatformOps g_platform_ops = {
|
||||
.poll_events = bananos_poll_events,
|
||||
.create_window = bananos_create_window,
|
||||
.invalidate = bananos_invalidate,
|
||||
.begin_frame = nullptr,
|
||||
.end_frame = bananos_end_frame,
|
||||
.request_resize = bananos_request_resize,
|
||||
.request_reposition = nullptr,
|
||||
.request_reposition = bananos_request_reposition,
|
||||
.request_fullscreen = bananos_request_fullscreen,
|
||||
.warp_pointer = nullptr,
|
||||
.query_pointer = nullptr,
|
||||
.query_pointer = bananos_query_ponter,
|
||||
.set_pointer_grab = nullptr,
|
||||
.create_system_cursor = nullptr,
|
||||
.create_bitmap_cursor = bananos_create_bitmap_cursor,
|
||||
@@ -201,29 +246,27 @@ PlatformOps g_platform_ops = {
|
||||
#include <LibInput/KeyboardLayout.h>
|
||||
#include <LibInput/KeyEvent.h>
|
||||
|
||||
static uint32_t bananos_key_to_x_keysym(LibInput::Key, bool upper);
|
||||
static uint32_t bananos_keyevent_to_x_keysym(LibInput::KeyEvent event);
|
||||
|
||||
static BAN::ErrorOr<void> bananos_initialize_keymap()
|
||||
{
|
||||
static constexpr uint16_t modifier_map[] {
|
||||
0,
|
||||
LibInput::KeyEvent::LShift,
|
||||
LibInput::KeyEvent::RAlt,
|
||||
LibInput::KeyEvent::RAlt | LibInput::KeyEvent::LShift,
|
||||
};
|
||||
|
||||
// FIXME: get this from somewhere (gui command? enviroment? tmp file?)
|
||||
const auto keymap_path = "./us.keymap"_sv;
|
||||
|
||||
TRY(LibInput::KeyboardLayout::initialize());
|
||||
|
||||
auto& keyboard_layout = LibInput::KeyboardLayout::get();
|
||||
TRY(keyboard_layout.load_from_file(keymap_path));
|
||||
|
||||
const BAN::Span<const LibInput::Key> banan_keymaps[] {
|
||||
keyboard_layout.keymap_normal(),
|
||||
keyboard_layout.keymap_shift(),
|
||||
keyboard_layout.keymap_altgr(),
|
||||
keyboard_layout.keymap_altgr(), // add shift+altgr map?
|
||||
};
|
||||
|
||||
for (size_t scancode = 0; scancode < g_keymap_size; scancode++)
|
||||
for (uint8_t scancode = 0; scancode < g_keymap_size; scancode++)
|
||||
for (size_t layer = 0; layer < g_keymap_layers; layer++)
|
||||
if (const auto banan_key = banan_keymaps[layer][scancode]; banan_key != LibInput::Key::None)
|
||||
g_keymap[scancode][layer] = bananos_key_to_x_keysym(banan_key, layer % 2);
|
||||
if (const auto event = keyboard_layout.key_event_from_raw({ .modifier = modifier_map[layer], .keycode = scancode }); event.key != LibInput::Key::None)
|
||||
g_keymap[scancode][layer] = bananos_keyevent_to_x_keysym(event);
|
||||
|
||||
using LibInput::keycode_normal;
|
||||
using LibInput::keycode_numpad;
|
||||
@@ -258,22 +301,22 @@ static BAN::ErrorOr<void> bananos_initialize_keymap()
|
||||
|
||||
#include <wctype.h>
|
||||
|
||||
static uint32_t bananos_key_to_x_keysym(LibInput::Key key, bool upper)
|
||||
static uint32_t bananos_keyevent_to_x_keysym(LibInput::KeyEvent event)
|
||||
{
|
||||
using namespace LibInput;
|
||||
|
||||
if (const char* utf8 = key_to_utf8(key, upper ? KeyEvent::LShift : 0))
|
||||
if (const char* utf8 = key_to_utf8(event.key, event.modifier))
|
||||
{
|
||||
const uint32_t codepoint = BAN::UTF8::to_codepoint(utf8);
|
||||
uint32_t codepoint = BAN::UTF8::to_codepoint(utf8);
|
||||
if (codepoint != BAN::UTF8::invalid && iswprint(codepoint))
|
||||
{
|
||||
if ((codepoint >= 0x20 && codepoint <= 0x7E) || (codepoint >= 0xA0 && codepoint <= 0xFF))
|
||||
return codepoint;
|
||||
return 0x01000000 | codepoint;
|
||||
if (codepoint >= 0x100)
|
||||
codepoint |= 0x01000000;
|
||||
return codepoint;
|
||||
}
|
||||
}
|
||||
|
||||
switch (key)
|
||||
switch (event.key)
|
||||
{
|
||||
case Key::F1: return XK_F1;
|
||||
case Key::F2: return XK_F2;
|
||||
@@ -301,9 +344,10 @@ static uint32_t bananos_key_to_x_keysym(LibInput::Key key, bool upper)
|
||||
case Key::CapsLock: return XK_Caps_Lock;
|
||||
case Key::LeftShift: return XK_Shift_L;
|
||||
case Key::LeftCtrl: return XK_Control_L;
|
||||
case Key::Super: return XK_Super_L;
|
||||
case Key::LeftSuper: return XK_Super_L;
|
||||
case Key::LeftAlt: return XK_Alt_L;
|
||||
case Key::RightAlt: return XK_Alt_R;
|
||||
case Key::RightSuper: return XK_Super_R;
|
||||
case Key::RightCtrl: return XK_Control_R;
|
||||
case Key::RightShift: return XK_Shift_R;
|
||||
case Key::ArrowUp: return XK_Up;
|
||||
@@ -336,10 +380,11 @@ static uint32_t bananos_key_to_x_keysym(LibInput::Key key, bool upper)
|
||||
case Key::MediaStop: return XF86XK_AudioStop;
|
||||
case Key::MediaPrevious: return XF86XK_AudioPrev;
|
||||
case Key::MediaNext: return XF86XK_AudioNext;
|
||||
case Key::Application: return XF86XK_ApplicationRight;
|
||||
default: break;
|
||||
}
|
||||
|
||||
static_assert(static_cast<size_t>(Key::Count) == 145, "update keymap");
|
||||
static_assert(static_cast<size_t>(Key::Count) == 147, "update keymap");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
CARD32 g_next_global_id { 1 };
|
||||
|
||||
const xPixmapFormat g_formats[6] {
|
||||
{
|
||||
.depth = 1,
|
||||
@@ -58,7 +60,7 @@ const xDepth g_depth {
|
||||
};
|
||||
|
||||
const xVisualType g_visual {
|
||||
.visualID = 1,
|
||||
.visualID = g_next_global_id++,
|
||||
.c_class = TrueColor,
|
||||
.bitsPerRGB = 8,
|
||||
.colormapEntries = 256,
|
||||
@@ -68,24 +70,26 @@ const xVisualType g_visual {
|
||||
};
|
||||
|
||||
xWindowRoot g_root {
|
||||
.windowId = 2,
|
||||
.windowId = g_next_global_id++,
|
||||
.defaultColormap = 0,
|
||||
.whitePixel = 0xFFFFFF,
|
||||
.blackPixel = 0x000000,
|
||||
.currentInputMask = 0,
|
||||
.pixWidth = 0,
|
||||
.pixHeight = 0,
|
||||
.mmWidth = 0,
|
||||
.mmWidth = 0,
|
||||
.mmHeight = 0,
|
||||
.minInstalledMaps = 1,
|
||||
.maxInstalledMaps = 1,
|
||||
.rootVisualID = g_visual.visualID,
|
||||
.backingStore = 0,
|
||||
.saveUnders = 0,
|
||||
.rootDepth = 24,
|
||||
.rootDepth = g_depth.depth,
|
||||
.nDepths = 1,
|
||||
};
|
||||
|
||||
BAN::Vector<DisplayInfo> g_displays;
|
||||
|
||||
BAN::HashMap<CARD32, BAN::UniqPtr<Object>> g_objects;
|
||||
|
||||
BAN::HashMap<BAN::String, ATOM> g_atoms_name_to_id;
|
||||
@@ -261,13 +265,53 @@ int main()
|
||||
APPEND_ATOM_CUSTOM(_NET_WM_WINDOW_TYPE_UTILITY);
|
||||
#undef APPEND_ATOM_CUSTOM
|
||||
|
||||
uint32_t display_w, display_h;
|
||||
if (!g_platform_ops.initialize(&display_w, &display_h))
|
||||
if (!g_platform_ops.initialize())
|
||||
return 1;
|
||||
g_root.pixWidth = display_w;
|
||||
g_root.pixHeight = display_h;
|
||||
g_root.mmWidth = static_cast<CARD16>(display_w * 254 / 960); // 96 DPI
|
||||
g_root.mmHeight = static_cast<CARD16>(display_h * 254 / 960); // 96 DPI
|
||||
|
||||
if (g_displays.empty())
|
||||
{
|
||||
dwarnln("No displays windows initilized");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int32_t display_min_x { INT32_MAX }, display_min_y { INT32_MAX };
|
||||
int32_t display_max_x { INT32_MIN }, display_max_y { INT32_MIN };
|
||||
for (const auto& display : g_displays)
|
||||
{
|
||||
display_min_x = BAN::Math::min<int32_t>(display_min_x, display.x);
|
||||
display_min_y = BAN::Math::min<int32_t>(display_min_y, display.y);
|
||||
display_max_x = BAN::Math::max<int32_t>(display_max_x, display.x + display.w);
|
||||
display_max_y = BAN::Math::max<int32_t>(display_max_y, display.y + display.h);
|
||||
}
|
||||
|
||||
g_root.pixWidth = display_max_x - display_min_x;
|
||||
g_root.pixHeight = display_max_y - display_min_y;
|
||||
|
||||
g_root.mmWidth = g_root.pixWidth * 254 / 960; // 96 DPI
|
||||
g_root.mmHeight = g_root.pixHeight * 254 / 960; // 96 DPI
|
||||
|
||||
Client dummy_owner;
|
||||
MUST(g_objects.insert(g_root.windowId, MUST(BAN::UniqPtr<Object>::create(Object {
|
||||
.type = Object::Type::Window,
|
||||
.object = Object::Window {
|
||||
.owner = dummy_owner,
|
||||
.depth = g_root.rootDepth,
|
||||
.x = display_min_x,
|
||||
.y = display_min_y,
|
||||
.parent = None,
|
||||
.cursor = None,
|
||||
.c_class = InputOutput,
|
||||
.width = g_root.pixWidth,
|
||||
.height = g_root.pixHeight,
|
||||
.background = None,
|
||||
}
|
||||
}))));
|
||||
|
||||
MUST(g_objects.insert(g_visual.visualID,
|
||||
MUST(BAN::UniqPtr<Object>::create(Object {
|
||||
.type = Object::Type::Visual,
|
||||
}))
|
||||
));
|
||||
|
||||
printf("xbanan started\n");
|
||||
|
||||
@@ -353,28 +397,6 @@ int main()
|
||||
}
|
||||
};
|
||||
|
||||
Client dummy_client {};
|
||||
MUST(g_objects.insert(g_root.windowId,
|
||||
MUST(BAN::UniqPtr<Object>::create(Object {
|
||||
.type = Object::Type::Window,
|
||||
.object = Object::Window {
|
||||
.owner = dummy_client,
|
||||
.mapped = true,
|
||||
.depth = g_root.rootDepth,
|
||||
.parent = None,
|
||||
.c_class = InputOutput,
|
||||
.width = g_root.pixWidth,
|
||||
.height = g_root.pixHeight,
|
||||
}
|
||||
}))
|
||||
));
|
||||
|
||||
MUST(g_objects.insert(g_visual.visualID,
|
||||
MUST(BAN::UniqPtr<Object>::create(Object {
|
||||
.type = Object::Type::Visual,
|
||||
}))
|
||||
));
|
||||
|
||||
for (;;)
|
||||
{
|
||||
epoll_event events[16];
|
||||
@@ -607,6 +629,18 @@ int main()
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& [_, object] : g_objects)
|
||||
{
|
||||
if (object->type != Object::Type::Window)
|
||||
continue;
|
||||
auto& window = object->object.get<Object::Window>();
|
||||
if (!window.platform_window_invalidated)
|
||||
continue;
|
||||
if (g_platform_ops.end_frame)
|
||||
g_platform_ops.end_frame(window.platform_window.ptr());
|
||||
window.platform_window_invalidated = false;
|
||||
}
|
||||
|
||||
iterator_invalidated:
|
||||
for (auto& [_, thingy] : g_epoll_thingies)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user