Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7370d562de | |||
| b85cbd5edf | |||
| 40c002323e | |||
| 0e0624ceb6 |
457
xbanan/Base.cpp
457
xbanan/Base.cpp
@@ -12,6 +12,7 @@
|
|||||||
#include <X11/Xatom.h>
|
#include <X11/Xatom.h>
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <sys/epoll.h>
|
||||||
|
|
||||||
struct Selection
|
struct Selection
|
||||||
{
|
{
|
||||||
@@ -158,6 +159,16 @@ static const char* s_opcode_to_name[] {
|
|||||||
[X_NoOperation] = "X_NoOperation",
|
[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 Object::Window::full_event_mask() const
|
||||||
{
|
{
|
||||||
uint32_t full_event_mask = 0;
|
uint32_t full_event_mask = 0;
|
||||||
@@ -199,9 +210,9 @@ BAN::ErrorOr<void> setup_client_conneciton(Client& client_info, const xConnClien
|
|||||||
xConnSetupPrefix setup_prefix {
|
xConnSetupPrefix setup_prefix {
|
||||||
.success = 1,
|
.success = 1,
|
||||||
.lengthReason = 0, // wtf is this
|
.lengthReason = 0, // wtf is this
|
||||||
.majorVersion = client_prefix.majorVersion,
|
.majorVersion = 11,
|
||||||
.minorVersion = client_prefix.minorVersion,
|
.minorVersion = 0,
|
||||||
.length = 8 + 2*format_count + (8 + 0 + sz_xWindowRoot + sz_xDepth + sz_xVisualType) / 4,
|
.length = 8 + 2 * format_count + (8 + 0 + sz_xWindowRoot + sz_xDepth + sz_xVisualType) / 4,
|
||||||
};
|
};
|
||||||
TRY(encode(client_info.output_buffer, setup_prefix));
|
TRY(encode(client_info.output_buffer, setup_prefix));
|
||||||
|
|
||||||
@@ -285,85 +296,61 @@ static BAN::ErrorOr<void> send_visibility_events_recursively(Client& client_info
|
|||||||
return {};
|
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)
|
if (src_window.c_class == InputOutput)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
const auto& child_object = *g_objects[child_wid];
|
ASSERT(src_x >= 0);
|
||||||
ASSERT(child_object.type == Object::Type::Window);
|
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>();
|
for (int32_t y = 0; y < h; y++)
|
||||||
if (!child_window.mapped)
|
{
|
||||||
continue;
|
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];
|
||||||
const auto child_x = x - child_window.x;
|
for (int32_t x = 0; x < w; x++)
|
||||||
const auto child_y = y - child_window.y;
|
{
|
||||||
|
if (src_u32[x] != COLOR_INVISIBLE)
|
||||||
const auto child_w = BAN::Math::min<int32_t>(w - child_window.x, child_window.width - child_x);
|
dst_u32[x] = 0xFF000000 | src_u32[x];
|
||||||
const auto child_h = BAN::Math::min<int32_t>(h - child_window.y, child_window.height - child_y);
|
else if (&dst_window == &src_window)
|
||||||
|
dst_u32[x] = 0x00000000;
|
||||||
invalidate_window_recursive(
|
}
|
||||||
child_wid,
|
}
|
||||||
child_x, child_y,
|
|
||||||
child_w, child_h
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (window.platform_window || window.c_class == InputOnly)
|
for (auto child_wid : src_window.children)
|
||||||
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++)
|
|
||||||
{
|
{
|
||||||
const int32_t child_y = y + y_off;
|
const auto& child = g_objects[child_wid]->object.get<Object::Window>();
|
||||||
if (child_y < 0 || child_y >= child_h)
|
if (!child.mapped)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const int32_t parent_y = window.y + y + y_off;
|
const auto diff_x = src_x - child.x;
|
||||||
if (parent_y < 0 || parent_y >= parent_h)
|
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;
|
continue;
|
||||||
|
|
||||||
for (int32_t x_off = 0; x_off < w; x_off++)
|
invalidate_window_recursive(
|
||||||
{
|
dst_window,
|
||||||
const int32_t child_x = x + x_off;
|
dst_x - (diff_x - min_x),
|
||||||
if (child_x < 0 || child_x >= child_w)
|
dst_y - (diff_y - min_y),
|
||||||
continue;
|
child,
|
||||||
|
min_x,
|
||||||
const int32_t parent_x = window.x + x + x_off;
|
min_y,
|
||||||
if (parent_x < 0 || parent_x >= parent_w)
|
max_x - min_x,
|
||||||
continue;
|
max_y - min_y
|
||||||
|
);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -371,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);
|
ASSERT(wid != g_root.windowId);
|
||||||
|
|
||||||
|
int32_t min_x { x }, max_x { x + w };
|
||||||
|
int32_t min_y { y }, max_y { y + h };
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
if (wid == g_root.windowId)
|
if (wid == g_root.windowId)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto& object = *g_objects[wid];
|
const auto& window = g_objects[wid]->object.get<Object::Window>();
|
||||||
ASSERT(object.type == Object::Type::Window);
|
|
||||||
|
|
||||||
auto& window = object.object.get<Object::Window>();
|
|
||||||
if (!window.mapped)
|
if (!window.mapped)
|
||||||
return;
|
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)
|
if (window.platform_window)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
x += window.x;
|
min_x += window.x;
|
||||||
y += window.y;
|
min_y += window.y;
|
||||||
wid = window.parent;
|
wid = window.parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& object = *g_objects[wid];
|
auto& window = g_objects[wid]->object.get<Object::Window>();
|
||||||
ASSERT(object.type == Object::Type::Window);
|
|
||||||
|
|
||||||
auto& window = object.object.get<Object::Window>();
|
invalidate_window_recursive(
|
||||||
ASSERT(window.platform_window);
|
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);
|
g_platform_ops.invalidate(
|
||||||
const auto min_y = BAN::Math::max<int32_t>(y, 0);
|
window.platform_window.ptr(),
|
||||||
const auto max_x = BAN::Math::min<int32_t>(x + w, window.width);
|
&window.double_buffer[min_y * window.width + min_x],
|
||||||
const auto max_y = BAN::Math::min<int32_t>(y + h, window.height);
|
window.width * sizeof(uint32_t),
|
||||||
|
min_x, min_y,
|
||||||
if (min_x >= max_x || min_y >= max_y)
|
max_x - min_x,
|
||||||
return;
|
max_y - min_y
|
||||||
|
);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void send_exposure_recursive(WINDOW wid)
|
BAN::ErrorOr<void> send_configure_notify(WINDOW wid)
|
||||||
{
|
{
|
||||||
auto& object = *g_objects[wid];
|
auto& window = g_objects[wid]->object.get<Object::Window>();
|
||||||
ASSERT(object.type == Object::Type::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)
|
if (!window.mapped)
|
||||||
return;
|
return {};
|
||||||
|
|
||||||
for (auto child_wid : window.children)
|
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 = {
|
xEvent event = { .u = {
|
||||||
.expose = {
|
.expose = {
|
||||||
@@ -444,66 +483,32 @@ void send_exposure_recursive(WINDOW wid)
|
|||||||
}
|
}
|
||||||
}};
|
}};
|
||||||
event.u.u.type = Expose;
|
event.u.u.type = Expose;
|
||||||
MUST(window.send_event(event, ExposureMask));
|
TRY(window.send_event(event, ExposureMask));
|
||||||
|
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PlatformWindowInfo
|
static WindowType get_plaform_window_info(const Object::Window& window)
|
||||||
{
|
|
||||||
PlatformWindow* parent;
|
|
||||||
WindowType type;
|
|
||||||
};
|
|
||||||
|
|
||||||
static PlatformWindowInfo get_plaform_window_info(const Object::Window& window)
|
|
||||||
{
|
{
|
||||||
static const CARD32 ATOM = g_atoms_name_to_id["ATOM"_sv];
|
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 = 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_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_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_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 {
|
auto it = window.properties.find(_NET_WM_WINDOW_TYPE);
|
||||||
.parent = nullptr,
|
if (it == window.properties.end())
|
||||||
.type = WindowType::Normal,
|
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))
|
||||||
{
|
return WindowType::Normal;
|
||||||
if (it->value.type != ATOM || it->value.data.size() != sizeof(CARD32))
|
|
||||||
goto wm_window_type_done;
|
|
||||||
|
|
||||||
const CARD32 type = *reinterpret_cast<const CARD32*>(it->value.data.data());
|
const CARD32 type = *reinterpret_cast<const CARD32*>(it->value.data.data());
|
||||||
if (type == _NET_WM_WINDOW_TYPE_NORMAL)
|
if (type == _NET_WM_WINDOW_TYPE_NORMAL)
|
||||||
info.type = WindowType::Normal;
|
return WindowType::Normal;
|
||||||
else if (type == _NET_WM_WINDOW_TYPE_SPLASH || type == _NET_WM_WINDOW_TYPE_DIALOG)
|
if (type == _NET_WM_WINDOW_TYPE_SPLASH || type == _NET_WM_WINDOW_TYPE_DIALOG)
|
||||||
info.type = WindowType::Utility;
|
return WindowType::Utility;
|
||||||
else
|
return WindowType::Popup;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static BAN::ErrorOr<void> map_window(Client& client_info, WINDOW wid)
|
static BAN::ErrorOr<void> map_window(Client& client_info, WINDOW wid)
|
||||||
@@ -526,10 +531,13 @@ static BAN::ErrorOr<void> map_window(Client& client_info, WINDOW wid)
|
|||||||
if (window.width <= 10 || window.height <= 10)
|
if (window.width <= 10 || window.height <= 10)
|
||||||
return {};
|
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(
|
window.platform_window = TRY(g_platform_ops.create_window(
|
||||||
info.parent,
|
type,
|
||||||
info.type,
|
|
||||||
wid,
|
wid,
|
||||||
window.x,
|
window.x,
|
||||||
window.y,
|
window.y,
|
||||||
@@ -573,19 +581,7 @@ static BAN::ErrorOr<void> map_window(Client& client_info, WINDOW wid)
|
|||||||
if (is_visible(window.parent))
|
if (is_visible(window.parent))
|
||||||
TRY(send_visibility_events_recursively(client_info, wid, true));
|
TRY(send_visibility_events_recursively(client_info, wid, true));
|
||||||
|
|
||||||
{
|
TRY(send_exposure_events_recursive(wid));
|
||||||
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));
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@@ -601,8 +597,8 @@ static BAN::ErrorOr<void> unmap_window(Client& client_info, WINDOW wid)
|
|||||||
|
|
||||||
window.mapped = false;
|
window.mapped = false;
|
||||||
|
|
||||||
if (window.platform_window)
|
window.double_buffer.clear();
|
||||||
window.platform_window.clear();
|
window.platform_window.clear();
|
||||||
|
|
||||||
if (is_visible(window.parent))
|
if (is_visible(window.parent))
|
||||||
TRY(send_visibility_events_recursively(client_info, wid, false));
|
TRY(send_visibility_events_recursively(client_info, wid, false));
|
||||||
@@ -1217,6 +1213,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
|||||||
|
|
||||||
dprintln("ConfigureWindow");
|
dprintln("ConfigureWindow");
|
||||||
dprintln(" window: {}", request.window);
|
dprintln(" window: {}", request.window);
|
||||||
|
dprintln(" mask: {4h}", request.mask);
|
||||||
|
|
||||||
auto& window = TRY_REF(get_window(client_info, request.window, opcode));
|
auto& window = TRY_REF(get_window(client_info, request.window, opcode));
|
||||||
|
|
||||||
@@ -1225,7 +1222,6 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
|||||||
uint32_t new_width = window.width;
|
uint32_t new_width = window.width;
|
||||||
uint32_t new_height = window.height;
|
uint32_t new_height = window.height;
|
||||||
|
|
||||||
dprintln(" mask:");
|
|
||||||
for (size_t i = 0; i < 7; i++)
|
for (size_t i = 0; i < 7; i++)
|
||||||
{
|
{
|
||||||
if (!(request.mask & (1 << i)))
|
if (!(request.mask & (1 << i)))
|
||||||
@@ -1237,15 +1233,19 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
|||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
new_x = value;
|
new_x = value;
|
||||||
|
dprintln(" x: {}", value);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
new_y = value;
|
new_y = value;
|
||||||
|
dprintln(" y: {}", value);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
new_width = value;
|
new_width = value;
|
||||||
|
dprintln(" w: {}", value);
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
new_height = value;
|
new_height = value;
|
||||||
|
dprintln(" h: {}", value);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
dprintln(" {4h}: {4h}", 1 << i, value);
|
dprintln(" {4h}: {4h}", 1 << i, value);
|
||||||
@@ -1253,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)
|
if (new_x != window.x || new_y != window.y)
|
||||||
{
|
{
|
||||||
@@ -1266,7 +1266,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
|||||||
{
|
{
|
||||||
window.x = new_x;
|
window.x = new_x;
|
||||||
window.y = new_y;
|
window.y = new_y;
|
||||||
send_configure = true;
|
should_send_configure_notify = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1285,52 +1285,17 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
|||||||
|
|
||||||
window.width = new_width;
|
window.width = new_width;
|
||||||
window.height = new_height;
|
window.height = new_height;
|
||||||
send_configure = true;
|
should_send_configure_notify = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!send_configure)
|
if (!should_send_configure_notify)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
{
|
TRY(send_configure_notify(request.window));
|
||||||
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));
|
|
||||||
}
|
|
||||||
|
|
||||||
auto& parent_object = *g_objects[window.parent];
|
if (is_visible(request.window))
|
||||||
ASSERT(parent_object.type == Object::Type::Window);
|
TRY(send_exposure_events_recursive(request.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));
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1362,15 +1327,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
|||||||
CARD16 width, height;
|
CARD16 width, height;
|
||||||
CARD8 depth;
|
CARD8 depth;
|
||||||
|
|
||||||
if (drawable_id == g_root.windowId)
|
if (drawable.type == Object::Type::Window)
|
||||||
{
|
|
||||||
width = g_root.pixWidth;
|
|
||||||
height = g_root.pixHeight;
|
|
||||||
depth = g_root.rootDepth;
|
|
||||||
x = 0;
|
|
||||||
y = 0;
|
|
||||||
}
|
|
||||||
else if (drawable.type == Object::Type::Window)
|
|
||||||
{
|
{
|
||||||
const auto& window = drawable.object.get<Object::Window>();
|
const auto& window = drawable.object.get<Object::Window>();
|
||||||
width = window.width;
|
width = window.width;
|
||||||
@@ -1813,9 +1770,9 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
|||||||
(void)TRY_REF(get_window(client_info, wid, X_SendEvent));
|
(void)TRY_REF(get_window(client_info, wid, X_SendEvent));
|
||||||
|
|
||||||
Client* target_client = nullptr;
|
Client* target_client = nullptr;
|
||||||
for (auto& [_, thingy] : g_pollables)
|
for (auto& [_, thingy] : g_epoll_thingies)
|
||||||
{
|
{
|
||||||
if (thingy.type != Pollable::Type::Client)
|
if (thingy.type != EpollThingy::Type::Client)
|
||||||
continue;
|
continue;
|
||||||
auto& other_client = thingy.value.get<Client>();
|
auto& other_client = thingy.value.get<Client>();
|
||||||
if (!other_client.objects.contains(wid))
|
if (!other_client.objects.contains(wid))
|
||||||
@@ -1937,11 +1894,47 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
|||||||
case X_GrabServer:
|
case X_GrabServer:
|
||||||
{
|
{
|
||||||
g_server_grabber_fd = client_info.fd;
|
g_server_grabber_fd = client_info.fd;
|
||||||
|
|
||||||
|
for (const auto& [_, thingy] : g_epoll_thingies)
|
||||||
|
{
|
||||||
|
if (thingy.type != EpollThingy::Type::Client)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto& other_client = thingy.value.get<Client>();
|
||||||
|
if (client_info.fd == other_client.fd)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
uint32_t events = 0;
|
||||||
|
if (other_client.has_epollout)
|
||||||
|
events |= EPOLLOUT;
|
||||||
|
|
||||||
|
epoll_event event { .events = events, .data = { .fd = other_client.fd } };
|
||||||
|
epoll_ctl(g_epoll_fd, EPOLL_CTL_MOD, other_client.fd, &event);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case X_UngrabServer:
|
case X_UngrabServer:
|
||||||
{
|
{
|
||||||
g_server_grabber_fd = -1;
|
g_server_grabber_fd = -1;
|
||||||
|
|
||||||
|
for (const auto& [_, thingy] : g_epoll_thingies)
|
||||||
|
{
|
||||||
|
if (thingy.type != EpollThingy::Type::Client)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto& other_client = thingy.value.get<Client>();
|
||||||
|
if (client_info.fd == other_client.fd)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
uint32_t events = EPOLLIN;
|
||||||
|
if (other_client.has_epollout)
|
||||||
|
events |= EPOLLOUT;
|
||||||
|
|
||||||
|
epoll_event event { .events = events, .data = { .fd = other_client.fd } };
|
||||||
|
epoll_ctl(g_epoll_fd, EPOLL_CTL_MOD, other_client.fd, &event);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case X_QueryPointer:
|
case X_QueryPointer:
|
||||||
@@ -2155,7 +2148,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
|
|||||||
// TODO: support invisible background
|
// TODO: support invisible background
|
||||||
|
|
||||||
uint32_t foreground = 0x000000;
|
uint32_t foreground = 0x000000;
|
||||||
uint32_t background = 0x000000;
|
uint32_t background = 0xFFFFFF;
|
||||||
uint16_t line_width = 0;
|
uint16_t line_width = 0;
|
||||||
uint32_t font = None;
|
uint32_t font = None;
|
||||||
bool graphics_exposures = true;
|
bool graphics_exposures = true;
|
||||||
|
|||||||
@@ -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);
|
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 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);
|
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);
|
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_keymask;
|
||||||
extern CARD16 g_butmask;
|
extern CARD16 g_butmask;
|
||||||
|
|||||||
@@ -66,8 +66,11 @@ struct Object
|
|||||||
|
|
||||||
uint32_t background { 0 };
|
uint32_t background { 0 };
|
||||||
|
|
||||||
|
bool platform_window_invalidated { false };
|
||||||
BAN::UniqPtr<PlatformWindow> platform_window;
|
BAN::UniqPtr<PlatformWindow> platform_window;
|
||||||
|
|
||||||
|
BAN::Vector<uint32_t> double_buffer;
|
||||||
|
|
||||||
BAN::HashMap<Client*, uint32_t> event_masks;
|
BAN::HashMap<Client*, uint32_t> event_masks;
|
||||||
|
|
||||||
BAN::HashMap<ATOM, Property> properties;
|
BAN::HashMap<ATOM, Property> properties;
|
||||||
@@ -140,6 +143,7 @@ struct Client
|
|||||||
};
|
};
|
||||||
int fd;
|
int fd;
|
||||||
State state;
|
State state;
|
||||||
|
bool has_epollout { false };
|
||||||
bool has_bigrequests { false };
|
bool has_bigrequests { false };
|
||||||
CARD16 sequence { 0 };
|
CARD16 sequence { 0 };
|
||||||
BAN::Optional<uint32_t> pid;
|
BAN::Optional<uint32_t> pid;
|
||||||
@@ -148,7 +152,7 @@ struct Client
|
|||||||
BAN::HashSet<CARD32> objects;
|
BAN::HashSet<CARD32> objects;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Pollable
|
struct EpollThingy
|
||||||
{
|
{
|
||||||
enum class Type
|
enum class Type
|
||||||
{
|
{
|
||||||
@@ -160,6 +164,12 @@ struct Pollable
|
|||||||
BAN::Variant<Client, void*> value;
|
BAN::Variant<Client, void*> value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct DisplayInfo
|
||||||
|
{
|
||||||
|
int32_t x, y;
|
||||||
|
uint32_t w, h;
|
||||||
|
};
|
||||||
|
|
||||||
extern const xPixmapFormat g_formats[6];
|
extern const xPixmapFormat g_formats[6];
|
||||||
extern const xDepth g_depth;
|
extern const xDepth g_depth;
|
||||||
extern const xVisualType g_visual;
|
extern const xVisualType g_visual;
|
||||||
@@ -171,6 +181,11 @@ extern BAN::HashMap<BAN::String, ATOM> g_atoms_name_to_id;
|
|||||||
extern BAN::HashMap<ATOM, BAN::String> g_atoms_id_to_name;
|
extern BAN::HashMap<ATOM, BAN::String> g_atoms_id_to_name;
|
||||||
extern ATOM g_atom_value;
|
extern ATOM g_atom_value;
|
||||||
|
|
||||||
extern BAN::HashMap<int, Pollable> g_pollables;
|
extern int g_epoll_fd;
|
||||||
|
extern BAN::HashMap<int, EpollThingy> g_epoll_thingies;
|
||||||
|
|
||||||
extern int g_server_grabber_fd;
|
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();
|
auto request = decode<xPolyLineReq>(packet).value();
|
||||||
|
|
||||||
dprintln("PolyLine");
|
dprintln("PolyLine");
|
||||||
dprintln(" drawable: {}", request.drawable);
|
dprintln(" drawable: {h}", request.drawable);
|
||||||
dprintln(" gc: {}", request.gc);
|
dprintln(" gc: {}", request.gc);
|
||||||
dprintln(" coordMode: {}", request.coordMode);
|
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();
|
auto request = decode<xPolySegmentReq>(packet).value();
|
||||||
|
|
||||||
dprintln("PolySegment");
|
dprintln("PolySegment");
|
||||||
dprintln(" drawable: {}", request.drawable);
|
dprintln(" drawable: {h}", request.drawable);
|
||||||
dprintln(" gc: {}", request.gc);
|
dprintln(" gc: {}", request.gc);
|
||||||
|
|
||||||
auto [out_data_u32, out_w, out_h, _] = TRY(get_drawable_info(client_info, request.drawable, X_PolySegment));
|
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();
|
auto request = decode<xFillPolyReq>(packet).value();
|
||||||
|
|
||||||
dprintln("FillPoly");
|
dprintln("FillPoly");
|
||||||
dprintln(" drawable: {}", request.drawable);
|
dprintln(" drawable: {h}", request.drawable);
|
||||||
dprintln(" gc: {}", request.gc);
|
dprintln(" gc: {}", request.gc);
|
||||||
dprintln(" shape: {}", request.shape);
|
dprintln(" shape: {}", request.shape);
|
||||||
dprintln(" coordMode: {}", request.coordMode);
|
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();
|
auto request = decode<xPolyFillRectangleReq>(packet).value();
|
||||||
|
|
||||||
dprintln("PolyFillRectangle");
|
dprintln("PolyFillRectangle");
|
||||||
dprintln(" drawable: {}", request.drawable);
|
dprintln(" drawable: {h}", request.drawable);
|
||||||
dprintln(" gc: {}", request.gc);
|
dprintln(" gc: {}", request.gc);
|
||||||
|
|
||||||
auto [out_data_u32, out_w, out_h, _] = TRY(get_drawable_info(client_info, request.drawable, X_PolyFillRectangle));
|
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();
|
auto request = decode<xPolyFillArcReq>(packet).value();
|
||||||
|
|
||||||
dprintln("PolyFillArc");
|
dprintln("PolyFillArc");
|
||||||
dprintln(" drawable: {}", request.drawable);
|
dprintln(" drawable: {h}", request.drawable);
|
||||||
dprintln(" gc: {}", request.gc);
|
dprintln(" gc: {}", request.gc);
|
||||||
|
|
||||||
auto [out_data_32, out_w, out_h, _] = TRY(get_drawable_info(client_info, request.drawable, X_PolyFillArc));
|
auto [out_data_32, out_w, out_h, _] = TRY(get_drawable_info(client_info, request.drawable, X_PolyFillArc));
|
||||||
|
|||||||
@@ -7,18 +7,23 @@
|
|||||||
#include <X11/Xatom.h>
|
#include <X11/Xatom.h>
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <sys/epoll.h>
|
||||||
|
|
||||||
void register_event_fd(int fd, void* data)
|
void register_event_fd(int fd, void* data)
|
||||||
{
|
{
|
||||||
MUST(g_pollables.insert(fd, {
|
epoll_event event { .events = EPOLLIN, .data = { .fd = fd } };
|
||||||
.type = Pollable::Type::Event,
|
epoll_ctl(g_epoll_fd, EPOLL_CTL_ADD, fd, &event);
|
||||||
|
|
||||||
|
MUST(g_epoll_thingies.insert(fd, {
|
||||||
|
.type = EpollThingy::Type::Event,
|
||||||
.value = data,
|
.value = data,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
void unregister_event_fd(int fd)
|
void unregister_event_fd(int fd)
|
||||||
{
|
{
|
||||||
g_pollables.remove(fd);
|
epoll_ctl(g_epoll_fd, EPOLL_CTL_DEL, fd, nullptr);
|
||||||
|
g_epoll_thingies.remove(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_window_close_event(WINDOW wid)
|
void on_window_close_event(WINDOW wid)
|
||||||
@@ -70,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)
|
void on_window_resize_event(WINDOW wid, uint32_t new_width, uint32_t new_height)
|
||||||
{
|
{
|
||||||
auto& object = *g_objects[wid];
|
auto& object = *g_objects[wid];
|
||||||
ASSERT(object.type == Object::Type::Window);
|
ASSERT(object.type == Object::Type::Window);
|
||||||
auto& window = object.object.get<Object::Window>();
|
auto& window = object.object.get<Object::Window>();
|
||||||
|
|
||||||
{
|
window.width = new_width;
|
||||||
window.width = new_width;
|
window.height = new_height;
|
||||||
window.height = new_height;
|
|
||||||
|
|
||||||
MUST(window.pixels.resize(new_width * new_height));
|
MUST(window.pixels.resize(new_width * new_height));
|
||||||
for (auto& pixel : window.pixels)
|
for (auto& pixel : window.pixels)
|
||||||
pixel = window.background;
|
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)
|
void on_window_move_event(WINDOW wid, int32_t x, int32_t y)
|
||||||
@@ -144,7 +106,7 @@ void on_window_move_event(WINDOW wid, int32_t x, int32_t y)
|
|||||||
window.x = x;
|
window.x = x;
|
||||||
window.y = y;
|
window.y = y;
|
||||||
|
|
||||||
send_window_configure(wid, window);
|
MUST(send_configure_notify(wid));
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_window_focus_event(WINDOW wid, bool focused)
|
void on_window_focus_event(WINDOW wid, bool focused)
|
||||||
|
|||||||
@@ -6,12 +6,64 @@
|
|||||||
|
|
||||||
#include <time.h>
|
#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 BAN::ErrorOr<void> extension_randr(Client& client_info, BAN::ConstByteSpan packet)
|
||||||
{
|
{
|
||||||
static CARD32 crtc_id = 5;
|
if (s_randr_displays.empty())
|
||||||
static CARD32 output_id = 6;
|
initialize_displays();
|
||||||
static CARD32 mode_id = 7;
|
|
||||||
static CARD32 timestamp = time(nullptr);
|
|
||||||
|
|
||||||
static xRenderTransform transform {
|
static xRenderTransform transform {
|
||||||
1 << 16, 0, 0,
|
1 << 16, 0, 0,
|
||||||
@@ -61,14 +113,14 @@ static BAN::ErrorOr<void> extension_randr(Client& client_info, BAN::ConstByteSpa
|
|||||||
.setOfRotations = RR_Rotate_0,
|
.setOfRotations = RR_Rotate_0,
|
||||||
.sequenceNumber = client_info.sequence,
|
.sequenceNumber = client_info.sequence,
|
||||||
.length = 3,
|
.length = 3,
|
||||||
.root = g_root.windowId,
|
.root = g_root.windowId,
|
||||||
.timestamp = timestamp,
|
.timestamp = s_timestamp,
|
||||||
.configTimestamp = timestamp,
|
.configTimestamp = s_timestamp,
|
||||||
.nSizes = 1,
|
.nSizes = 1,
|
||||||
.sizeID = 0,
|
.sizeID = 0,
|
||||||
.rotation = RR_Rotate_0,
|
.rotation = RR_Rotate_0,
|
||||||
.rate = 60,
|
.rate = 60,
|
||||||
.nrateEnts = 1,
|
.nrateEnts = 1,
|
||||||
};
|
};
|
||||||
TRY(encode(client_info.output_buffer, reply));
|
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("RRGetScreenResources{}", current ? "Current" : "");
|
||||||
dprintln(" window: {}", request.window);
|
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 {
|
xRRGetScreenResourcesReply reply {
|
||||||
.type = X_Reply,
|
.type = X_Reply,
|
||||||
.sequenceNumber = client_info.sequence,
|
.sequenceNumber = client_info.sequence,
|
||||||
.length = static_cast<CARD32>(1 + 1 + 8 + (mode_name.size() + 3) / 4),
|
.length = static_cast<CARD32>(s_randr_displays.size() * (1 + 1 + 8) + (mode_name_bytes + 3) / 4),
|
||||||
.timestamp = timestamp,
|
.timestamp = s_timestamp,
|
||||||
.configTimestamp = timestamp,
|
.configTimestamp = s_timestamp,
|
||||||
.nCrtcs = 1,
|
.nCrtcs = static_cast<CARD16>(s_randr_displays.size()),
|
||||||
.nOutputs = 1,
|
.nOutputs = static_cast<CARD16>(s_randr_displays.size()),
|
||||||
.nModes = 1,
|
.nModes = static_cast<CARD16>(s_randr_displays.size()),
|
||||||
.nbytesNames = static_cast<CARD16>(mode_name.size()),
|
.nbytesNames = static_cast<CARD16>(mode_name_bytes),
|
||||||
};
|
};
|
||||||
TRY(encode(client_info.output_buffer, reply));
|
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;
|
for (const auto& display : s_randr_displays)
|
||||||
const CARD16 hsync_end = g_root.pixWidth + 1;
|
{
|
||||||
const CARD16 htotal = g_root.pixWidth + 1;
|
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_start = display.info.h;
|
||||||
const CARD16 vsync_end = g_root.pixHeight + 1;
|
const CARD16 vsync_end = display.info.h + 1;
|
||||||
const CARD16 vtotal = g_root.pixHeight + 1;
|
const CARD16 vtotal = display.info.h + 1;
|
||||||
|
|
||||||
const CARD32 clock = htotal * vtotal * 60;
|
const CARD32 clock = htotal * vtotal * 60;
|
||||||
|
|
||||||
xRRModeInfo mode_info {
|
xRRModeInfo mode_info {
|
||||||
.id = mode_id,
|
.id = display.mode_id,
|
||||||
.width = g_root.pixWidth,
|
.width = static_cast<CARD16>(display.info.w),
|
||||||
.height = g_root.pixHeight,
|
.height = static_cast<CARD16>(display.info.h),
|
||||||
.dotClock = clock,
|
.dotClock = clock,
|
||||||
.hSyncStart = hsync_start,
|
.hSyncStart = hsync_start,
|
||||||
.hSyncEnd = hsync_end,
|
.hSyncEnd = hsync_end,
|
||||||
.hTotal = htotal,
|
.hTotal = htotal,
|
||||||
.hSkew = 0,
|
.hSkew = 0,
|
||||||
.vSyncStart = vsync_start,
|
.vSyncStart = vsync_start,
|
||||||
.vSyncEnd = vsync_end,
|
.vSyncEnd = vsync_end,
|
||||||
.vTotal = vtotal,
|
.vTotal = vtotal,
|
||||||
.nameLength = static_cast<CARD16>(mode_name.size()),
|
.nameLength = static_cast<CARD16>(display.mode_str.size()),
|
||||||
.modeFlags = RR_HSyncPositive | RR_VSyncPositive,
|
.modeFlags = RR_HSyncPositive | RR_VSyncPositive,
|
||||||
};
|
};
|
||||||
TRY(encode(client_info.output_buffer, mode_info));
|
TRY(encode(client_info.output_buffer, mode_info));
|
||||||
|
}
|
||||||
|
|
||||||
TRY(encode(client_info.output_buffer, mode_name));
|
for (const auto& display : s_randr_displays)
|
||||||
for (size_t i = 0; (mode_name.size() + i) % 4; i++)
|
TRY(encode(client_info.output_buffer, display.mode_str));
|
||||||
TRY(encode(client_info.output_buffer, '\0'));
|
while (client_info.output_buffer.size() % 4)
|
||||||
|
TRY(encode<BYTE>(client_info.output_buffer, 0));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -175,27 +235,31 @@ static BAN::ErrorOr<void> extension_randr(Client& client_info, BAN::ConstByteSpa
|
|||||||
dprintln(" output: {}", request.output);
|
dprintln(" output: {}", request.output);
|
||||||
dprintln(" configTimestamp: {}", request.configTimestamp);
|
dprintln(" configTimestamp: {}", request.configTimestamp);
|
||||||
|
|
||||||
|
const auto& display = find_display_by_output(request.output);
|
||||||
|
|
||||||
xRRGetOutputInfoReply reply {
|
xRRGetOutputInfoReply reply {
|
||||||
.type = X_Reply,
|
.type = X_Reply,
|
||||||
.status = Success,
|
.status = Success,
|
||||||
.sequenceNumber = client_info.sequence,
|
.sequenceNumber = client_info.sequence,
|
||||||
.length = 1 + 1 + 1 + 2,
|
.length = static_cast<CARD32>(1 + 1 + 1 + (display.output_str.size() + 3) / 4),
|
||||||
.timestamp = timestamp,
|
.timestamp = s_timestamp,
|
||||||
.crtc = crtc_id,
|
.crtc = display.crtc_id,
|
||||||
.mmWidth = g_root.mmWidth,
|
.mmWidth = display.info.w * 254 / 960, // 96 DPI
|
||||||
.mmHeight = g_root.mmHeight,
|
.mmHeight = display.info.h * 254 / 960, // 96 DPI
|
||||||
.connection = RR_Connected,
|
.connection = RR_Connected,
|
||||||
.subpixelOrder = SubPixelUnknown,
|
.subpixelOrder = SubPixelUnknown,
|
||||||
.nCrtcs = 1,
|
.nCrtcs = 1,
|
||||||
.nModes = 1,
|
.nModes = 1,
|
||||||
.nPreferred = 1,
|
.nPreferred = 1,
|
||||||
.nClones = 0,
|
.nClones = 0,
|
||||||
.nameLength = 5,
|
.nameLength = static_cast<CARD16>(display.output_str.size()),
|
||||||
};
|
};
|
||||||
TRY(encode(client_info.output_buffer, reply));
|
TRY(encode(client_info.output_buffer, reply));
|
||||||
TRY(encode(client_info.output_buffer, crtc_id));
|
TRY(encode(client_info.output_buffer, display.crtc_id));
|
||||||
TRY(encode(client_info.output_buffer, mode_id));
|
TRY(encode(client_info.output_buffer, display.mode_id));
|
||||||
TRY(encode(client_info.output_buffer, "B-OUT\0\0\0"_sv));
|
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;
|
break;
|
||||||
}
|
}
|
||||||
@@ -250,25 +314,27 @@ static BAN::ErrorOr<void> extension_randr(Client& client_info, BAN::ConstByteSpa
|
|||||||
dprintln(" crtc: {}", request.crtc);
|
dprintln(" crtc: {}", request.crtc);
|
||||||
dprintln(" configTimestamp: {}", request.configTimestamp);
|
dprintln(" configTimestamp: {}", request.configTimestamp);
|
||||||
|
|
||||||
|
const auto& display = find_display_by_crtc(request.crtc);
|
||||||
|
|
||||||
xRRGetCrtcInfoReply reply {
|
xRRGetCrtcInfoReply reply {
|
||||||
.type = X_Reply,
|
.type = X_Reply,
|
||||||
.status = Success,
|
.status = Success,
|
||||||
.sequenceNumber = client_info.sequence,
|
.sequenceNumber = client_info.sequence,
|
||||||
.length = 2,
|
.length = 2,
|
||||||
.timestamp = timestamp,
|
.timestamp = s_timestamp,
|
||||||
.x = 0,
|
.x = static_cast<INT16>(display.info.x),
|
||||||
.y = 0,
|
.y = static_cast<INT16>(display.info.y),
|
||||||
.width = g_root.pixWidth,
|
.width = static_cast<CARD16>(display.info.w),
|
||||||
.height = g_root.pixHeight,
|
.height = static_cast<CARD16>(display.info.h),
|
||||||
.mode = mode_id,
|
.mode = display.mode_id,
|
||||||
.rotation = RR_Rotate_0,
|
.rotation = RR_Rotate_0,
|
||||||
.rotations = RR_Rotate_0,
|
.rotations = RR_Rotate_0,
|
||||||
.nOutput = 1,
|
.nOutput = 1,
|
||||||
.nPossibleOutput = 1,
|
.nPossibleOutput = 1,
|
||||||
};
|
};
|
||||||
TRY(encode(client_info.output_buffer, reply));
|
TRY(encode(client_info.output_buffer, reply));
|
||||||
TRY(encode(client_info.output_buffer, output_id));
|
TRY(encode(client_info.output_buffer, display.output_id));
|
||||||
TRY(encode(client_info.output_buffer, output_id));
|
TRY(encode(client_info.output_buffer, display.output_id));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -285,13 +351,13 @@ static BAN::ErrorOr<void> extension_randr(Client& client_info, BAN::ConstByteSpa
|
|||||||
dprintln(" mode: {}", request.mode);
|
dprintln(" mode: {}", request.mode);
|
||||||
dprintln(" rotation: {}", request.rotation);
|
dprintln(" rotation: {}", request.rotation);
|
||||||
|
|
||||||
timestamp = time(nullptr);
|
s_timestamp = time(nullptr);
|
||||||
xRRSetCrtcConfigReply reply {
|
xRRSetCrtcConfigReply reply {
|
||||||
.type = X_Reply,
|
.type = X_Reply,
|
||||||
.status = Success,
|
.status = Success,
|
||||||
.sequenceNumber = client_info.sequence,
|
.sequenceNumber = client_info.sequence,
|
||||||
.length = 0,
|
.length = 0,
|
||||||
.newTimestamp = timestamp,
|
.newTimestamp = s_timestamp,
|
||||||
};
|
};
|
||||||
TRY(encode(client_info.output_buffer, reply));
|
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();
|
auto request = decode<xRRGetCrtcGammaSizeReq>(packet).value();
|
||||||
|
|
||||||
dprintln("RRGetCrtcGammaSize");
|
dwarnln("RRGetCrtcGammaSize");
|
||||||
dprintln(" crtc: {}", request.crtc);
|
dwarnln(" crtc: {}", request.crtc);
|
||||||
|
|
||||||
xRRGetCrtcGammaSizeReply reply {
|
xRRGetCrtcGammaSizeReply reply {
|
||||||
.type = X_Reply,
|
.type = X_Reply,
|
||||||
.status = Success,
|
.status = Success,
|
||||||
.sequenceNumber = client_info.sequence,
|
.sequenceNumber = client_info.sequence,
|
||||||
.length = 0,
|
.length = 0,
|
||||||
.size = 1,
|
.size = 256,
|
||||||
};
|
};
|
||||||
TRY(encode(client_info.output_buffer, reply));
|
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);
|
dprintln(" crtc: {}", request.crtc);
|
||||||
|
|
||||||
xRRGetCrtcGammaReply reply {
|
xRRGetCrtcGammaReply reply {
|
||||||
.type = X_Reply,
|
.type = X_Reply,
|
||||||
.status = Success,
|
.status = Success,
|
||||||
.sequenceNumber = client_info.sequence,
|
.sequenceNumber = client_info.sequence,
|
||||||
.length = 2,
|
.length = (6 * 256) / 4,
|
||||||
.size = 1,
|
.size = 256,
|
||||||
};
|
};
|
||||||
TRY(encode(client_info.output_buffer, reply));
|
TRY(encode(client_info.output_buffer, reply));
|
||||||
TRY(encode<CARD16>(client_info.output_buffer, 1));
|
for (size_t i = 0; i < 3; i++)
|
||||||
TRY(encode<CARD16>(client_info.output_buffer, 1));
|
for (size_t j = 0; j < 256; j++)
|
||||||
TRY(encode<CARD16>(client_info.output_buffer, 1));
|
TRY(encode<CARD16>(client_info.output_buffer, j * 65535 / 255));
|
||||||
TRY(encode<CARD16>(client_info.output_buffer, 0));
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -345,17 +410,17 @@ static BAN::ErrorOr<void> extension_randr(Client& client_info, BAN::ConstByteSpa
|
|||||||
dprintln(" crtc: {}", request.crtc);
|
dprintln(" crtc: {}", request.crtc);
|
||||||
|
|
||||||
xRRGetCrtcTransformReply reply {
|
xRRGetCrtcTransformReply reply {
|
||||||
.type = X_Reply,
|
.type = X_Reply,
|
||||||
.status = Success,
|
.status = Success,
|
||||||
.sequenceNumber = client_info.sequence,
|
.sequenceNumber = client_info.sequence,
|
||||||
.length = 16,
|
.length = 16,
|
||||||
.pendingTransform = transform,
|
.pendingTransform = transform,
|
||||||
.hasTransforms = xFalse,
|
.hasTransforms = xFalse,
|
||||||
.currentTransform = transform,
|
.currentTransform = transform,
|
||||||
.pendingNbytesFilter = 0,
|
.pendingNbytesFilter = 0,
|
||||||
.pendingNparamsFilter = 0,
|
.pendingNparamsFilter = 0,
|
||||||
.currentNbytesFilter = 0,
|
.currentNbytesFilter = 0,
|
||||||
.currentNparamsFilter = 0,
|
.currentNparamsFilter = 0,
|
||||||
};
|
};
|
||||||
TRY(encode(client_info.output_buffer, reply));
|
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);
|
dprintln(" crtc: {}", request.crtc);
|
||||||
|
|
||||||
xRRGetPanningReply reply {
|
xRRGetPanningReply reply {
|
||||||
.type = X_Reply,
|
.type = X_Reply,
|
||||||
.status = Success,
|
.status = Success,
|
||||||
.sequenceNumber = client_info.sequence,
|
.sequenceNumber = client_info.sequence,
|
||||||
.length = 1,
|
.length = 1,
|
||||||
.timestamp = timestamp,
|
.timestamp = s_timestamp,
|
||||||
.left = 0,
|
.left = 0,
|
||||||
.top = 0,
|
.top = 0,
|
||||||
.width = 0,
|
.width = 0,
|
||||||
.height = 0,
|
.height = 0,
|
||||||
.track_left = 0,
|
.track_left = 0,
|
||||||
.track_top = 0,
|
.track_top = 0,
|
||||||
.track_width = 0,
|
.track_width = 0,
|
||||||
.track_height = 0,
|
.track_height = 0,
|
||||||
.border_left = 0,
|
.border_left = 0,
|
||||||
.border_top = 0,
|
.border_top = 0,
|
||||||
.border_right = 0,
|
.border_right = 0,
|
||||||
.border_bottom = 0,
|
.border_bottom = 0,
|
||||||
};
|
};
|
||||||
TRY(encode(client_info.output_buffer, reply));
|
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);
|
dprintln(" window: {}", request.window);
|
||||||
|
|
||||||
xRRGetOutputPrimaryReply reply {
|
xRRGetOutputPrimaryReply reply {
|
||||||
.type = X_Reply,
|
.type = X_Reply,
|
||||||
.sequenceNumber = client_info.sequence,
|
.sequenceNumber = client_info.sequence,
|
||||||
.length = 0,
|
.length = 0,
|
||||||
.output = output_id,
|
.output = s_randr_displays.front().output_id,
|
||||||
};
|
};
|
||||||
TRY(encode(client_info.output_buffer, reply));
|
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);
|
dprintln(" window: {}", request.window);
|
||||||
|
|
||||||
xRRGetProvidersReply reply {
|
xRRGetProvidersReply reply {
|
||||||
.type = X_Reply,
|
.type = X_Reply,
|
||||||
.sequenceNumber = client_info.sequence,
|
.sequenceNumber = client_info.sequence,
|
||||||
.length = 0,
|
.length = 0,
|
||||||
.timestamp = timestamp,
|
.timestamp = s_timestamp,
|
||||||
.nProviders = 0,
|
.nProviders = 0,
|
||||||
};
|
};
|
||||||
TRY(encode(client_info.output_buffer, reply));
|
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);
|
dprintln(" get_active: {}", request.get_active);
|
||||||
|
|
||||||
xRRGetMonitorsReply reply {
|
xRRGetMonitorsReply reply {
|
||||||
.type = X_Reply,
|
.type = X_Reply,
|
||||||
.status = Success,
|
.status = Success,
|
||||||
.sequenceNumber = client_info.sequence,
|
.sequenceNumber = client_info.sequence,
|
||||||
.length = 6 + 1,
|
.length = static_cast<CARD32>(6 * s_randr_displays.size() + s_randr_displays.size()),
|
||||||
.timestamp = timestamp,
|
.timestamp = s_timestamp,
|
||||||
.nmonitors = 1,
|
.nmonitors = static_cast<CARD32>(s_randr_displays.size()),
|
||||||
.noutputs = 1,
|
.noutputs = static_cast<CARD32>(s_randr_displays.size()),
|
||||||
};
|
};
|
||||||
TRY(encode(client_info.output_buffer, reply));
|
TRY(encode(client_info.output_buffer, reply));
|
||||||
|
|
||||||
xRRMonitorInfo monitor {
|
for (const auto& display : s_randr_displays)
|
||||||
.name = None,
|
{
|
||||||
.primary = xTrue,
|
xRRMonitorInfo monitor {
|
||||||
.automatic = xTrue,
|
.name = display.name_atom,
|
||||||
.noutput = 1,
|
.primary = (&display == &s_randr_displays.front()),
|
||||||
.x = 0,
|
.automatic = xTrue,
|
||||||
.y = 0,
|
.noutput = 1,
|
||||||
.width = g_root.pixWidth,
|
.x = static_cast<INT16>(display.info.x),
|
||||||
.height = g_root.pixHeight,
|
.y = static_cast<INT16>(display.info.y),
|
||||||
.widthInMillimeters = g_root.mmWidth,
|
.width = static_cast<CARD16>(display.info.w),
|
||||||
.heightInMillimeters = g_root.mmHeight,
|
.height = static_cast<CARD16>(display.info.h),
|
||||||
};
|
.widthInMillimeters = display.info.w * 254 / 96, // 96 DPI
|
||||||
TRY(encode(client_info.output_buffer, monitor));
|
.heightInMillimeters = display.info.h * 254 / 96, // 96 DPI
|
||||||
|
};
|
||||||
TRY(encode(client_info.output_buffer, output_id));
|
TRY(encode(client_info.output_buffer, monitor));
|
||||||
|
TRY(encode(client_info.output_buffer, display.output_id));
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,12 +7,12 @@
|
|||||||
template<typename F>
|
template<typename F>
|
||||||
static BAN::ErrorOr<void> for_each_client(uint32_t target_spec, const F& callback)
|
static BAN::ErrorOr<void> for_each_client(uint32_t target_spec, const F& callback)
|
||||||
{
|
{
|
||||||
for (auto [fd, thingy] : g_pollables)
|
for (const auto& [fd, thingy] : g_epoll_thingies)
|
||||||
{
|
{
|
||||||
if (thingy.type != Pollable::Type::Client)
|
if (thingy.type != EpollThingy::Type::Client)
|
||||||
continue;
|
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)
|
if (target_spec && (target_spec >> 20) != client_info.fd)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -61,7 +61,7 @@ BAN::ErrorOr<void> extension_xres(Client& client_info, BAN::ConstByteSpan packet
|
|||||||
{
|
{
|
||||||
auto spec = decode<xXResClientIdSpec>(packet).value();
|
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))
|
if (spec.mask == None || (spec.mask & X_XResClientXIDMask))
|
||||||
{
|
{
|
||||||
xXResClientIdValue value {
|
xXResClientIdValue value {
|
||||||
|
|||||||
@@ -47,13 +47,18 @@ enum class SystemCursorType
|
|||||||
struct PlatformOps
|
struct PlatformOps
|
||||||
{
|
{
|
||||||
/* Do platform initialization */
|
/* Do platform initialization */
|
||||||
bool (*initialize)(uint32_t* width, uint32_t* height);
|
bool (*initialize)();
|
||||||
/* Handle pending events */
|
/* Handle pending events */
|
||||||
void (*poll_events)(void*);
|
void (*poll_events)(void*);
|
||||||
/* Create a window with given size */
|
/* 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);
|
BAN::ErrorOr<BAN::UniqPtr<PlatformWindow>> (*create_window)(WindowType, WINDOW wid, int32_t x, int32_t y, uint32_t width, uint32_t height);
|
||||||
/* Invaldate part of a window */
|
/* All invalidate calls during one frame happen between calls to begin_frame and end_frame. pixels is in ARGB8888
|
||||||
void (*invalidate)(PlatformWindow*, const uint32_t* pixels, uint32_t x, uint32_t y, uint32_t width, uint32_t height);
|
* 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 */
|
/* Request resize of a window, can be async */
|
||||||
void (*request_resize)(PlatformWindow*, uint32_t width, uint32_t height);
|
void (*request_resize)(PlatformWindow*, uint32_t width, uint32_t height);
|
||||||
/* Request window repositioning */
|
/* Request window repositioning */
|
||||||
@@ -74,3 +79,5 @@ struct PlatformOps
|
|||||||
void (*set_cursor)(PlatformWindow*, PlatformCursor*);
|
void (*set_cursor)(PlatformWindow*, PlatformCursor*);
|
||||||
};
|
};
|
||||||
extern PlatformOps g_platform_ops;
|
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 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))
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
*display_w = *display_h = 0;
|
|
||||||
|
|
||||||
const SDL_DisplayID* display_ids = SDL_GetDisplays(nullptr);
|
const SDL_DisplayID* display_ids = SDL_GetDisplays(nullptr);
|
||||||
for (int i = 0; display_ids[i]; i++)
|
for (int i = 0; display_ids[i]; i++)
|
||||||
{
|
{
|
||||||
SDL_Rect rect;
|
SDL_Rect rect;
|
||||||
SDL_GetDisplayBounds(display_ids[i], &rect);
|
if (!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);
|
dwarnln("Could not display {} bounds: {}", SDL_GetError());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
register_display(rect.x, rect.y, rect.w, rect.h);
|
||||||
}
|
}
|
||||||
|
|
||||||
sdl3_initialize_keymap();
|
sdl3_initialize_keymap();
|
||||||
@@ -107,7 +108,7 @@ static bool sdl3_initialize(uint32_t* display_w, uint32_t* display_h)
|
|||||||
return true;
|
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());
|
auto window = TRY(BAN::UniqPtr<SDLWindow>::create());
|
||||||
|
|
||||||
@@ -119,29 +120,19 @@ static BAN::ErrorOr<BAN::UniqPtr<PlatformWindow>> sdl3_create_window(PlatformWin
|
|||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case WindowType::Normal:
|
case WindowType::Normal:
|
||||||
case WindowType::Utility:
|
|
||||||
flags = SDL_WINDOW_RESIZABLE;
|
flags = SDL_WINDOW_RESIZABLE;
|
||||||
break;
|
break;
|
||||||
|
case WindowType::Utility:
|
||||||
|
flags = SDL_WINDOW_RESIZABLE | SDL_WINDOW_UTILITY;
|
||||||
|
break;
|
||||||
case WindowType::Popup:
|
case WindowType::Popup:
|
||||||
flags = SDL_WINDOW_BORDERLESS;
|
flags = SDL_WINDOW_BORDERLESS | SDL_WINDOW_UTILITY;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parent == nullptr || type != WindowType::Popup)
|
flags |= SDL_WINDOW_TRANSPARENT;
|
||||||
{
|
|
||||||
if (type != WindowType::Normal)
|
|
||||||
flags |= SDL_WINDOW_UTILITY;
|
|
||||||
window->window = SDL_CreateWindow("", width, height, flags);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto& sdl_parent = *static_cast<SDLWindow*>(parent);
|
|
||||||
|
|
||||||
int parent_x, parent_y;
|
window->window = SDL_CreateWindow("", width, height, flags);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (window->window == nullptr)
|
if (window->window == nullptr)
|
||||||
{
|
{
|
||||||
@@ -149,6 +140,9 @@ static BAN::ErrorOr<BAN::UniqPtr<PlatformWindow>> sdl3_create_window(PlatformWin
|
|||||||
return BAN::Error::from_errno(EFAULT);
|
return BAN::Error::from_errno(EFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (x != 0 || y != 0)
|
||||||
|
SDL_SetWindowPosition(window->window, x, y);
|
||||||
|
|
||||||
window->renderer = SDL_CreateRenderer(window->window, nullptr);
|
window->renderer = SDL_CreateRenderer(window->window, nullptr);
|
||||||
if (window->renderer == 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);
|
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);
|
window->texture = SDL_CreateTexture(window->renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, width, height);
|
||||||
if (window->texture == nullptr)
|
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);
|
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++)
|
for (int32_t y_off = 0; y_off < rect.h; y_off++)
|
||||||
{
|
{
|
||||||
memcpy(
|
memcpy(
|
||||||
static_cast<uint8_t*>(dst_pixels) + y_off * dst_pitch,
|
static_cast< uint8_t*>(dst_pixels) + y_off * dst_pitch,
|
||||||
&src_pixels[(rect.y + y_off) * sdl_window.width + rect.x],
|
static_cast<const uint8_t*>(src_pixels) + y_off * src_pitch,
|
||||||
rect.w * sizeof(uint32_t)
|
rect.w * sizeof(uint32_t)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_UnlockTexture(sdl_window.texture);
|
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_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);
|
SDL_RenderPresent(sdl_window.renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -438,6 +438,8 @@ PlatformOps g_platform_ops = {
|
|||||||
.poll_events = sdl3_poll_events,
|
.poll_events = sdl3_poll_events,
|
||||||
.create_window = sdl3_create_window,
|
.create_window = sdl3_create_window,
|
||||||
.invalidate = sdl3_invalidate,
|
.invalidate = sdl3_invalidate,
|
||||||
|
.begin_frame = nullptr,
|
||||||
|
.end_frame = sdl3_end_frame,
|
||||||
.request_resize = sdl3_request_resize,
|
.request_resize = sdl3_request_resize,
|
||||||
.request_reposition = sdl3_request_reposition,
|
.request_reposition = sdl3_request_reposition,
|
||||||
.request_fullscreen = sdl3_request_fullscreen,
|
.request_fullscreen = sdl3_request_fullscreen,
|
||||||
@@ -505,9 +507,9 @@ static uint32_t sdl3_keycode_to_x_keysym(SDL_Keycode keycode)
|
|||||||
{
|
{
|
||||||
if (iswprint(keycode))
|
if (iswprint(keycode))
|
||||||
{
|
{
|
||||||
if ((keycode >= 0x20 && keycode <= 0x7E) || (keycode >= 0xA0 && keycode <= 0xFF))
|
if (keycode >= 0x100)
|
||||||
return keycode;
|
keycode |= 0x01000000;
|
||||||
return 0x01000000 | keycode;
|
return keycode;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (keycode)
|
switch (keycode)
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ struct BananCursor final : public PlatformCursor
|
|||||||
|
|
||||||
static BAN::ErrorOr<void> bananos_initialize_keymap();
|
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;
|
auto attributes = LibGUI::Window::default_attributes;
|
||||||
attributes.shown = false;
|
attributes.shown = false;
|
||||||
@@ -40,8 +40,7 @@ static bool bananos_initialize(uint32_t* display_w, uint32_t* display_h)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
*display_w = dummy_or_error.value()->width();
|
register_display(0, 0, dummy_or_error.value()->width(), dummy_or_error.value()->height());
|
||||||
*display_h = dummy_or_error.value()->height();
|
|
||||||
|
|
||||||
if (auto ret = bananos_initialize_keymap(); ret.is_error())
|
if (auto ret = bananos_initialize_keymap(); ret.is_error())
|
||||||
{
|
{
|
||||||
@@ -58,12 +57,9 @@ static void bananos_poll_events(void* window)
|
|||||||
banan_window.window->poll_events();
|
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)type;
|
||||||
(void)x;
|
|
||||||
(void)y;
|
|
||||||
|
|
||||||
auto window = TRY(BAN::UniqPtr<BananWindow>::create());
|
auto window = TRY(BAN::UniqPtr<BananWindow>::create());
|
||||||
|
|
||||||
@@ -71,6 +67,7 @@ static BAN::ErrorOr<BAN::UniqPtr<PlatformWindow>> bananos_create_window(Platform
|
|||||||
attributes.shown = true;
|
attributes.shown = true;
|
||||||
attributes.title_bar = false;
|
attributes.title_bar = false;
|
||||||
attributes.resizable = true;
|
attributes.resizable = true;
|
||||||
|
attributes.alpha_channel = true;
|
||||||
|
|
||||||
auto gui_window = TRY(LibGUI::Window::create(width, height, ""_sv, attributes));
|
auto gui_window = TRY(LibGUI::Window::create(width, height, ""_sv, attributes));
|
||||||
auto* winp = gui_window.ptr();
|
auto* winp = gui_window.ptr();
|
||||||
@@ -133,18 +130,28 @@ static void bananos_request_resize(PlatformWindow* window, uint32_t width, uint3
|
|||||||
banan_window.window->request_resize(width, height);
|
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_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);
|
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 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)
|
static void bananos_request_fullscreen(PlatformWindow* window, bool fullscreen)
|
||||||
@@ -187,6 +194,8 @@ PlatformOps g_platform_ops = {
|
|||||||
.poll_events = bananos_poll_events,
|
.poll_events = bananos_poll_events,
|
||||||
.create_window = bananos_create_window,
|
.create_window = bananos_create_window,
|
||||||
.invalidate = bananos_invalidate,
|
.invalidate = bananos_invalidate,
|
||||||
|
.begin_frame = nullptr,
|
||||||
|
.end_frame = bananos_end_frame,
|
||||||
.request_resize = bananos_request_resize,
|
.request_resize = bananos_request_resize,
|
||||||
.request_reposition = nullptr,
|
.request_reposition = nullptr,
|
||||||
.request_fullscreen = bananos_request_fullscreen,
|
.request_fullscreen = bananos_request_fullscreen,
|
||||||
@@ -201,29 +210,27 @@ PlatformOps g_platform_ops = {
|
|||||||
#include <LibInput/KeyboardLayout.h>
|
#include <LibInput/KeyboardLayout.h>
|
||||||
#include <LibInput/KeyEvent.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 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?)
|
// FIXME: get this from somewhere (gui command? enviroment? tmp file?)
|
||||||
const auto keymap_path = "./us.keymap"_sv;
|
const auto keymap_path = "./us.keymap"_sv;
|
||||||
|
|
||||||
TRY(LibInput::KeyboardLayout::initialize());
|
TRY(LibInput::KeyboardLayout::initialize());
|
||||||
|
|
||||||
auto& keyboard_layout = LibInput::KeyboardLayout::get();
|
auto& keyboard_layout = LibInput::KeyboardLayout::get();
|
||||||
TRY(keyboard_layout.load_from_file(keymap_path));
|
TRY(keyboard_layout.load_from_file(keymap_path));
|
||||||
|
|
||||||
const BAN::Span<const LibInput::Key> banan_keymaps[] {
|
for (uint8_t scancode = 0; scancode < g_keymap_size; scancode++)
|
||||||
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 (size_t layer = 0; layer < g_keymap_layers; layer++)
|
for (size_t layer = 0; layer < g_keymap_layers; layer++)
|
||||||
if (const auto banan_key = banan_keymaps[layer][scancode]; banan_key != LibInput::Key::None)
|
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_key_to_x_keysym(banan_key, layer % 2);
|
g_keymap[scancode][layer] = bananos_keyevent_to_x_keysym(event);
|
||||||
|
|
||||||
using LibInput::keycode_normal;
|
using LibInput::keycode_normal;
|
||||||
using LibInput::keycode_numpad;
|
using LibInput::keycode_numpad;
|
||||||
@@ -258,22 +265,22 @@ static BAN::ErrorOr<void> bananos_initialize_keymap()
|
|||||||
|
|
||||||
#include <wctype.h>
|
#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;
|
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 != BAN::UTF8::invalid && iswprint(codepoint))
|
||||||
{
|
{
|
||||||
if ((codepoint >= 0x20 && codepoint <= 0x7E) || (codepoint >= 0xA0 && codepoint <= 0xFF))
|
if (codepoint >= 0x100)
|
||||||
return codepoint;
|
codepoint |= 0x01000000;
|
||||||
return 0x01000000 | codepoint;
|
return codepoint;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (key)
|
switch (event.key)
|
||||||
{
|
{
|
||||||
case Key::F1: return XK_F1;
|
case Key::F1: return XK_F1;
|
||||||
case Key::F2: return XK_F2;
|
case Key::F2: return XK_F2;
|
||||||
|
|||||||
258
xbanan/main.cpp
258
xbanan/main.cpp
@@ -5,8 +5,8 @@
|
|||||||
#include <X11/Xatom.h>
|
#include <X11/Xatom.h>
|
||||||
|
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
#include <poll.h>
|
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
#include <sys/epoll.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@@ -19,6 +19,8 @@
|
|||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
CARD32 g_next_global_id { 1 };
|
||||||
|
|
||||||
const xPixmapFormat g_formats[6] {
|
const xPixmapFormat g_formats[6] {
|
||||||
{
|
{
|
||||||
.depth = 1,
|
.depth = 1,
|
||||||
@@ -58,7 +60,7 @@ const xDepth g_depth {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const xVisualType g_visual {
|
const xVisualType g_visual {
|
||||||
.visualID = 1,
|
.visualID = g_next_global_id++,
|
||||||
.c_class = TrueColor,
|
.c_class = TrueColor,
|
||||||
.bitsPerRGB = 8,
|
.bitsPerRGB = 8,
|
||||||
.colormapEntries = 256,
|
.colormapEntries = 256,
|
||||||
@@ -68,31 +70,34 @@ const xVisualType g_visual {
|
|||||||
};
|
};
|
||||||
|
|
||||||
xWindowRoot g_root {
|
xWindowRoot g_root {
|
||||||
.windowId = 2,
|
.windowId = g_next_global_id++,
|
||||||
.defaultColormap = 0,
|
.defaultColormap = 0,
|
||||||
.whitePixel = 0xFFFFFF,
|
.whitePixel = 0xFFFFFF,
|
||||||
.blackPixel = 0x000000,
|
.blackPixel = 0x000000,
|
||||||
.currentInputMask = 0,
|
.currentInputMask = 0,
|
||||||
.pixWidth = 0,
|
.pixWidth = 0,
|
||||||
.pixHeight = 0,
|
.pixHeight = 0,
|
||||||
.mmWidth = 0,
|
.mmWidth = 0,
|
||||||
.mmHeight = 0,
|
.mmHeight = 0,
|
||||||
.minInstalledMaps = 1,
|
.minInstalledMaps = 1,
|
||||||
.maxInstalledMaps = 1,
|
.maxInstalledMaps = 1,
|
||||||
.rootVisualID = g_visual.visualID,
|
.rootVisualID = g_visual.visualID,
|
||||||
.backingStore = 0,
|
.backingStore = 0,
|
||||||
.saveUnders = 0,
|
.saveUnders = 0,
|
||||||
.rootDepth = 24,
|
.rootDepth = g_depth.depth,
|
||||||
.nDepths = 1,
|
.nDepths = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
BAN::Vector<DisplayInfo> g_displays;
|
||||||
|
|
||||||
BAN::HashMap<CARD32, BAN::UniqPtr<Object>> g_objects;
|
BAN::HashMap<CARD32, BAN::UniqPtr<Object>> g_objects;
|
||||||
|
|
||||||
BAN::HashMap<BAN::String, ATOM> g_atoms_name_to_id;
|
BAN::HashMap<BAN::String, ATOM> g_atoms_name_to_id;
|
||||||
BAN::HashMap<ATOM, BAN::String> g_atoms_id_to_name;
|
BAN::HashMap<ATOM, BAN::String> g_atoms_id_to_name;
|
||||||
ATOM g_atom_value = XA_LAST_PREDEFINED + 1;
|
ATOM g_atom_value = XA_LAST_PREDEFINED + 1;
|
||||||
|
|
||||||
BAN::HashMap<int, Pollable> g_pollables;
|
int g_epoll_fd;
|
||||||
|
BAN::HashMap<int, EpollThingy> g_epoll_thingies;
|
||||||
|
|
||||||
int g_server_grabber_fd = -1;
|
int g_server_grabber_fd = -1;
|
||||||
|
|
||||||
@@ -154,6 +159,22 @@ int main()
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_epoll_fd = epoll_create1(0);
|
||||||
|
if (g_epoll_fd == -1)
|
||||||
|
{
|
||||||
|
perror("xbanan: epoll_create1");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
epoll_event event { .events = EPOLLIN, .data = { .ptr = nullptr } };
|
||||||
|
if (epoll_ctl(g_epoll_fd, EPOLL_CTL_ADD, server_sock, &event) == -1)
|
||||||
|
{
|
||||||
|
perror("xbanan: epoll_ctl");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#define APPEND_ATOM(name) do { \
|
#define APPEND_ATOM(name) do { \
|
||||||
MUST(g_atoms_id_to_name.insert(name, #name##_sv.substring(3))); \
|
MUST(g_atoms_id_to_name.insert(name, #name##_sv.substring(3))); \
|
||||||
MUST(g_atoms_name_to_id.insert(#name##_sv.substring(3), name)); \
|
MUST(g_atoms_name_to_id.insert(#name##_sv.substring(3), name)); \
|
||||||
@@ -244,22 +265,62 @@ int main()
|
|||||||
APPEND_ATOM_CUSTOM(_NET_WM_WINDOW_TYPE_UTILITY);
|
APPEND_ATOM_CUSTOM(_NET_WM_WINDOW_TYPE_UTILITY);
|
||||||
#undef APPEND_ATOM_CUSTOM
|
#undef APPEND_ATOM_CUSTOM
|
||||||
|
|
||||||
uint32_t display_w, display_h;
|
if (!g_platform_ops.initialize())
|
||||||
if (!g_platform_ops.initialize(&display_w, &display_h))
|
|
||||||
return 1;
|
return 1;
|
||||||
g_root.pixWidth = display_w;
|
|
||||||
g_root.pixHeight = display_h;
|
if (g_displays.empty())
|
||||||
g_root.mmWidth = static_cast<CARD16>(display_w * 254 / 960); // 96 DPI
|
{
|
||||||
g_root.mmHeight = static_cast<CARD16>(display_h * 254 / 960); // 96 DPI
|
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");
|
printf("xbanan started\n");
|
||||||
|
|
||||||
const auto close_client =
|
const auto close_client =
|
||||||
[](int client_fd)
|
[](int client_fd)
|
||||||
{
|
{
|
||||||
auto& pollable = g_pollables[client_fd];
|
auto& epoll_thingy = g_epoll_thingies[client_fd];
|
||||||
ASSERT(pollable.type == Pollable::Type::Client);
|
ASSERT(epoll_thingy.type == EpollThingy::Type::Client);
|
||||||
auto& client_info = pollable.value.get<Client>();
|
auto& client_info = epoll_thingy.value.get<Client>();
|
||||||
|
|
||||||
dprintln("client {} disconnected", client_fd);
|
dprintln("client {} disconnected", client_fd);
|
||||||
|
|
||||||
@@ -311,68 +372,39 @@ int main()
|
|||||||
g_objects.remove(it);
|
g_objects.remove(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_pollables.remove(client_fd);
|
epoll_ctl(g_epoll_fd, EPOLL_CTL_DEL, client_fd, nullptr);
|
||||||
|
g_epoll_thingies.remove(client_fd);
|
||||||
close(client_fd);
|
close(client_fd);
|
||||||
|
|
||||||
if (g_server_grabber_fd == client_fd)
|
if (client_fd == g_server_grabber_fd)
|
||||||
|
{
|
||||||
g_server_grabber_fd = -1;
|
g_server_grabber_fd = -1;
|
||||||
};
|
|
||||||
|
|
||||||
Client dummy_client {};
|
for (const auto& [_, thingy] : g_epoll_thingies)
|
||||||
MUST(g_objects.insert(g_root.windowId,
|
{
|
||||||
MUST(BAN::UniqPtr<Object>::create(Object {
|
if (thingy.type != EpollThingy::Type::Client)
|
||||||
.type = Object::Type::Window,
|
continue;
|
||||||
.object = Object::Window {
|
|
||||||
.owner = dummy_client,
|
auto& other_client = thingy.value.get<Client>();
|
||||||
.mapped = true,
|
|
||||||
.depth = g_root.rootDepth,
|
uint32_t events = EPOLLIN;
|
||||||
.parent = None,
|
if (other_client.has_epollout)
|
||||||
.c_class = InputOutput,
|
events |= EPOLLOUT;
|
||||||
.width = g_root.pixWidth,
|
|
||||||
.height = g_root.pixHeight,
|
epoll_event event { .events = events, .data = { .fd = other_client.fd } };
|
||||||
|
epoll_ctl(g_epoll_fd, EPOLL_CTL_MOD, other_client.fd, &event);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}))
|
};
|
||||||
));
|
|
||||||
|
|
||||||
MUST(g_objects.insert(g_visual.visualID,
|
|
||||||
MUST(BAN::UniqPtr<Object>::create(Object {
|
|
||||||
.type = Object::Type::Visual,
|
|
||||||
}))
|
|
||||||
));
|
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
BAN::Vector<pollfd> pollfds;
|
epoll_event events[16];
|
||||||
MUST(pollfds.reserve(g_pollables.size() + 1));
|
const int event_count = epoll_wait(g_epoll_fd, events, 16, -1);
|
||||||
MUST(pollfds.push_back({
|
|
||||||
.fd = server_sock,
|
for (int i = 0; i < event_count; i++)
|
||||||
.events = POLLIN,
|
|
||||||
.revents = 0,
|
|
||||||
}));
|
|
||||||
for (auto& [fd, pollable] : g_pollables)
|
|
||||||
{
|
{
|
||||||
short events = 0;
|
if (events[i].data.ptr == nullptr)
|
||||||
if (g_server_grabber_fd == -1 || g_server_grabber_fd == fd)
|
|
||||||
events |= POLLIN;
|
|
||||||
if (pollable.type == Pollable::Type::Client && !pollable.value.get<Client>().output_buffer.empty())
|
|
||||||
events |= POLLOUT;
|
|
||||||
if (events == 0)
|
|
||||||
continue;
|
|
||||||
MUST(pollfds.push_back(pollfd {
|
|
||||||
.fd = fd,
|
|
||||||
.events = events,
|
|
||||||
.revents = 0,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
const int event_count = poll(pollfds.data(), pollfds.size(), -1);
|
|
||||||
|
|
||||||
for (const auto& pollfd : pollfds)
|
|
||||||
{
|
|
||||||
if (pollfd.revents == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (pollfd.fd == server_sock)
|
|
||||||
{
|
{
|
||||||
int client_sock = accept(server_sock, nullptr, nullptr);
|
int client_sock = accept(server_sock, nullptr, nullptr);
|
||||||
if (client_sock == -1)
|
if (client_sock == -1)
|
||||||
@@ -390,8 +422,8 @@ int main()
|
|||||||
client_pid = client_cred.pid;
|
client_pid = client_cred.pid;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
MUST(g_pollables.insert(client_sock, {
|
MUST(g_epoll_thingies.insert(client_sock, {
|
||||||
.type = Pollable::Type::Client,
|
.type = EpollThingy::Type::Client,
|
||||||
.value = Client {
|
.value = Client {
|
||||||
.fd = client_sock,
|
.fd = client_sock,
|
||||||
.state = Client::State::ConnectionSetup,
|
.state = Client::State::ConnectionSetup,
|
||||||
@@ -399,32 +431,44 @@ int main()
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
uint32_t events = 0;
|
||||||
|
if (g_server_grabber_fd == -1)
|
||||||
|
events |= EPOLLIN;
|
||||||
|
|
||||||
|
epoll_event event = { .events = events, .data = { .fd = client_sock } };
|
||||||
|
if (epoll_ctl(g_epoll_fd, EPOLL_CTL_ADD, client_sock, &event) == -1)
|
||||||
|
{
|
||||||
|
perror("xbanan: epoll_ctl");
|
||||||
|
close(client_sock);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
dprintln("client {} connected", client_sock);
|
dprintln("client {} connected", client_sock);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto it = g_pollables.find(pollfd.fd);
|
auto it = g_epoll_thingies.find(events[i].data.fd);
|
||||||
if (it == g_pollables.end())
|
if (it == g_epoll_thingies.end())
|
||||||
continue;
|
continue;
|
||||||
auto& pollable = it->value;
|
auto& epoll_thingy = it->value;
|
||||||
|
|
||||||
if (pollable.type == Pollable::Type::Event)
|
if (epoll_thingy.type == EpollThingy::Type::Event)
|
||||||
{
|
{
|
||||||
g_platform_ops.poll_events(pollable.value.get<void*>());
|
g_platform_ops.poll_events(epoll_thingy.value.get<void*>());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT(pollable.type == Pollable::Type::Client);
|
ASSERT(epoll_thingy.type == EpollThingy::Type::Client);
|
||||||
|
|
||||||
auto& client_info = pollable.value.get<Client>();
|
auto& client_info = epoll_thingy.value.get<Client>();
|
||||||
|
|
||||||
if (pollfd.revents & POLLHUP)
|
if (events[i].events & EPOLLHUP)
|
||||||
{
|
{
|
||||||
close_client(client_info.fd);
|
close_client(client_info.fd);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pollfd.revents & POLLOUT)
|
if (events[i].events & EPOLLOUT)
|
||||||
{
|
{
|
||||||
const ssize_t nsend = send(
|
const ssize_t nsend = send(
|
||||||
client_info.fd,
|
client_info.fd,
|
||||||
@@ -451,11 +495,28 @@ int main()
|
|||||||
);
|
);
|
||||||
MUST(client_info.output_buffer.resize(client_info.output_buffer.size() - nsend));
|
MUST(client_info.output_buffer.resize(client_info.output_buffer.size() - nsend));
|
||||||
|
|
||||||
|
if (client_info.output_buffer.empty())
|
||||||
|
{
|
||||||
|
uint32_t events = 0;
|
||||||
|
if (g_server_grabber_fd == -1 || g_server_grabber_fd == client_info.fd)
|
||||||
|
events |= EPOLLIN;
|
||||||
|
|
||||||
|
epoll_event event { .events = events, .data = { .fd = client_info.fd } };
|
||||||
|
if (epoll_ctl(g_epoll_fd, EPOLL_CTL_MOD, client_info.fd, &event) == -1)
|
||||||
|
{
|
||||||
|
perror("xbanan: epoll_ctl");
|
||||||
|
close_client(client_info.fd);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
client_info.has_epollout = false;
|
||||||
|
}
|
||||||
|
|
||||||
send_done:
|
send_done:
|
||||||
(void)0;
|
(void)0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(pollfd.revents & POLLIN))
|
if (!(events[i].events & EPOLLIN))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (g_server_grabber_fd != -1 && g_server_grabber_fd != client_info.fd)
|
if (g_server_grabber_fd != -1 && g_server_grabber_fd != client_info.fd)
|
||||||
@@ -567,5 +628,42 @@ 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)
|
||||||
|
{
|
||||||
|
if (thingy.type != EpollThingy::Type::Client)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto& client_info = thingy.value.get<Client>();
|
||||||
|
if (client_info.output_buffer.empty() || client_info.has_epollout)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
uint32_t events = EPOLLOUT;
|
||||||
|
if (g_server_grabber_fd == -1 || g_server_grabber_fd == client_info.fd)
|
||||||
|
events |= EPOLLIN;
|
||||||
|
|
||||||
|
epoll_event event { .events = events, .data = { .fd = client_info.fd } };
|
||||||
|
if (epoll_ctl(g_epoll_fd, EPOLL_CTL_MOD, client_info.fd, &event) == -1)
|
||||||
|
{
|
||||||
|
perror("xbanan: epoll_ctl");
|
||||||
|
close_client(client_info.fd);
|
||||||
|
goto iterator_invalidated;
|
||||||
|
}
|
||||||
|
|
||||||
|
client_info.has_epollout = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user