Start work on making xbanan portable
This will allow usage of xbanan on non banan-os platforms. I added a "native" SDL2 port so it can be used without the window manager
This commit is contained in:
9
.clangd
Normal file
9
.clangd
Normal file
@@ -0,0 +1,9 @@
|
||||
Diagnostics:
|
||||
Suppress: [
|
||||
c99-designator,
|
||||
]
|
||||
|
||||
CompileFlags:
|
||||
Add: [
|
||||
-std=c++20,
|
||||
]
|
||||
949
xbanan/Base.cpp
949
xbanan/Base.cpp
File diff suppressed because it is too large
Load Diff
@@ -6,3 +6,14 @@ 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> destroy_window(Client& client_info, WINDOW wid);
|
||||
|
||||
WINDOW find_child_window(WINDOW wid, int32_t& x, int32_t& y);
|
||||
|
||||
static constexpr uint32_t COLOR_INVISIBLE = 0x69000000;
|
||||
|
||||
extern CARD16 g_keymask;
|
||||
extern CARD16 g_butmask;
|
||||
extern WINDOW g_focus_window;
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
set(SOURCES
|
||||
set(XBANAN_SOURCES
|
||||
main.cpp
|
||||
Base.cpp
|
||||
Drawing.cpp
|
||||
Events.cpp
|
||||
Extensions.cpp
|
||||
ExtBigReg.cpp
|
||||
ExtRANDR.cpp
|
||||
@@ -12,22 +13,40 @@ set(SOURCES
|
||||
)
|
||||
|
||||
option(ENABLE_GLX "enable glx extension" ON)
|
||||
option(ENABLE_SHM "enable shm extension" ON)
|
||||
|
||||
if(ENABLE_GLX)
|
||||
set(SOURCES ${SOURCES} ExtGLX.cpp)
|
||||
list(APPEND XBANAN_SOURCES ExtGLX.cpp)
|
||||
endif()
|
||||
|
||||
option(ENABLE_SHM "enable shm extension" ON)
|
||||
if(ENABLE_SHM)
|
||||
set(SOURCES ${SOURCES} ExtSHM.cpp)
|
||||
list(APPEND XBANAN_SOURCES ExtSHM.cpp)
|
||||
endif()
|
||||
|
||||
add_executable(xbanan ${SOURCES})
|
||||
set(PLATFORM "banan-os" CACHE STRING "target platform")
|
||||
|
||||
set(VALID_PLATFORMS "banan-os" "SDL2")
|
||||
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 "SDL2")
|
||||
list(APPEND XBANAN_SOURCES SDL2/sdl2.cpp)
|
||||
endif()
|
||||
|
||||
add_executable(xbanan ${XBANAN_SOURCES})
|
||||
banan_link_library(xbanan ban)
|
||||
banan_link_library(xbanan libdeflate)
|
||||
banan_link_library(xbanan libgui)
|
||||
banan_link_library(xbanan libinput)
|
||||
|
||||
if(PLATFORM STREQUAL "banan-os")
|
||||
banan_link_library(xbanan libgui)
|
||||
elseif(PLATFORM STREQUAL "SDL2")
|
||||
find_package(SDL2 REQUIRED)
|
||||
banan_link_library(xbanan SDL2::SDL2)
|
||||
endif()
|
||||
|
||||
target_compile_options(xbanan PRIVATE -Wall -Wextra)
|
||||
target_compile_options(xbanan PRIVATE
|
||||
-Wno-sign-compare
|
||||
@@ -36,4 +55,7 @@ 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)
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "Font.h"
|
||||
#include "Platform.h"
|
||||
#include "Types.h"
|
||||
|
||||
#include <BAN/Vector.h>
|
||||
#include <BAN/UniqPtr.h>
|
||||
#include <BAN/HashMap.h>
|
||||
#include <BAN/HashSet.h>
|
||||
|
||||
#include <LibGUI/Window.h>
|
||||
#include <BAN/String.h>
|
||||
#include <BAN/UniqPtr.h>
|
||||
#include <BAN/Vector.h>
|
||||
|
||||
#include <X11/Xproto.h>
|
||||
|
||||
@@ -18,15 +19,6 @@
|
||||
#define dprintln(...)
|
||||
#endif
|
||||
|
||||
typedef CARD32 ATOM;
|
||||
typedef CARD32 BITGRAVITY;
|
||||
typedef CARD32 COLORMAP;
|
||||
typedef CARD32 CURSOR;
|
||||
typedef CARD32 PIXMAP;
|
||||
typedef CARD32 VISUALID;
|
||||
typedef CARD32 WINDOW;
|
||||
typedef CARD32 WINGRAVITY;
|
||||
|
||||
struct Property
|
||||
{
|
||||
CARD8 format;
|
||||
@@ -60,6 +52,8 @@ struct Object
|
||||
|
||||
struct Window
|
||||
{
|
||||
Client& owner;
|
||||
|
||||
bool mapped { false };
|
||||
bool focused { false };
|
||||
bool fullscreen { false };
|
||||
@@ -72,33 +66,19 @@ struct Object
|
||||
CURSOR cursor;
|
||||
CARD16 c_class;
|
||||
BAN::Vector<WINDOW> children;
|
||||
BAN::Variant<
|
||||
BAN::UniqPtr<LibGUI::Window>,
|
||||
LibGUI::Texture
|
||||
> window;
|
||||
|
||||
uint32_t width { 0 };
|
||||
uint32_t height { 0 };
|
||||
BAN::Vector<uint32_t> pixels;
|
||||
|
||||
uint32_t background { 0 };
|
||||
|
||||
BAN::UniqPtr<PlatformWindow> platform_window;
|
||||
|
||||
BAN::HashMap<Client*, uint32_t> event_masks;
|
||||
|
||||
BAN::HashMap<ATOM, Property> properties;
|
||||
|
||||
LibGUI::Texture& texture()
|
||||
{
|
||||
if (window.has<LibGUI::Texture>())
|
||||
return window.get<LibGUI::Texture>();
|
||||
if (window.has<BAN::UniqPtr<LibGUI::Window>>())
|
||||
return window.get<BAN::UniqPtr<LibGUI::Window>>()->texture();
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
const LibGUI::Texture& texture() const
|
||||
{
|
||||
if (window.has<LibGUI::Texture>())
|
||||
return window.get<LibGUI::Texture>();
|
||||
if (window.has<BAN::UniqPtr<LibGUI::Window>>())
|
||||
return window.get<BAN::UniqPtr<LibGUI::Window>>()->texture();
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
uint32_t full_event_mask() const;
|
||||
BAN::ErrorOr<void> send_event(xEvent event, uint32_t event_mask);
|
||||
};
|
||||
@@ -181,17 +161,17 @@ struct EpollThingy
|
||||
enum class Type
|
||||
{
|
||||
Client,
|
||||
Window,
|
||||
Event,
|
||||
};
|
||||
|
||||
Type type;
|
||||
BAN::Variant<Client, LibGUI::Window*> value;
|
||||
BAN::Variant<Client, void*> value;
|
||||
};
|
||||
|
||||
extern const xPixmapFormat g_formats[6];
|
||||
extern const xWindowRoot g_root;
|
||||
extern const xDepth g_depth;
|
||||
extern const xVisualType g_visual;
|
||||
extern xWindowRoot g_root;
|
||||
|
||||
extern BAN::HashMap<CARD32, BAN::UniqPtr<Object>> g_objects;
|
||||
|
||||
|
||||
@@ -300,6 +300,9 @@ BAN::ErrorOr<void> poly_fill_rectangle(Client& client_info, BAN::ConstByteSpan p
|
||||
const int32_t max_x = BAN::Math::min<int32_t>(rect.x + rect.width, out_w);
|
||||
const int32_t max_y = BAN::Math::min<int32_t>(rect.y + rect.height, out_h);
|
||||
|
||||
if (min_x >= max_x || min_y >= max_y)
|
||||
continue;
|
||||
|
||||
for (int32_t y = min_y; y < max_y; y++)
|
||||
for (int32_t x = min_x; x < max_x; x++)
|
||||
if (!gc.is_clipped(x, y))
|
||||
@@ -351,6 +354,9 @@ BAN::ErrorOr<void> poly_fill_arc(Client& client_info, BAN::ConstByteSpan packet)
|
||||
const int32_t max_x = BAN::Math::min<int32_t>(out_w, arc.x + arc.width);
|
||||
const int32_t max_y = BAN::Math::min<int32_t>(out_h, arc.y + arc.height);
|
||||
|
||||
if (min_x >= max_x || min_y >= max_y)
|
||||
continue;
|
||||
|
||||
const auto rx = arc.width / 2;
|
||||
const auto ry = arc.height / 2;
|
||||
|
||||
|
||||
559
xbanan/Events.cpp
Normal file
559
xbanan/Events.cpp
Normal file
@@ -0,0 +1,559 @@
|
||||
#include "Base.h"
|
||||
#include "Definitions.h"
|
||||
#include "Keymap.h"
|
||||
#include "Utils.h"
|
||||
|
||||
#include <X11/X.h>
|
||||
#include <X11/Xatom.h>
|
||||
|
||||
#include <time.h>
|
||||
#include <sys/epoll.h>
|
||||
|
||||
void register_event_fd(int fd, void* data)
|
||||
{
|
||||
epoll_event event { .events = EPOLLIN, .data = { .fd = fd } };
|
||||
epoll_ctl(g_epoll_fd, EPOLL_CTL_ADD, fd, &event);
|
||||
|
||||
MUST(g_epoll_thingies.insert(fd, {
|
||||
.type = EpollThingy::Type::Event,
|
||||
.value = data,
|
||||
}));
|
||||
}
|
||||
|
||||
void unregister_event_fd(int fd)
|
||||
{
|
||||
epoll_ctl(g_epoll_fd, EPOLL_CTL_DEL, fd, nullptr);
|
||||
g_epoll_thingies.remove(fd);
|
||||
}
|
||||
|
||||
void on_window_close_event(WINDOW wid)
|
||||
{
|
||||
static CARD32 WM_PROTOCOLS = g_atoms_name_to_id["WM_PROTOCOLS"_sv];
|
||||
static CARD32 WM_DELETE_WINDOW = g_atoms_name_to_id["WM_DELETE_WINDOW"_sv];
|
||||
|
||||
auto& object = *g_objects[wid];
|
||||
ASSERT(object.type == Object::Type::Window);
|
||||
auto& window = object.object.get<Object::Window>();
|
||||
|
||||
const bool supports_wm_delete_winow =
|
||||
[&window]
|
||||
{
|
||||
auto wm_protocols_it = window.properties.find(WM_PROTOCOLS);
|
||||
if (wm_protocols_it == window.properties.end())
|
||||
return false;
|
||||
|
||||
const auto& wm_protocols = wm_protocols_it->value;
|
||||
if (wm_protocols.type != XA_ATOM || wm_protocols.format != 32)
|
||||
return false;
|
||||
|
||||
const auto atoms = BAN::ConstByteSpan(wm_protocols.data.span()).as_span<const CARD32>();
|
||||
for (auto atom : atoms)
|
||||
if (atom == WM_DELETE_WINDOW)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}();
|
||||
|
||||
if (!supports_wm_delete_winow)
|
||||
MUST(destroy_window(window.owner, wid));
|
||||
else
|
||||
{
|
||||
xEvent event { .u = {
|
||||
.clientMessage = {
|
||||
.window = wid,
|
||||
.u = { .l = {
|
||||
.type = WM_PROTOCOLS,
|
||||
.longs0 = static_cast<INT32>(WM_DELETE_WINDOW),
|
||||
.longs1 = static_cast<INT32>(time(nullptr)),
|
||||
}}
|
||||
}
|
||||
}};
|
||||
event.u.u.type = ClientMessage;
|
||||
event.u.u.detail = 32;
|
||||
event.u.u.sequenceNumber = window.owner.sequence;
|
||||
MUST(encode(window.owner.output_buffer, event));
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
MUST(window.pixels.resize(new_width * new_height));
|
||||
for (auto& pixel : window.pixels)
|
||||
pixel = window.background;
|
||||
}
|
||||
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
send_exposure_recursive(wid);
|
||||
|
||||
invalidate_window(wid, 0, 0, window.width, window.height);
|
||||
}
|
||||
|
||||
void on_window_focus_event(WINDOW wid, bool focused)
|
||||
{
|
||||
if (focused)
|
||||
g_focus_window = wid;
|
||||
|
||||
auto& object = *g_objects[wid];
|
||||
ASSERT(object.type == Object::Type::Window);
|
||||
|
||||
auto& window = object.object.get<Object::Window>();
|
||||
if (window.focused == focused)
|
||||
return;
|
||||
|
||||
window.focused = focused;
|
||||
|
||||
// FIXME: handle children
|
||||
|
||||
xEvent event { .u = {
|
||||
.focus = {
|
||||
.window = wid,
|
||||
.mode = NotifyNormal,
|
||||
}
|
||||
}};
|
||||
event.u.u.type = focused ? FocusIn : FocusOut,
|
||||
event.u.u.detail = NotifyNonlinear;
|
||||
MUST(window.send_event(event, FocusChangeMask));
|
||||
}
|
||||
|
||||
void on_window_fullscreen_event(WINDOW wid, bool is_fullscreen)
|
||||
{
|
||||
static CARD32 _NET_WM_STATE = g_atoms_name_to_id["_NET_WM_STATE"_sv];
|
||||
static CARD32 _NET_WM_STATE_FULLSCREEN = g_atoms_name_to_id["_NET_WM_STATE_FULLSCREEN"_sv];
|
||||
|
||||
auto window_it = g_objects.find(wid);
|
||||
if (window_it == g_objects.end() || window_it->value->type != Object::Type::Window)
|
||||
return;
|
||||
|
||||
auto& window = window_it->value->object.get<Object::Window>();
|
||||
|
||||
window.fullscreen = is_fullscreen;
|
||||
|
||||
auto it = window.properties.find(_NET_WM_STATE);
|
||||
if (it == window.properties.end())
|
||||
it = MUST(window.properties.emplace(_NET_WM_STATE));
|
||||
|
||||
auto& _net_wm_state = it->value;
|
||||
if (_net_wm_state.type != XA_ATOM || _net_wm_state.format != 32)
|
||||
_net_wm_state = {};
|
||||
|
||||
_net_wm_state.type = XA_ATOM;
|
||||
_net_wm_state.format = 32;
|
||||
|
||||
for (size_t i = 0; i + 4 <= _net_wm_state.data.size(); i += 4)
|
||||
{
|
||||
const auto atom = *reinterpret_cast<const CARD32*>(_net_wm_state.data.data() + i);
|
||||
if (atom != _NET_WM_STATE_FULLSCREEN)
|
||||
continue;
|
||||
_net_wm_state.data.remove(i);
|
||||
_net_wm_state.data.remove(i);
|
||||
_net_wm_state.data.remove(i);
|
||||
_net_wm_state.data.remove(i);
|
||||
i -= 4;
|
||||
}
|
||||
|
||||
if (is_fullscreen)
|
||||
{
|
||||
const size_t atom_count = _net_wm_state.data.size() / 4;
|
||||
MUST(_net_wm_state.data.resize(_net_wm_state.data.size() + 4));
|
||||
reinterpret_cast<CARD32*>(_net_wm_state.data.data())[atom_count] = _NET_WM_STATE_FULLSCREEN;
|
||||
}
|
||||
|
||||
xEvent event = { .u = {
|
||||
.property = {
|
||||
.window = wid,
|
||||
.atom = _NET_WM_STATE,
|
||||
.time = static_cast<CARD32>(time(nullptr)),
|
||||
.state = PropertyNewValue,
|
||||
}
|
||||
}};
|
||||
event.u.u.type = PropertyNotify;
|
||||
MUST(window.send_event(event, PropertyChangeMask));
|
||||
}
|
||||
|
||||
static void send_key_button_pointer_event(WINDOW root_wid, BYTE detail, uint32_t event_mask, BYTE event_type, KeyButMask state)
|
||||
{
|
||||
int32_t root_x, root_y;
|
||||
int32_t event_x, event_y;
|
||||
|
||||
{
|
||||
auto& object = *g_objects[root_wid];
|
||||
ASSERT(object.type == Object::Type::Window);
|
||||
auto& window = object.object.get<Object::Window>();
|
||||
root_x = event_x = window.cursor_x;
|
||||
root_y = event_y = window.cursor_y;
|
||||
}
|
||||
|
||||
const auto child_wid = find_child_window(root_wid, event_x, event_y);
|
||||
|
||||
auto wid = child_wid;
|
||||
while (wid != None)
|
||||
{
|
||||
auto& object = *g_objects[wid];
|
||||
ASSERT(object.type == Object::Type::Window);
|
||||
auto& window = object.object.get<Object::Window>();
|
||||
if (window.full_event_mask() & event_mask)
|
||||
break;
|
||||
|
||||
event_x += window.x;
|
||||
event_y += window.y;
|
||||
wid = window.parent;
|
||||
}
|
||||
|
||||
if (wid == None)
|
||||
{
|
||||
if (event_type == MotionNotify && g_butmask == 0)
|
||||
return;
|
||||
wid = root_wid;
|
||||
}
|
||||
|
||||
auto& object = *g_objects[wid];
|
||||
ASSERT(object.type == Object::Type::Window);
|
||||
auto& window = object.object.get<Object::Window>();
|
||||
|
||||
xEvent event { .u = {
|
||||
.keyButtonPointer = {
|
||||
.time = static_cast<CARD32>(time(nullptr)),
|
||||
.root = g_root.windowId,
|
||||
.event = wid,
|
||||
.child = static_cast<CARD32>(child_wid == wid ? None : child_wid),
|
||||
.rootX = static_cast<INT16>(root_x),
|
||||
.rootY = static_cast<INT16>(root_y),
|
||||
.eventX = static_cast<INT16>(event_x),
|
||||
.eventY = static_cast<INT16>(event_y),
|
||||
.state = state,
|
||||
.sameScreen = xTrue,
|
||||
}
|
||||
}};
|
||||
event.u.u.type = event_type,
|
||||
event.u.u.detail = detail;
|
||||
MUST(window.send_event(event, event_mask));
|
||||
}
|
||||
|
||||
static void update_cursor_position_recursive(WINDOW wid, int32_t new_x, int32_t new_y)
|
||||
{
|
||||
auto& object = *g_objects[wid];
|
||||
ASSERT(object.type == Object::Type::Window);
|
||||
auto& window = object.object.get<Object::Window>();
|
||||
|
||||
window.cursor_x = new_x;
|
||||
window.cursor_y = new_y;
|
||||
|
||||
for (auto child_wid : window.children)
|
||||
{
|
||||
auto& child_object = *g_objects[child_wid];
|
||||
ASSERT(child_object.type == Object::Type::Window);
|
||||
auto& child_window = child_object.object.get<Object::Window>();
|
||||
update_cursor_position_recursive(child_wid, new_x - child_window.x, new_y - child_window.y);
|
||||
}
|
||||
}
|
||||
|
||||
static void update_cursor(WINDOW wid, int32_t old_x, int32_t old_y, int32_t new_x, int32_t new_y)
|
||||
{
|
||||
const auto old_wid = find_child_window(wid, old_x, old_y);
|
||||
const auto new_wid = find_child_window(wid, new_x, new_y);
|
||||
if (old_wid == new_wid || old_wid == None || new_wid == None)
|
||||
return;
|
||||
|
||||
const auto& old_window = g_objects[old_wid]->object.get<Object::Window>();
|
||||
const auto& new_window = g_objects[new_wid]->object.get<Object::Window>();
|
||||
if (old_window.cursor == new_window.cursor)
|
||||
return;
|
||||
|
||||
auto& window = g_objects[wid]->object.get<Object::Window>();
|
||||
const auto& cursor = get_cursor_safe(window.cursor);
|
||||
|
||||
if (g_platform_ops.set_cursor)
|
||||
{
|
||||
g_platform_ops.set_cursor(
|
||||
window.platform_window.ptr(),
|
||||
cursor.pixels.data(),
|
||||
cursor.width, cursor.height,
|
||||
cursor.origin_x, cursor.origin_y
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static BAN::Vector<WINDOW> get_path_to_child(WINDOW wid, int32_t x, int32_t y)
|
||||
{
|
||||
BAN::Vector<WINDOW> result;
|
||||
|
||||
const auto window_contains =
|
||||
[](const Object::Window& window, int32_t x, int32_t y) -> bool
|
||||
{
|
||||
return x >= 0 && y >= 0 && x < window.width && y < window.height;
|
||||
};
|
||||
|
||||
for (;;)
|
||||
{
|
||||
const auto& object = *g_objects[wid];
|
||||
ASSERT(object.type == Object::Type::Window);
|
||||
|
||||
const auto& window = object.object.get<Object::Window>();
|
||||
if (!window_contains(window, x, y))
|
||||
break;
|
||||
|
||||
MUST(result.push_back(wid));
|
||||
|
||||
const WINDOW old_wid = wid;
|
||||
for (auto child_wid : window.children)
|
||||
{
|
||||
const auto& child_object = *g_objects[child_wid];
|
||||
ASSERT(child_object.type == Object::Type::Window);
|
||||
|
||||
const auto& child_window = child_object.object.get<Object::Window>();
|
||||
if (!window_contains(child_window, x - child_window.x, y - child_window.y))
|
||||
continue;
|
||||
wid = child_wid;
|
||||
break;
|
||||
}
|
||||
|
||||
if (old_wid == wid)
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void send_enter_and_leave_events(WINDOW wid, int32_t old_x, int32_t old_y, int32_t new_x, int32_t new_y)
|
||||
{
|
||||
// FIXME: correct event_x and event_y values in events
|
||||
|
||||
const auto old_child_path = get_path_to_child(wid, old_x, old_y);
|
||||
const auto new_child_path = get_path_to_child(wid, new_x, new_y);
|
||||
|
||||
size_t common_ancestors = 0;
|
||||
while (common_ancestors < old_child_path.size() && common_ancestors < new_child_path.size())
|
||||
{
|
||||
if (old_child_path[common_ancestors] != new_child_path[common_ancestors])
|
||||
break;
|
||||
common_ancestors++;
|
||||
}
|
||||
|
||||
if (old_child_path.size() == common_ancestors && new_child_path.size() == common_ancestors)
|
||||
return;
|
||||
|
||||
const bool linear = (common_ancestors == old_child_path.size() || common_ancestors == new_child_path.size());
|
||||
|
||||
const auto get_flags =
|
||||
[](WINDOW wid) -> BYTE
|
||||
{
|
||||
return ELFlagSameScreen | (g_focus_window == wid ? ELFlagFocus : 0);
|
||||
};
|
||||
|
||||
size_t leave_events = old_child_path.size() - common_ancestors;
|
||||
if (linear && common_ancestors && old_child_path.size() < new_child_path.size())
|
||||
leave_events++;
|
||||
|
||||
size_t enter_events = new_child_path.size() - common_ancestors;
|
||||
if (linear && common_ancestors && new_child_path.size() < old_child_path.size())
|
||||
enter_events++;
|
||||
|
||||
for (size_t i = 0; i < leave_events; i++)
|
||||
{
|
||||
const bool first = (i == 0);
|
||||
const BYTE detail =
|
||||
[&]() -> BYTE {
|
||||
if (!linear)
|
||||
return first ? NotifyNonlinear : NotifyNonlinearVirtual;
|
||||
if (!first)
|
||||
return NotifyVirtual;
|
||||
return (old_child_path.size() > new_child_path.size())
|
||||
? NotifyAncestor
|
||||
: NotifyInferior;
|
||||
}();
|
||||
|
||||
const auto& wid = old_child_path[old_child_path.size() - i - 1];
|
||||
|
||||
auto& object = *g_objects[wid];
|
||||
ASSERT(object.type == Object::Type::Window);
|
||||
auto& window = object.object.get<Object::Window>();
|
||||
|
||||
xEvent event { .u = {
|
||||
.enterLeave = {
|
||||
.time = static_cast<CARD32>(time(nullptr)),
|
||||
.root = g_root.windowId,
|
||||
.event = wid,
|
||||
.child = first ? static_cast<WINDOW>(None) : old_child_path.back(),
|
||||
.rootX = static_cast<INT16>(old_x),
|
||||
.rootY = static_cast<INT16>(old_y),
|
||||
.eventX = static_cast<INT16>(old_x),
|
||||
.eventY = static_cast<INT16>(old_y),
|
||||
.state = static_cast<KeyButMask>(g_keymask | g_butmask),
|
||||
.mode = NotifyNormal,
|
||||
.flags = get_flags(wid),
|
||||
}
|
||||
}};
|
||||
event.u.u.type = LeaveNotify,
|
||||
event.u.u.detail = detail;
|
||||
MUST(window.send_event(event, LeaveWindowMask));
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < enter_events; i++)
|
||||
{
|
||||
const bool last = (i == enter_events - 1);
|
||||
const BYTE detail =
|
||||
[&]() -> BYTE {
|
||||
if (!linear)
|
||||
return last ? NotifyNonlinear : NotifyNonlinearVirtual;
|
||||
if (!last)
|
||||
return NotifyVirtual;
|
||||
return (old_child_path.size() > new_child_path.size())
|
||||
? NotifyInferior
|
||||
: NotifyAncestor;
|
||||
}();
|
||||
|
||||
const auto& wid = new_child_path[new_child_path.size() - enter_events + i];
|
||||
|
||||
auto& object = *g_objects[wid];
|
||||
ASSERT(object.type == Object::Type::Window);
|
||||
auto& window = object.object.get<Object::Window>();
|
||||
|
||||
xEvent event { .u = {
|
||||
.enterLeave = {
|
||||
.time = static_cast<CARD32>(time(nullptr)),
|
||||
.root = g_root.windowId,
|
||||
.event = wid,
|
||||
.child = last ? static_cast<WINDOW>(None) : new_child_path.back(),
|
||||
.rootX = static_cast<INT16>(new_x),
|
||||
.rootY = static_cast<INT16>(new_y),
|
||||
.eventX = static_cast<INT16>(new_x),
|
||||
.eventY = static_cast<INT16>(new_y),
|
||||
.state = static_cast<KeyButMask>(g_keymask | g_butmask),
|
||||
.mode = NotifyNormal,
|
||||
.flags = get_flags(wid),
|
||||
}
|
||||
}};
|
||||
event.u.u.type = EnterNotify,
|
||||
event.u.u.detail = detail;
|
||||
MUST(window.send_event(event, EnterWindowMask));
|
||||
}
|
||||
}
|
||||
|
||||
void on_mouse_move_event(WINDOW wid, int32_t x, int32_t y)
|
||||
{
|
||||
auto& object = *g_objects[wid];
|
||||
ASSERT(object.type == Object::Type::Window);
|
||||
auto& window = object.object.get<Object::Window>();
|
||||
|
||||
update_cursor(wid, window.cursor_x, window.cursor_y, x, y);
|
||||
|
||||
send_enter_and_leave_events(wid, window.cursor_x, window.cursor_y, x, y);
|
||||
|
||||
update_cursor_position_recursive(wid, x, y);
|
||||
|
||||
// TODO: optimize with PointerMotionHint
|
||||
uint32_t event_mask = PointerMotionMask | PointerMotionHintMask;
|
||||
if (g_butmask) event_mask |= ButtonMotionMask;
|
||||
if (g_butmask & Button1Mask) event_mask |= Button1MotionMask;
|
||||
if (g_butmask & Button2Mask) event_mask |= Button2MotionMask;
|
||||
if (g_butmask & Button3Mask) event_mask |= Button3MotionMask;
|
||||
if (g_butmask & Button4Mask) event_mask |= Button4MotionMask;
|
||||
if (g_butmask & Button5Mask) event_mask |= Button5MotionMask;
|
||||
send_key_button_pointer_event(wid, NotifyNormal, event_mask, MotionNotify, g_keymask | g_butmask);
|
||||
}
|
||||
|
||||
void on_mouse_button_event(WINDOW wid, uint8_t xbutton, bool pressed)
|
||||
{
|
||||
uint16_t mask = 0;
|
||||
switch (xbutton)
|
||||
{
|
||||
case Button1: mask = Button1Mask; break;
|
||||
case Button2: mask = Button2Mask; break;
|
||||
case Button3: mask = Button3Mask; break;
|
||||
case Button4: mask = Button4Mask; break;
|
||||
case Button5: mask = Button5Mask; break;
|
||||
}
|
||||
|
||||
const auto old_state = g_keymask | g_butmask;
|
||||
|
||||
if (pressed)
|
||||
g_butmask |= mask;
|
||||
else
|
||||
g_butmask &= ~mask;
|
||||
|
||||
send_key_button_pointer_event(
|
||||
wid,
|
||||
xbutton,
|
||||
pressed ? ButtonPressMask : ButtonReleaseMask,
|
||||
pressed ? ButtonPress : ButtonRelease,
|
||||
old_state
|
||||
);
|
||||
}
|
||||
|
||||
void on_key_event(WINDOW wid, uint8_t scancode, uint8_t xmod, bool pressed)
|
||||
{
|
||||
const uint8_t xkeycode = scancode + g_keymap_min_keycode;
|
||||
if (xkeycode < g_keymap_min_keycode)
|
||||
{
|
||||
dwarnln("cannot send keycode {}", xkeycode);
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
const uint8_t byte = xkeycode / 8;
|
||||
const uint8_t bit = xkeycode % 8;
|
||||
if (pressed)
|
||||
g_pressed_keys[byte] |= 1 << bit;
|
||||
else
|
||||
g_pressed_keys[byte] &= ~(1 << bit);
|
||||
}
|
||||
|
||||
const auto old_state = g_keymask | g_butmask;
|
||||
|
||||
g_keymask = xmod;
|
||||
|
||||
send_key_button_pointer_event(
|
||||
wid,
|
||||
xkeycode,
|
||||
pressed ? KeyPressMask : KeyReleaseMask,
|
||||
pressed ? KeyPress : KeyRelease,
|
||||
old_state
|
||||
);
|
||||
}
|
||||
15
xbanan/Events.h
Normal file
15
xbanan/Events.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
void register_event_fd(int fd, void* data);
|
||||
void unregister_event_fd(int fd);
|
||||
|
||||
void on_window_close_event(WINDOW wid);
|
||||
void on_window_resize_event(WINDOW wid, uint32_t width, uint32_t height);
|
||||
void on_window_focus_event(WINDOW wid, bool focused);
|
||||
void on_window_fullscreen_event(WINDOW wid, bool is_fullscreen);
|
||||
|
||||
void on_mouse_move_event(WINDOW wid, int32_t x, int32_t y);
|
||||
void on_mouse_button_event(WINDOW wid, uint8_t xbutton, bool pressed);
|
||||
void on_key_event(WINDOW wid, uint8_t scancode, uint8_t xmod, bool pressed);
|
||||
@@ -337,7 +337,7 @@ BAN::ErrorOr<void> extension_glx(Client& client_info, BAN::ConstByteSpan packet)
|
||||
|
||||
const auto& object = g_objects[request.drawable];
|
||||
ASSERT(object->type == Object::Type::Window);
|
||||
const auto& texture = object->object.get<Object::Window>().texture();
|
||||
const auto& window = object->object.get<Object::Window>();
|
||||
|
||||
xGLXGetDrawableAttributesReply reply {
|
||||
.type = X_Reply,
|
||||
@@ -348,16 +348,16 @@ BAN::ErrorOr<void> extension_glx(Client& client_info, BAN::ConstByteSpan packet)
|
||||
TRY(encode(client_info.output_buffer, reply));
|
||||
|
||||
TRY(encode<CARD32>(client_info.output_buffer, GLX_WIDTH));
|
||||
TRY(encode<CARD32>(client_info.output_buffer, texture.width()));
|
||||
TRY(encode<CARD32>(client_info.output_buffer, window.width));
|
||||
|
||||
TRY(encode<CARD32>(client_info.output_buffer, GLX_HEIGHT));
|
||||
TRY(encode<CARD32>(client_info.output_buffer, texture.height()));
|
||||
TRY(encode<CARD32>(client_info.output_buffer, window.height));
|
||||
|
||||
TRY(encode<CARD32>(client_info.output_buffer, GLX_PRESERVED_CONTENTS));
|
||||
TRY(encode<CARD32>(client_info.output_buffer, xTrue));
|
||||
|
||||
TRY(encode<CARD32>(client_info.output_buffer, GLX_LARGEST_PBUFFER));
|
||||
TRY(encode<CARD32>(client_info.output_buffer, texture.width() * texture.height()));
|
||||
TRY(encode<CARD32>(client_info.output_buffer, window.width * window.height));
|
||||
|
||||
TRY(encode<CARD32>(client_info.output_buffer, GLX_FBCONFIG_ID));
|
||||
TRY(encode<CARD32>(client_info.output_buffer, 1));
|
||||
|
||||
@@ -159,7 +159,6 @@ static BAN::ErrorOr<void> extension_shm(Client& client_info, BAN::ConstByteSpan
|
||||
{
|
||||
auto request = decode<xShmPutImageReq>(packet).value();
|
||||
|
||||
#if 0
|
||||
dprintln("ShmPutImage");
|
||||
dprintln(" drawable: {}", request.drawable);
|
||||
dprintln(" gc: {}", request.gc);
|
||||
@@ -176,7 +175,6 @@ static BAN::ErrorOr<void> extension_shm(Client& client_info, BAN::ConstByteSpan
|
||||
dprintln(" sendEvent: {}", request.sendEvent);
|
||||
dprintln(" shmseg: {}", request.shmseg);
|
||||
dprintln(" offset: {}", request.offset);
|
||||
#endif
|
||||
|
||||
void* shm_segment = TRY(get_shmseg(client_info, request.shmseg, op_major, op_minor));
|
||||
|
||||
|
||||
@@ -784,7 +784,7 @@ static void write_text(WriteTextInfo& info)
|
||||
? info.gc.foreground
|
||||
: info.gc.background;
|
||||
|
||||
if (color != LibGUI::Texture::color_invisible)
|
||||
if (color != COLOR_INVISIBLE)
|
||||
info.out_data_u32[out_y * info.out_w + out_x] = color;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
|
||||
uint32_t g_keymap[0x100][g_keymap_layers];
|
||||
|
||||
uint8_t g_pressed_keys[32] {};
|
||||
|
||||
static constexpr uint32_t my_key_to_x_keysym(LibInput::Key key)
|
||||
{
|
||||
using LibInput::Key;
|
||||
|
||||
@@ -11,3 +11,5 @@ constexpr size_t g_keymap_min_keycode = 8;
|
||||
constexpr size_t g_keymap_max_keycode = 255;
|
||||
constexpr size_t g_keymap_layers = 4;
|
||||
extern uint32_t g_keymap[0x100][g_keymap_layers];
|
||||
|
||||
extern uint8_t g_pressed_keys[32];
|
||||
|
||||
30
xbanan/Platform.h
Normal file
30
xbanan/Platform.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
#include <BAN/UniqPtr.h>
|
||||
|
||||
struct PlatformWindow
|
||||
{
|
||||
virtual ~PlatformWindow() = default;
|
||||
};
|
||||
|
||||
// initialize, poll_events, create_window and invalidate are required
|
||||
struct PlatformOps
|
||||
{
|
||||
/* Do platform initialization */
|
||||
bool (*initialize)(uint32_t* width, uint32_t* height);
|
||||
/* Handle pending events */
|
||||
void (*poll_events)(void*);
|
||||
/* Create a window with given size */
|
||||
BAN::ErrorOr<BAN::UniqPtr<PlatformWindow>> (*create_window)(WINDOW wid, 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);
|
||||
/* Request resize of a window, can be async */
|
||||
void (*request_resize)(PlatformWindow*, uint32_t width, uint32_t height);
|
||||
/* Request new fullscreen state, can be async */
|
||||
void (*request_fullscreen)(PlatformWindow*, bool fullscreen);
|
||||
/* Set custom cursor */
|
||||
void (*set_cursor)(PlatformWindow*, const uint32_t* pixels, uint32_t width, uint32_t height, int32_t origin_x, int32_t origin_y);
|
||||
};
|
||||
extern PlatformOps g_platform_ops;
|
||||
441
xbanan/SDL2/sdl2.cpp
Normal file
441
xbanan/SDL2/sdl2.cpp
Normal file
@@ -0,0 +1,441 @@
|
||||
#include "../Events.h"
|
||||
#include "../Platform.h"
|
||||
|
||||
#include <BAN/Atomic.h>
|
||||
#include <BAN/HashMap.h>
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
|
||||
#include <pthread.h>
|
||||
#include <sys/eventfd.h>
|
||||
#include <unistd.h>
|
||||
|
||||
BAN::HashMap<uint32_t, struct SDLWindow*> s_window_map;
|
||||
|
||||
struct SDLWindow final : public PlatformWindow
|
||||
{
|
||||
~SDLWindow()
|
||||
{
|
||||
if (texture != nullptr)
|
||||
SDL_DestroyTexture(texture);
|
||||
|
||||
if (renderer != nullptr)
|
||||
SDL_DestroyRenderer(renderer);
|
||||
|
||||
if (window != nullptr)
|
||||
{
|
||||
s_window_map.remove(SDL_GetWindowID(window));
|
||||
SDL_DestroyWindow(window);
|
||||
}
|
||||
}
|
||||
|
||||
WINDOW wid;
|
||||
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
|
||||
SDL_Window* window { nullptr };
|
||||
SDL_Renderer* renderer { nullptr };
|
||||
SDL_Texture* texture { nullptr };
|
||||
};
|
||||
|
||||
static int s_eventfd { -1 };
|
||||
|
||||
struct Keymap
|
||||
{
|
||||
consteval Keymap();
|
||||
uint8_t map[SDL_NUM_SCANCODES];
|
||||
};
|
||||
static Keymap s_sdl_keymap;
|
||||
|
||||
static void* sdl2_thread(void*)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
const uint64_t value { 1 };
|
||||
write(s_eventfd, &value, sizeof(value));
|
||||
usleep(16'666);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static bool sdl2_initialize(uint32_t* display_w, uint32_t* display_h)
|
||||
{
|
||||
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) == -1)
|
||||
{
|
||||
dwarnln("Could not initialize SDL: {}", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
SDL_DisplayMode DM;
|
||||
if (SDL_GetCurrentDisplayMode(0, &DM) == -1)
|
||||
{
|
||||
dwarnln("Could not get display mode: {}", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
*display_w = DM.w;
|
||||
*display_h = DM.h;
|
||||
|
||||
s_eventfd = eventfd(0, 0);
|
||||
if (s_eventfd == -1)
|
||||
{
|
||||
dwarnln("Could not create eventfd: {}", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
register_event_fd(s_eventfd, nullptr);
|
||||
|
||||
pthread_t thread;
|
||||
pthread_create(&thread, nullptr, sdl2_thread, nullptr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool sdl2_init_window(SDLWindow& window, uint32_t width, uint32_t height)
|
||||
{
|
||||
window.renderer = SDL_CreateRenderer(window.window, -1, SDL_RENDERER_ACCELERATED);
|
||||
if (window.renderer == nullptr)
|
||||
{
|
||||
dwarnln("Could not create SDL renderer: {}\n", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
window.texture = SDL_CreateTexture(window.renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, width, height);
|
||||
if (window.texture == nullptr)
|
||||
{
|
||||
dwarnln("Could not create SDL texture: {}\n", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static BAN::ErrorOr<BAN::UniqPtr<PlatformWindow>> sdl2_create_window(WINDOW wid, uint32_t width, uint32_t height)
|
||||
{
|
||||
auto window = TRY(BAN::UniqPtr<SDLWindow>::create());
|
||||
|
||||
window->wid = wid;
|
||||
window->width = width;
|
||||
window->height = height;
|
||||
|
||||
const auto flags = SDL_WINDOW_RESIZABLE | SDL_WINDOW_UTILITY;
|
||||
window->window = SDL_CreateWindow("", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, flags);
|
||||
if (window->window == nullptr)
|
||||
{
|
||||
dwarnln("Could not create SDL window: {}", SDL_GetError());
|
||||
return BAN::Error::from_errno(EFAULT);
|
||||
}
|
||||
|
||||
if (!sdl2_init_window(*window, width, height))
|
||||
return BAN::Error::from_errno(EFAULT);
|
||||
|
||||
TRY(s_window_map.insert(SDL_GetWindowID(window->window), window.ptr()));
|
||||
|
||||
return BAN::UniqPtr<PlatformWindow>(BAN::move(window));
|
||||
}
|
||||
|
||||
static void sdl2_request_resize(PlatformWindow* window, uint32_t width, uint32_t height)
|
||||
{
|
||||
auto& sdl_window = *static_cast<SDLWindow*>(window);
|
||||
SDL_SetWindowSize(sdl_window.window, width, height);
|
||||
}
|
||||
|
||||
static void sdl2_poll_events(void*)
|
||||
{
|
||||
uint64_t dummy;
|
||||
read(s_eventfd, &dummy, sizeof(dummy));
|
||||
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event))
|
||||
{
|
||||
switch (event.type)
|
||||
{
|
||||
case SDL_WINDOWEVENT:
|
||||
{
|
||||
auto it = s_window_map.find(event.window.windowID);
|
||||
if (it == s_window_map.end())
|
||||
break;
|
||||
auto& window = *it->value;
|
||||
switch (event.window.event)
|
||||
{
|
||||
case SDL_WINDOWEVENT_CLOSE:
|
||||
on_window_close_event(window.wid);
|
||||
break;
|
||||
case SDL_WINDOWEVENT_SIZE_CHANGED:
|
||||
window.width = event.window.data1;
|
||||
window.height = event.window.data2;
|
||||
|
||||
SDL_DestroyTexture(window.texture);
|
||||
window.texture = SDL_CreateTexture(window.renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, window.width, window.height);
|
||||
ASSERT(window.texture);
|
||||
|
||||
on_window_resize_event(window.wid, event.window.data1, event.window.data2);
|
||||
break;
|
||||
case SDL_WINDOWEVENT_FOCUS_GAINED:
|
||||
on_window_focus_event(window.wid, true);
|
||||
break;
|
||||
case SDL_WINDOWEVENT_FOCUS_LOST:
|
||||
on_window_focus_event(window.wid, false);
|
||||
break;
|
||||
case SDL_WINDOWEVENT_MAXIMIZED:
|
||||
on_window_fullscreen_event(window.wid, true);
|
||||
break;
|
||||
case SDL_WINDOWEVENT_RESTORED:
|
||||
on_window_fullscreen_event(window.wid, false);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SDL_MOUSEMOTION:
|
||||
{
|
||||
auto it = s_window_map.find(event.window.windowID);
|
||||
if (it != s_window_map.end())
|
||||
on_mouse_move_event(it->value->wid, event.motion.x, event.motion.y);
|
||||
break;
|
||||
}
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
{
|
||||
uint8_t xbutton { 0 };
|
||||
switch (event.button.button)
|
||||
{
|
||||
case SDL_BUTTON_LEFT: xbutton = 1; break;
|
||||
case SDL_BUTTON_MIDDLE: xbutton = 2; break;
|
||||
case SDL_BUTTON_RIGHT: xbutton = 3; break;
|
||||
case SDL_BUTTON_X1: xbutton = 8; break;
|
||||
case SDL_BUTTON_X2: xbutton = 9; break;
|
||||
}
|
||||
|
||||
auto it = s_window_map.find(event.window.windowID);
|
||||
if (xbutton && it != s_window_map.end())
|
||||
on_mouse_button_event(it->value->wid, xbutton, (event.type == SDL_MOUSEBUTTONDOWN));
|
||||
break;
|
||||
}
|
||||
case SDL_MOUSEWHEEL:
|
||||
{
|
||||
uint8_t xbutton { 0 };
|
||||
if (event.wheel.y > 0)
|
||||
xbutton = 4;
|
||||
if (event.wheel.y < 0)
|
||||
xbutton = 5;
|
||||
|
||||
auto it = s_window_map.find(event.window.windowID);
|
||||
if (xbutton && it != s_window_map.end())
|
||||
{
|
||||
on_mouse_button_event(it->value->wid, xbutton, true);
|
||||
on_mouse_button_event(it->value->wid, xbutton, false);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case SDL_KEYUP:
|
||||
case SDL_KEYDOWN:
|
||||
{
|
||||
uint8_t scancode = s_sdl_keymap.map[event.key.keysym.scancode];
|
||||
|
||||
uint8_t xmod { 0 };
|
||||
if (event.key.keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT))
|
||||
xmod |= (1 << 0);
|
||||
if (event.key.keysym.mod & (KMOD_CAPS))
|
||||
xmod |= (1 << 1);
|
||||
if (event.key.keysym.mod & (KMOD_LCTRL | KMOD_RCTRL))
|
||||
xmod |= (1 << 2);
|
||||
if (event.key.keysym.mod & (KMOD_LALT | KMOD_RALT))
|
||||
xmod |= (1 << 3);
|
||||
|
||||
auto it = s_window_map.find(event.window.windowID);
|
||||
if (it != s_window_map.end())
|
||||
on_key_event(it->value->wid, scancode, xmod, (event.type == SDL_KEYDOWN));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void sdl2_invalidate(PlatformWindow* window, const uint32_t* src_pixels, uint32_t x, uint32_t y, uint32_t width, uint32_t height)
|
||||
{
|
||||
auto& sdl_window = *static_cast<SDLWindow*>(window);
|
||||
|
||||
ASSERT(x < sdl_window.width && width <= sdl_window.width - x);
|
||||
ASSERT(y < sdl_window.height && height <= sdl_window.height - y);
|
||||
|
||||
const SDL_Rect rect {
|
||||
.x = static_cast<int>(x),
|
||||
.y = static_cast<int>(y),
|
||||
.w = static_cast<int>(width),
|
||||
.h = static_cast<int>(height),
|
||||
};
|
||||
|
||||
void* dst_pixels;
|
||||
int dst_pitch;
|
||||
if (SDL_LockTexture(sdl_window.texture, &rect, &dst_pixels, &dst_pitch) == -1)
|
||||
{
|
||||
dwarnln("Could not lock texture: {}", SDL_GetError());
|
||||
return;
|
||||
}
|
||||
|
||||
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],
|
||||
rect.w * sizeof(uint32_t)
|
||||
);
|
||||
}
|
||||
|
||||
SDL_UnlockTexture(sdl_window.texture);
|
||||
|
||||
SDL_RenderClear(sdl_window.renderer);
|
||||
SDL_RenderCopy(sdl_window.renderer, sdl_window.texture, NULL, NULL);
|
||||
SDL_RenderPresent(sdl_window.renderer);
|
||||
}
|
||||
|
||||
static void sdl2_set_cursor(PlatformWindow* window, const uint32_t* pixels, uint32_t width, uint32_t height, int32_t origin_x, int32_t origin_y)
|
||||
{
|
||||
auto& sdl_window = *static_cast<SDLWindow*>(window);
|
||||
(void)sdl_window;
|
||||
(void)pixels;
|
||||
(void)width;
|
||||
(void)height;
|
||||
(void)origin_x;
|
||||
(void)origin_y;
|
||||
}
|
||||
|
||||
static void sdl2_request_fullscreen(PlatformWindow* window, bool fullscreen)
|
||||
{
|
||||
auto& sdl_window = *static_cast<SDLWindow*>(window);
|
||||
SDL_SetWindowFullscreen(sdl_window.window, fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
|
||||
}
|
||||
|
||||
PlatformOps g_platform_ops = {
|
||||
.initialize = sdl2_initialize,
|
||||
.poll_events = sdl2_poll_events,
|
||||
.create_window = sdl2_create_window,
|
||||
.invalidate = sdl2_invalidate,
|
||||
.request_resize = sdl2_request_resize,
|
||||
.request_fullscreen = sdl2_request_fullscreen,
|
||||
.set_cursor = sdl2_set_cursor,
|
||||
};
|
||||
|
||||
#include <LibInput/KeyEvent.h>
|
||||
|
||||
consteval Keymap::Keymap()
|
||||
{
|
||||
for (auto& scancode : map)
|
||||
scancode = 0;
|
||||
|
||||
using LibInput::keycode_normal;
|
||||
using LibInput::keycode_function;
|
||||
using LibInput::keycode_numpad;
|
||||
|
||||
map[SDL_SCANCODE_GRAVE] = keycode_normal(0, 0);
|
||||
map[SDL_SCANCODE_1] = keycode_normal(0, 1);
|
||||
map[SDL_SCANCODE_2] = keycode_normal(0, 2);
|
||||
map[SDL_SCANCODE_3] = keycode_normal(0, 3);
|
||||
map[SDL_SCANCODE_4] = keycode_normal(0, 4);
|
||||
map[SDL_SCANCODE_5] = keycode_normal(0, 5);
|
||||
map[SDL_SCANCODE_6] = keycode_normal(0, 6);
|
||||
map[SDL_SCANCODE_7] = keycode_normal(0, 7);
|
||||
map[SDL_SCANCODE_8] = keycode_normal(0, 8);
|
||||
map[SDL_SCANCODE_9] = keycode_normal(0, 9);
|
||||
map[SDL_SCANCODE_0] = keycode_normal(0, 10);
|
||||
map[SDL_SCANCODE_MINUS] = keycode_normal(0, 11);
|
||||
map[SDL_SCANCODE_EQUALS] = keycode_normal(0, 12);
|
||||
map[SDL_SCANCODE_BACKSPACE] = keycode_normal(0, 13);
|
||||
|
||||
map[SDL_SCANCODE_TAB] = keycode_normal(1, 0);
|
||||
map[SDL_SCANCODE_Q] = keycode_normal(1, 1);
|
||||
map[SDL_SCANCODE_W] = keycode_normal(1, 2);
|
||||
map[SDL_SCANCODE_E] = keycode_normal(1, 3);
|
||||
map[SDL_SCANCODE_R] = keycode_normal(1, 4);
|
||||
map[SDL_SCANCODE_T] = keycode_normal(1, 5);
|
||||
map[SDL_SCANCODE_Y] = keycode_normal(1, 6);
|
||||
map[SDL_SCANCODE_U] = keycode_normal(1, 7);
|
||||
map[SDL_SCANCODE_I] = keycode_normal(1, 8);
|
||||
map[SDL_SCANCODE_O] = keycode_normal(1, 9);
|
||||
map[SDL_SCANCODE_P] = keycode_normal(1, 10);
|
||||
map[SDL_SCANCODE_LEFTBRACKET] = keycode_normal(1, 11);
|
||||
map[SDL_SCANCODE_RIGHTBRACKET] = keycode_normal(1, 12);
|
||||
|
||||
map[SDL_SCANCODE_CAPSLOCK] = keycode_normal(2, 0);
|
||||
map[SDL_SCANCODE_A] = keycode_normal(2, 1);
|
||||
map[SDL_SCANCODE_S] = keycode_normal(2, 2);
|
||||
map[SDL_SCANCODE_D] = keycode_normal(2, 3);
|
||||
map[SDL_SCANCODE_F] = keycode_normal(2, 4);
|
||||
map[SDL_SCANCODE_G] = keycode_normal(2, 5);
|
||||
map[SDL_SCANCODE_H] = keycode_normal(2, 6);
|
||||
map[SDL_SCANCODE_J] = keycode_normal(2, 7);
|
||||
map[SDL_SCANCODE_K] = keycode_normal(2, 8);
|
||||
map[SDL_SCANCODE_L] = keycode_normal(2, 9);
|
||||
map[SDL_SCANCODE_SEMICOLON] = keycode_normal(2, 10);
|
||||
map[SDL_SCANCODE_APOSTROPHE] = keycode_normal(2, 11);
|
||||
map[SDL_SCANCODE_BACKSLASH] = keycode_normal(2, 12);
|
||||
map[SDL_SCANCODE_RETURN] = keycode_normal(2, 13);
|
||||
|
||||
map[SDL_SCANCODE_LSHIFT] = keycode_normal(3, 0);
|
||||
map[SDL_SCANCODE_NONUSBACKSLASH] = keycode_normal(3, 1);
|
||||
map[SDL_SCANCODE_Z] = keycode_normal(3, 2);
|
||||
map[SDL_SCANCODE_X] = keycode_normal(3, 3);
|
||||
map[SDL_SCANCODE_C] = keycode_normal(3, 4);
|
||||
map[SDL_SCANCODE_V] = keycode_normal(3, 5);
|
||||
map[SDL_SCANCODE_B] = keycode_normal(3, 6);
|
||||
map[SDL_SCANCODE_N] = keycode_normal(3, 7);
|
||||
map[SDL_SCANCODE_M] = keycode_normal(3, 8);
|
||||
map[SDL_SCANCODE_COMMA] = keycode_normal(3, 9);
|
||||
map[SDL_SCANCODE_PERIOD] = keycode_normal(3, 10);
|
||||
map[SDL_SCANCODE_SLASH] = keycode_normal(3, 11);
|
||||
map[SDL_SCANCODE_RSHIFT] = keycode_normal(3, 12);
|
||||
|
||||
map[SDL_SCANCODE_LCTRL] = keycode_normal(4, 0);
|
||||
map[SDL_SCANCODE_LGUI] = keycode_normal(4, 1);
|
||||
map[SDL_SCANCODE_LALT] = keycode_normal(4, 2);
|
||||
map[SDL_SCANCODE_SPACE] = keycode_normal(4, 3);
|
||||
map[SDL_SCANCODE_RALT] = keycode_normal(4, 4);
|
||||
map[SDL_SCANCODE_RCTRL] = keycode_normal(4, 5);
|
||||
|
||||
map[SDL_SCANCODE_UP] = keycode_normal(5, 0);
|
||||
map[SDL_SCANCODE_LEFT] = keycode_normal(5, 1);
|
||||
map[SDL_SCANCODE_DOWN] = keycode_normal(5, 2);
|
||||
map[SDL_SCANCODE_RIGHT] = keycode_normal(5, 3);
|
||||
|
||||
map[SDL_SCANCODE_ESCAPE] = keycode_function(0);
|
||||
map[SDL_SCANCODE_F1] = keycode_function(1);
|
||||
map[SDL_SCANCODE_F2] = keycode_function(2);
|
||||
map[SDL_SCANCODE_F3] = keycode_function(3);
|
||||
map[SDL_SCANCODE_F4] = keycode_function(4);
|
||||
map[SDL_SCANCODE_F5] = keycode_function(5);
|
||||
map[SDL_SCANCODE_F6] = keycode_function(6);
|
||||
map[SDL_SCANCODE_F7] = keycode_function(7);
|
||||
map[SDL_SCANCODE_F8] = keycode_function(8);
|
||||
map[SDL_SCANCODE_F9] = keycode_function(9);
|
||||
map[SDL_SCANCODE_F10] = keycode_function(10);
|
||||
map[SDL_SCANCODE_F11] = keycode_function(11);
|
||||
map[SDL_SCANCODE_F12] = keycode_function(12);
|
||||
map[SDL_SCANCODE_INSERT] = keycode_function(13);
|
||||
map[SDL_SCANCODE_PRINTSCREEN] = keycode_function(14);
|
||||
map[SDL_SCANCODE_DELETE] = keycode_function(15);
|
||||
map[SDL_SCANCODE_HOME] = keycode_function(16);
|
||||
map[SDL_SCANCODE_END] = keycode_function(17);
|
||||
map[SDL_SCANCODE_PAGEUP] = keycode_function(18);
|
||||
map[SDL_SCANCODE_PAGEDOWN] = keycode_function(19);
|
||||
map[SDL_SCANCODE_SCROLLLOCK] = keycode_function(20);
|
||||
|
||||
map[SDL_SCANCODE_NUMLOCKCLEAR] = keycode_numpad(0, 0);
|
||||
map[SDL_SCANCODE_KP_DIVIDE] = keycode_numpad(0, 1);
|
||||
map[SDL_SCANCODE_KP_MULTIPLY] = keycode_numpad(0, 2);
|
||||
map[SDL_SCANCODE_KP_MINUS] = keycode_numpad(0, 3);
|
||||
map[SDL_SCANCODE_KP_7] = keycode_numpad(1, 0);
|
||||
map[SDL_SCANCODE_KP_8] = keycode_numpad(1, 1);
|
||||
map[SDL_SCANCODE_KP_9] = keycode_numpad(1, 2);
|
||||
map[SDL_SCANCODE_KP_PLUS] = keycode_numpad(1, 3);
|
||||
map[SDL_SCANCODE_KP_4] = keycode_numpad(2, 0);
|
||||
map[SDL_SCANCODE_KP_5] = keycode_numpad(2, 1);
|
||||
map[SDL_SCANCODE_KP_6] = keycode_numpad(2, 2);
|
||||
map[SDL_SCANCODE_KP_1] = keycode_numpad(3, 0);
|
||||
map[SDL_SCANCODE_KP_2] = keycode_numpad(3, 1);
|
||||
map[SDL_SCANCODE_KP_3] = keycode_numpad(3, 2);
|
||||
map[SDL_SCANCODE_KP_ENTER] = keycode_numpad(3, 3);
|
||||
map[SDL_SCANCODE_KP_0] = keycode_numpad(4, 0);
|
||||
map[SDL_SCANCODE_KP_COMMA] = keycode_numpad(4, 1);
|
||||
};
|
||||
@@ -87,10 +87,9 @@ BAN::ErrorOr<DrawableInfo> get_drawable_info(Client& client_info, CARD32 drawabl
|
||||
case Object::Type::Window:
|
||||
{
|
||||
auto& window = drawable_it->value->object.get<Object::Window>();
|
||||
auto& texture = window.texture();
|
||||
info.data_u32 = texture.pixels().data();
|
||||
info.w = texture.width();
|
||||
info.h = texture.height();
|
||||
info.data_u32 = window.pixels.data();
|
||||
info.w = window.width;
|
||||
info.h = window.height;
|
||||
info.depth = window.depth;
|
||||
break;
|
||||
}
|
||||
@@ -109,3 +108,14 @@ BAN::ErrorOr<DrawableInfo> get_drawable_info(Client& client_info, CARD32 drawabl
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
Object::Cursor& get_cursor_safe(CURSOR cid)
|
||||
{
|
||||
static Object::Cursor dummy {};
|
||||
auto it = g_objects.find(cid);
|
||||
if (it == g_objects.end())
|
||||
return dummy;
|
||||
if (it->value->type != Object::Type::Cursor)
|
||||
return dummy;
|
||||
return it->value->object.get<Object::Cursor>();
|
||||
}
|
||||
|
||||
@@ -13,3 +13,5 @@ BAN::ErrorOr<Object::Window&> get_window(Client& client_info, CARD32 wid, BYTE o
|
||||
BAN::ErrorOr<Object::Pixmap&> get_pixmap(Client& client_info, CARD32 pid, BYTE op_major, BYTE op_minor = 0);
|
||||
BAN::ErrorOr<Object::GraphicsContext&> get_gc(Client& client_info, CARD32 gc, BYTE op_major, BYTE op_minor = 0);
|
||||
BAN::ErrorOr<DrawableInfo> get_drawable_info(Client& client_info, CARD32 drawable, BYTE op_major, BYTE op_minor = 0);
|
||||
|
||||
Object::Cursor& get_cursor_safe(CURSOR cid);
|
||||
|
||||
12
xbanan/Types.h
Normal file
12
xbanan/Types.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
using ATOM = uint32_t;
|
||||
using BITGRAVITY = uint32_t;
|
||||
using COLORMAP = uint32_t;
|
||||
using CURSOR = uint32_t;
|
||||
using PIXMAP = uint32_t;
|
||||
using VISUALID = uint32_t;
|
||||
using WINDOW = uint32_t;
|
||||
using WINGRAVITY = uint32_t;
|
||||
141
xbanan/banan-os/banan-os.cpp
Normal file
141
xbanan/banan-os/banan-os.cpp
Normal file
@@ -0,0 +1,141 @@
|
||||
#include "../Events.h"
|
||||
#include "../Platform.h"
|
||||
|
||||
#include <LibGUI/Window.h>
|
||||
|
||||
struct BananWindow final : public PlatformWindow
|
||||
{
|
||||
~BananWindow()
|
||||
{
|
||||
if (window)
|
||||
unregister_event_fd(window->server_fd());
|
||||
}
|
||||
|
||||
BAN::UniqPtr<LibGUI::Window> window;
|
||||
};
|
||||
|
||||
static bool bananos_initialize(uint32_t* display_w, uint32_t* display_h)
|
||||
{
|
||||
auto attributes = LibGUI::Window::default_attributes;
|
||||
attributes.shown = false;
|
||||
|
||||
auto dummy_or_error = LibGUI::Window::create(0, 0, ""_sv, attributes);
|
||||
if (dummy_or_error.is_error())
|
||||
{
|
||||
dwarnln("Could not get display size: {}", dummy_or_error.error());
|
||||
return false;
|
||||
}
|
||||
|
||||
*display_w = dummy_or_error.value()->width();
|
||||
*display_h = dummy_or_error.value()->height();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void bananos_poll_events(void* window)
|
||||
{
|
||||
auto& banan_window = *static_cast<BananWindow*>(window);
|
||||
banan_window.window->poll_events();
|
||||
}
|
||||
|
||||
static BAN::ErrorOr<BAN::UniqPtr<PlatformWindow>> bananos_create_window(WINDOW wid, uint32_t width, uint32_t height)
|
||||
{
|
||||
auto window = TRY(BAN::UniqPtr<BananWindow>::create());
|
||||
|
||||
auto attributes = LibGUI::Window::default_attributes;
|
||||
attributes.shown = true;
|
||||
attributes.title_bar = false;
|
||||
attributes.resizable = true;
|
||||
|
||||
auto gui_window = TRY(LibGUI::Window::create(width, height, ""_sv, attributes));
|
||||
auto* winp = gui_window.ptr();
|
||||
|
||||
gui_window->set_close_window_event_callback([wid] {
|
||||
on_window_close_event(wid);
|
||||
});
|
||||
gui_window->set_resize_window_event_callback([wid, winp]() {
|
||||
on_window_resize_event(wid, winp->width(), winp->height());
|
||||
});
|
||||
gui_window->set_window_focus_event_callback([wid](auto event) {
|
||||
on_window_focus_event(wid, event.focused);
|
||||
});
|
||||
gui_window->set_window_fullscreen_event_callback([wid](auto event) {
|
||||
on_window_fullscreen_event(wid, event.fullscreen);
|
||||
});
|
||||
gui_window->set_mouse_move_event_callback([wid](auto event) {
|
||||
on_mouse_move_event(wid, event.x, event.y);
|
||||
});
|
||||
gui_window->set_mouse_button_event_callback([wid](auto event) {
|
||||
uint8_t xbutton = 0;
|
||||
switch (event.button)
|
||||
{
|
||||
case LibInput::MouseButton::Left: xbutton = 1; break;
|
||||
case LibInput::MouseButton::Middle: xbutton = 2; break;
|
||||
case LibInput::MouseButton::Right: xbutton = 3; break;
|
||||
case LibInput::MouseButton::Extra1: xbutton = 8; break;
|
||||
case LibInput::MouseButton::Extra2: xbutton = 9; break;
|
||||
}
|
||||
if (xbutton)
|
||||
on_mouse_button_event(wid, xbutton, event.pressed);
|
||||
});
|
||||
gui_window->set_mouse_scroll_event_callback([wid](auto event) {
|
||||
on_mouse_button_event(wid, event.scroll > 0 ? 4 : 5, true);
|
||||
on_mouse_button_event(wid, event.scroll > 0 ? 4 : 5, false);
|
||||
});
|
||||
gui_window->set_key_event_callback([wid](auto event) {
|
||||
const uint8_t xmod =
|
||||
(event.shift() ? (1 << 0) : 0) |
|
||||
(event.caps_lock() ? (1 << 1) : 0) |
|
||||
(event.ctrl() ? (1 << 2) : 0) |
|
||||
(event.alt() ? (1 << 3) : 0);
|
||||
on_key_event(wid, event.scancode, xmod, event.pressed());
|
||||
});
|
||||
|
||||
window->window = BAN::move(gui_window);
|
||||
|
||||
register_event_fd(window->window->server_fd(), window.ptr());
|
||||
|
||||
return BAN::UniqPtr<PlatformWindow>(BAN::move(window));
|
||||
}
|
||||
|
||||
static void bananos_request_resize(PlatformWindow* window, uint32_t width, uint32_t height)
|
||||
{
|
||||
auto& banan_window = *static_cast<BananWindow*>(window);
|
||||
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)
|
||||
{
|
||||
auto& banan_window = *static_cast<BananWindow*>(window);
|
||||
|
||||
const uint32_t win_width = banan_window.window->width();
|
||||
|
||||
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)];
|
||||
|
||||
banan_window.window->invalidate(x, y, width, height);
|
||||
}
|
||||
|
||||
static void bananos_set_cursor(PlatformWindow* window, const uint32_t* pixels, uint32_t width, uint32_t height, int32_t origin_x, int32_t origin_y)
|
||||
{
|
||||
auto& banan_window = *static_cast<BananWindow*>(window);
|
||||
banan_window.window->set_cursor(width, height, { pixels, width * height }, origin_x, origin_y);
|
||||
}
|
||||
|
||||
static void bananos_request_fullscreen(PlatformWindow* window, bool fullscreen)
|
||||
{
|
||||
auto& banan_window = *static_cast<BananWindow*>(window);
|
||||
banan_window.window->set_fullscreen(fullscreen);
|
||||
}
|
||||
|
||||
PlatformOps g_platform_ops = {
|
||||
.initialize = bananos_initialize,
|
||||
.poll_events = bananos_poll_events,
|
||||
.create_window = bananos_create_window,
|
||||
.invalidate = bananos_invalidate,
|
||||
.request_resize = bananos_request_resize,
|
||||
.request_fullscreen = bananos_request_fullscreen,
|
||||
.set_cursor = bananos_set_cursor,
|
||||
};
|
||||
@@ -11,7 +11,7 @@
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define USE_UNIX_SOCKET 0
|
||||
#define USE_UNIX_SOCKET 1
|
||||
|
||||
#if USE_UNIX_SOCKET
|
||||
#include <sys/un.h>
|
||||
@@ -19,20 +19,6 @@
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
static BAN::UniqPtr<LibGUI::Window> s_dummy_window =
|
||||
[]() {
|
||||
auto attributes = LibGUI::Window::default_attributes;
|
||||
attributes.shown = false;
|
||||
return MUST(LibGUI::Window::create(0, 0, ""_sv, attributes));
|
||||
}();
|
||||
|
||||
static const xRectangle s_screen_bounds = {
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
.width = static_cast<CARD16>(s_dummy_window->width()),
|
||||
.height = static_cast<CARD16>(s_dummy_window->height()),
|
||||
};
|
||||
|
||||
const xPixmapFormat g_formats[6] {
|
||||
{
|
||||
.depth = 1,
|
||||
@@ -81,16 +67,16 @@ const xVisualType g_visual {
|
||||
.blueMask = 0x0000FF,
|
||||
};
|
||||
|
||||
const xWindowRoot g_root {
|
||||
xWindowRoot g_root {
|
||||
.windowId = 2,
|
||||
.defaultColormap = 0,
|
||||
.whitePixel = 0xFFFFFF,
|
||||
.blackPixel = 0x000000,
|
||||
.currentInputMask = 0,
|
||||
.pixWidth = s_screen_bounds.width,
|
||||
.pixHeight = s_screen_bounds.height,
|
||||
.mmWidth = static_cast<CARD16>(s_screen_bounds.width * 254 / 960), // 96 DPI
|
||||
.mmHeight = static_cast<CARD16>(s_screen_bounds.height * 254 / 960), // 96 DPI
|
||||
.pixWidth = 0,
|
||||
.pixHeight = 0,
|
||||
.mmWidth = 0,
|
||||
.mmHeight = 0,
|
||||
.minInstalledMaps = 1,
|
||||
.maxInstalledMaps = 1,
|
||||
.rootVisualID = g_visual.visualID,
|
||||
@@ -183,17 +169,6 @@ int main()
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
epoll_event event { .events = EPOLLIN, .data = { .ptr = (void*)1 } };
|
||||
if (epoll_ctl(g_epoll_fd, EPOLL_CTL_ADD, s_dummy_window->server_fd(), &event) == -1)
|
||||
{
|
||||
perror("xbanan: epoll_ctl");
|
||||
return 1;
|
||||
}
|
||||
|
||||
s_dummy_window->request_resize(1, 1);
|
||||
}
|
||||
|
||||
#define APPEND_ATOM(name) do { \
|
||||
MUST(g_atoms_id_to_name.insert(name, #name##_sv.substring(3))); \
|
||||
MUST(g_atoms_name_to_id.insert(#name##_sv.substring(3), name)); \
|
||||
@@ -281,6 +256,14 @@ int main()
|
||||
|
||||
MUST(initialize_keymap());
|
||||
|
||||
uint32_t display_w, display_h;
|
||||
if (!g_platform_ops.initialize(&display_w, &display_h))
|
||||
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
|
||||
|
||||
printf("xbanan started\n");
|
||||
|
||||
const auto close_client =
|
||||
@@ -309,28 +292,29 @@ int main()
|
||||
continue;
|
||||
|
||||
auto& object = *it->value;
|
||||
if (object.type == Object::Type::Window)
|
||||
switch (object.type)
|
||||
{
|
||||
auto& window = object.object.get<Object::Window>();
|
||||
if (window.window.has<BAN::UniqPtr<LibGUI::Window>>())
|
||||
case Object::Type::Visual:
|
||||
case Object::Type::Cursor:
|
||||
case Object::Type::Pixmap:
|
||||
case Object::Type::GraphicsContext:
|
||||
case Object::Type::Font:
|
||||
case Object::Type::Window:
|
||||
break;
|
||||
case Object::Type::Extension:
|
||||
{
|
||||
auto& gui_window = window.window.get<BAN::UniqPtr<LibGUI::Window>>();
|
||||
epoll_ctl(g_epoll_fd, EPOLL_CTL_DEL, gui_window->server_fd(), nullptr);
|
||||
g_epoll_thingies.remove(gui_window->server_fd());
|
||||
auto& extension = object.object.get<Object::Extension>();
|
||||
extension.destructor(extension);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (object.type == Object::Type::Extension)
|
||||
{
|
||||
auto& extension = object.object.get<Object::Extension>();
|
||||
extension.destructor(extension);
|
||||
}
|
||||
|
||||
g_objects.remove(it);
|
||||
}
|
||||
|
||||
epoll_ctl(g_epoll_fd, EPOLL_CTL_DEL, client_fd, nullptr);
|
||||
close(client_fd);
|
||||
g_epoll_thingies.remove(client_fd);
|
||||
close(client_fd);
|
||||
|
||||
if (client_fd == g_server_grabber_fd)
|
||||
{
|
||||
@@ -353,15 +337,18 @@ 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,
|
||||
.window = {},
|
||||
.width = g_root.pixWidth,
|
||||
.height = g_root.pixHeight,
|
||||
}
|
||||
}))
|
||||
));
|
||||
@@ -412,21 +399,14 @@ int main()
|
||||
continue;
|
||||
}
|
||||
|
||||
if (events[i].data.ptr == (void*)1)
|
||||
{
|
||||
s_dummy_window->poll_events();
|
||||
continue;
|
||||
}
|
||||
|
||||
auto it = g_epoll_thingies.find(events[i].data.fd);
|
||||
if (it == g_epoll_thingies.end())
|
||||
continue;
|
||||
auto& epoll_thingy = it->value;
|
||||
|
||||
if (epoll_thingy.type == EpollThingy::Type::Window)
|
||||
if (epoll_thingy.type == EpollThingy::Type::Event)
|
||||
{
|
||||
auto* window = epoll_thingy.value.get<LibGUI::Window*>();
|
||||
window->poll_events();
|
||||
g_platform_ops.poll_events(epoll_thingy.value.get<void*>());
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user