Implement per-client event masks

This allows multiple clients to listen for events on the same window.
Mostly used for listening events on the root window
This commit is contained in:
Oskari Alaranta 2026-02-23 00:25:27 +02:00
parent e376c57cda
commit 61f8b2fa66
3 changed files with 191 additions and 219 deletions

View File

@ -159,6 +159,27 @@ static const char* s_opcode_to_name[] {
[X_NoOperation] = "X_NoOperation", [X_NoOperation] = "X_NoOperation",
}; };
uint32_t Object::Window::full_event_mask() const
{
uint32_t full_event_mask = 0;
for (auto [_, event_mask] : event_masks)
full_event_mask |= event_mask;
return full_event_mask;
}
BAN::ErrorOr<void> Object::Window::send_event(xEvent xevent, uint32_t xmask)
{
for (auto [client, event_mask] : event_masks)
{
if (!(event_mask & xmask))
continue;
xevent.u.u.sequenceNumber = client->sequence;
TRY(encode(client->output_buffer, xevent));
}
return {};
}
BAN::ErrorOr<void> setup_client_conneciton(Client& client_info, const xConnClientPrefix& client_prefix) BAN::ErrorOr<void> setup_client_conneciton(Client& client_info, const xConnClientPrefix& client_prefix)
{ {
dprintln("Connection Setup"); dprintln("Connection Setup");
@ -251,18 +272,14 @@ static BAN::ErrorOr<void> send_visibility_events_recursively(Client& client_info
if (window.c_class == InputOutput) if (window.c_class == InputOutput)
{ {
if (window.event_mask & VisibilityChangeMask) xEvent event = { .u = {
{ .visibility = {
xEvent event = { .u = { .window = wid,
.visibility = { .state = static_cast<CARD8>(visible ? 0 : 2),
.window = wid, }
.state = static_cast<CARD8>(visible ? 0 : 2), }};
} event.u.u.type = VisibilityNotify;
}}; TRY(window.send_event(event, VisibilityChangeMask));
event.u.u.type = VisibilityNotify;
event.u.u.sequenceNumber = client_info.sequence;
TRY(encode(client_info.output_buffer, event));
}
} }
for (auto child_wid : window.children) for (auto child_wid : window.children)
@ -413,7 +430,6 @@ static BAN::ErrorOr<void> map_window(Client& client_info, WINDOW wid)
gui_window->invalidate(); gui_window->invalidate();
} }
if (window.event_mask & StructureNotifyMask)
{ {
xEvent event = { .u = { xEvent event = { .u = {
.mapNotify = { .mapNotify = {
@ -423,15 +439,13 @@ static BAN::ErrorOr<void> map_window(Client& client_info, WINDOW wid)
} }
}}; }};
event.u.u.type = MapNotify; event.u.u.type = MapNotify;
event.u.u.sequenceNumber = client_info.sequence; TRY(window.send_event(event, StructureNotifyMask));
TRY(encode(client_info.output_buffer, event));
} }
auto& parent_object = *g_objects[window.parent]; auto& parent_object = *g_objects[window.parent];
ASSERT(parent_object.type == Object::Type::Window); ASSERT(parent_object.type == Object::Type::Window);
auto& parent_window = parent_object.object.get<Object::Window>(); auto& parent_window = parent_object.object.get<Object::Window>();
if (parent_window.event_mask & SubstructureNotifyMask)
{ {
xEvent event = { .u = { xEvent event = { .u = {
.mapNotify = { .mapNotify = {
@ -441,14 +455,12 @@ static BAN::ErrorOr<void> map_window(Client& client_info, WINDOW wid)
} }
}}; }};
event.u.u.type = MapNotify; event.u.u.type = MapNotify;
event.u.u.sequenceNumber = client_info.sequence; TRY(parent_window.send_event(event, SubstructureNotifyMask));
TRY(encode(client_info.output_buffer, event));
} }
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));
if (window.event_mask & ExposureMask)
{ {
xEvent event = { .u = { xEvent event = { .u = {
.expose = { .expose = {
@ -460,8 +472,7 @@ static BAN::ErrorOr<void> map_window(Client& client_info, WINDOW wid)
} }
}}; }};
event.u.u.type = Expose; event.u.u.type = Expose;
event.u.u.sequenceNumber = client_info.sequence; TRY(window.send_event(event, ExposureMask));
TRY(encode(client_info.output_buffer, event));
} }
return {}; return {};
@ -489,7 +500,6 @@ static BAN::ErrorOr<void> unmap_window(Client& client_info, WINDOW wid)
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));
if (window.event_mask & StructureNotifyMask)
{ {
xEvent event = { .u = { xEvent event = { .u = {
.unmapNotify = { .unmapNotify = {
@ -499,15 +509,13 @@ static BAN::ErrorOr<void> unmap_window(Client& client_info, WINDOW wid)
} }
}}; }};
event.u.u.type = UnmapNotify; event.u.u.type = UnmapNotify;
event.u.u.sequenceNumber = client_info.sequence; TRY(window.send_event(event, StructureNotifyMask));
TRY(encode(client_info.output_buffer, event));
} }
auto& parent_object = *g_objects[window.parent]; auto& parent_object = *g_objects[window.parent];
ASSERT(parent_object.type == Object::Type::Window); ASSERT(parent_object.type == Object::Type::Window);
auto& parent_window = parent_object.object.get<Object::Window>(); auto& parent_window = parent_object.object.get<Object::Window>();
if (parent_window.event_mask & SubstructureNotifyMask)
{ {
xEvent event = { .u = { xEvent event = { .u = {
.unmapNotify = { .unmapNotify = {
@ -517,8 +525,7 @@ static BAN::ErrorOr<void> unmap_window(Client& client_info, WINDOW wid)
} }
}}; }};
event.u.u.type = UnmapNotify; event.u.u.type = UnmapNotify;
event.u.u.sequenceNumber = client_info.sequence; TRY(parent_window.send_event(event, SubstructureNotifyMask));
TRY(encode(client_info.output_buffer, event));
} }
return {}; return {};
@ -536,7 +543,6 @@ static BAN::ErrorOr<void> destroy_window(Client& client_info, WINDOW wid)
for (auto child_wid : window.children) for (auto child_wid : window.children)
TRY(destroy_window(client_info, child_wid)); TRY(destroy_window(client_info, child_wid));
if (window.event_mask & StructureNotifyMask)
{ {
xEvent event = { .u = { xEvent event = { .u = {
.destroyNotify = { .destroyNotify = {
@ -545,15 +551,13 @@ static BAN::ErrorOr<void> destroy_window(Client& client_info, WINDOW wid)
} }
}}; }};
event.u.u.type = DestroyNotify; event.u.u.type = DestroyNotify;
event.u.u.sequenceNumber = client_info.sequence; TRY(window.send_event(event, StructureNotifyMask));
TRY(encode(client_info.output_buffer, event));
} }
auto& parent_object = *g_objects[window.parent]; auto& parent_object = *g_objects[window.parent];
ASSERT(parent_object.type == Object::Type::Window); ASSERT(parent_object.type == Object::Type::Window);
auto& parent_window = parent_object.object.get<Object::Window>(); auto& parent_window = parent_object.object.get<Object::Window>();
if (parent_window.event_mask & SubstructureNotifyMask)
{ {
xEvent event = { .u = { xEvent event = { .u = {
.destroyNotify = { .destroyNotify = {
@ -562,8 +566,7 @@ static BAN::ErrorOr<void> destroy_window(Client& client_info, WINDOW wid)
} }
}}; }};
event.u.u.type = DestroyNotify; event.u.u.type = DestroyNotify;
event.u.u.sequenceNumber = client_info.sequence; TRY(parent_window.send_event(event, SubstructureNotifyMask));
TRY(encode(client_info.output_buffer, event));
} }
for (size_t i = 0; i < parent_window.children.size(); i++) for (size_t i = 0; i < parent_window.children.size(); i++)
@ -669,7 +672,7 @@ static BAN::Vector<WINDOW> get_path_to_child(WINDOW wid, int32_t x, int32_t y)
return result; return result;
} }
static void send_enter_and_leave_events(Client& client_info, WINDOW wid, int32_t old_x, int32_t old_y, int32_t new_x, int32_t new_y) static void send_enter_and_leave_events(WINDOW wid, int32_t old_x, int32_t old_y, int32_t new_x, int32_t new_y)
{ {
// FIXME: correct event_x and event_y values in events // FIXME: correct event_x and event_y values in events
@ -722,10 +725,8 @@ static void send_enter_and_leave_events(Client& client_info, WINDOW wid, int32_t
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>();
if (!(window.event_mask & LeaveWindowMask))
continue;
xEvent xevent { .u = { xEvent event { .u = {
.enterLeave = { .enterLeave = {
.time = static_cast<CARD32>(time(nullptr)), .time = static_cast<CARD32>(time(nullptr)),
.root = g_root.windowId, .root = g_root.windowId,
@ -740,10 +741,9 @@ static void send_enter_and_leave_events(Client& client_info, WINDOW wid, int32_t
.flags = get_flags(wid), .flags = get_flags(wid),
} }
}}; }};
xevent.u.u.type = LeaveNotify, event.u.u.type = LeaveNotify,
xevent.u.u.detail = detail; event.u.u.detail = detail;
xevent.u.u.sequenceNumber = client_info.sequence; MUST(window.send_event(event, LeaveWindowMask));
MUST(encode(client_info.output_buffer, xevent));
} }
for (size_t i = 0; i < enter_events; i++) for (size_t i = 0; i < enter_events; i++)
@ -765,10 +765,8 @@ static void send_enter_and_leave_events(Client& client_info, WINDOW wid, int32_t
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>();
if (!(window.event_mask & EnterWindowMask))
continue;
xEvent xevent { .u = { xEvent event { .u = {
.enterLeave = { .enterLeave = {
.time = static_cast<CARD32>(time(nullptr)), .time = static_cast<CARD32>(time(nullptr)),
.root = g_root.windowId, .root = g_root.windowId,
@ -783,14 +781,13 @@ static void send_enter_and_leave_events(Client& client_info, WINDOW wid, int32_t
.flags = get_flags(wid), .flags = get_flags(wid),
} }
}}; }};
xevent.u.u.type = EnterNotify, event.u.u.type = EnterNotify,
xevent.u.u.detail = detail; event.u.u.detail = detail;
xevent.u.u.sequenceNumber = client_info.sequence; MUST(window.send_event(event, EnterWindowMask));
MUST(encode(client_info.output_buffer, xevent));
} }
} }
static void send_exposure_recursive(Client& client_info, WINDOW wid) static void send_exposure_recursive(WINDOW wid)
{ {
auto& object = *g_objects[wid]; auto& object = *g_objects[wid];
ASSERT(object.type == Object::Type::Window); ASSERT(object.type == Object::Type::Window);
@ -800,25 +797,21 @@ static void send_exposure_recursive(Client& client_info, WINDOW wid)
return; return;
for (auto child_wid : window.children) for (auto child_wid : window.children)
send_exposure_recursive(client_info, child_wid); send_exposure_recursive(child_wid);
window.texture().clear(); window.texture().clear();
if (window.event_mask & ExposureMask) xEvent event = { .u = {
{ .expose = {
xEvent event = { .u = { .window = wid,
.expose = { .x = 0,
.window = wid, .y = 0,
.x = 0, .width = static_cast<CARD16>(window.texture().width()),
.y = 0, .height = static_cast<CARD16>(window.texture().height()),
.width = static_cast<CARD16>(window.texture().width()), }
.height = static_cast<CARD16>(window.texture().height()), }};
} event.u.u.type = Expose;
}}; MUST(window.send_event(event, ExposureMask));
event.u.u.type = Expose;
event.u.u.sequenceNumber = client_info.sequence;
MUST(encode(client_info.output_buffer, event));
}
} }
static void on_window_close_event(Client& client_info, WINDOW wid) static void on_window_close_event(Client& client_info, WINDOW wid)
@ -870,13 +863,12 @@ static void on_window_close_event(Client& client_info, WINDOW wid)
} }
} }
static void on_window_resize_event(Client& client_info, WINDOW wid) static void on_window_resize_event(WINDOW wid)
{ {
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>();
if (window.event_mask & StructureNotifyMask)
{ {
xEvent event = { .u = { xEvent event = { .u = {
.configureNotify = { .configureNotify = {
@ -892,15 +884,13 @@ static void on_window_resize_event(Client& client_info, WINDOW wid)
} }
}}; }};
event.u.u.type = ConfigureNotify; event.u.u.type = ConfigureNotify;
event.u.u.sequenceNumber = client_info.sequence; MUST(window.send_event(event, StructureNotifyMask));
MUST(encode(client_info.output_buffer, event));
} }
auto& parent_object = *g_objects[window.parent]; auto& parent_object = *g_objects[window.parent];
ASSERT(parent_object.type == Object::Type::Window); ASSERT(parent_object.type == Object::Type::Window);
auto& parent_window = parent_object.object.get<Object::Window>(); auto& parent_window = parent_object.object.get<Object::Window>();
if (parent_window.event_mask & SubstructureNotifyMask)
{ {
xEvent event = { .u = { xEvent event = { .u = {
.configureNotify = { .configureNotify = {
@ -916,16 +906,15 @@ static void on_window_resize_event(Client& client_info, WINDOW wid)
} }
}}; }};
event.u.u.type = ConfigureNotify; event.u.u.type = ConfigureNotify;
event.u.u.sequenceNumber = client_info.sequence; MUST(parent_window.send_event(event, SubstructureNotifyMask));
MUST(encode(client_info.output_buffer, event));
} }
send_exposure_recursive(client_info, wid); send_exposure_recursive(wid);
invalidate_window(wid, 0, 0, window.texture().width(), window.texture().height()); invalidate_window(wid, 0, 0, window.texture().width(), window.texture().height());
} }
static void on_window_focus_event(Client& client_info, WINDOW wid, bool focused) static void on_window_focus_event(WINDOW wid, bool focused)
{ {
if (focused) if (focused)
s_focus_window = wid; s_focus_window = wid;
@ -939,24 +928,20 @@ static void on_window_focus_event(Client& client_info, WINDOW wid, bool focused)
window.focused = focused; window.focused = focused;
if (!(window.event_mask & FocusChangeMask))
return;
// FIXME: handle childs // FIXME: handle childs
xEvent xevent { .u = { xEvent event { .u = {
.focus = { .focus = {
.window = wid, .window = wid,
.mode = NotifyNormal, .mode = NotifyNormal,
} }
}}; }};
xevent.u.u.type = focused ? FocusIn : FocusOut, event.u.u.type = focused ? FocusIn : FocusOut,
xevent.u.u.detail = NotifyNonlinear; event.u.u.detail = NotifyNonlinear;
xevent.u.u.sequenceNumber = client_info.sequence; MUST(window.send_event(event, FocusChangeMask));
MUST(encode(client_info.output_buffer, xevent));
} }
static void send_key_button_pointer_event(Client& client_info, WINDOW root_wid, BYTE detail, uint32_t event_mask, BYTE event_type) static void send_key_button_pointer_event(WINDOW root_wid, BYTE detail, uint32_t event_mask, BYTE event_type)
{ {
int32_t root_x, root_y; int32_t root_x, root_y;
int32_t event_x, event_y; int32_t event_x, event_y;
@ -977,7 +962,7 @@ static void send_key_button_pointer_event(Client& client_info, WINDOW root_wid,
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>();
if (window.event_mask & event_mask) if (window.full_event_mask() & event_mask)
break; break;
event_x += window.x; event_x += window.x;
@ -992,7 +977,11 @@ static void send_key_button_pointer_event(Client& client_info, WINDOW root_wid,
wid = root_wid; wid = root_wid;
} }
xEvent xevent { .u = { auto& object = *g_objects[wid];
ASSERT(object.type == Object::Type::Window);
auto& window = object.object.get<Object::Window>();
xEvent event { .u = {
.keyButtonPointer = { .keyButtonPointer = {
.time = static_cast<CARD32>(time(nullptr)), .time = static_cast<CARD32>(time(nullptr)),
.root = g_root.windowId, .root = g_root.windowId,
@ -1006,10 +995,9 @@ static void send_key_button_pointer_event(Client& client_info, WINDOW root_wid,
.sameScreen = xTrue, .sameScreen = xTrue,
} }
}}; }};
xevent.u.u.type = event_type, event.u.u.type = event_type,
xevent.u.u.detail = detail; event.u.u.detail = detail;
xevent.u.u.sequenceNumber = client_info.sequence; MUST(window.send_event(event, event_mask));
MUST(encode(client_info.output_buffer, xevent));
} }
static void update_cursor_position_recursive(WINDOW wid, int32_t new_x, int32_t new_y) static void update_cursor_position_recursive(WINDOW wid, int32_t new_x, int32_t new_y)
@ -1049,7 +1037,7 @@ static void update_cursor(WINDOW wid, int32_t old_x, int32_t old_y, int32_t new_
gui_window->set_cursor(cursor.width, cursor.height, cursor.pixels.span(), cursor.origin_x, cursor.origin_y); gui_window->set_cursor(cursor.width, cursor.height, cursor.pixels.span(), cursor.origin_x, cursor.origin_y);
} }
static void on_mouse_move_event(Client& client_info, WINDOW wid, int32_t x, int32_t y) static void on_mouse_move_event(WINDOW wid, int32_t x, int32_t y)
{ {
auto& object = *g_objects[wid]; auto& object = *g_objects[wid];
ASSERT(object.type == Object::Type::Window); ASSERT(object.type == Object::Type::Window);
@ -1057,7 +1045,7 @@ static void on_mouse_move_event(Client& client_info, WINDOW wid, int32_t x, int3
update_cursor(wid, window.cursor_x, window.cursor_y, x, y); update_cursor(wid, window.cursor_x, window.cursor_y, x, y);
send_enter_and_leave_events(client_info, wid, window.cursor_x, window.cursor_y, x, y); send_enter_and_leave_events(wid, window.cursor_x, window.cursor_y, x, y);
update_cursor_position_recursive(wid, x, y); update_cursor_position_recursive(wid, x, y);
@ -1069,10 +1057,10 @@ static void on_mouse_move_event(Client& client_info, WINDOW wid, int32_t x, int3
if (s_butmask & Button3Mask) event_mask |= Button3MotionMask; if (s_butmask & Button3Mask) event_mask |= Button3MotionMask;
if (s_butmask & Button4Mask) event_mask |= Button4MotionMask; if (s_butmask & Button4Mask) event_mask |= Button4MotionMask;
if (s_butmask & Button5Mask) event_mask |= Button5MotionMask; if (s_butmask & Button5Mask) event_mask |= Button5MotionMask;
send_key_button_pointer_event(client_info, wid, NotifyNormal, event_mask, MotionNotify); send_key_button_pointer_event(wid, NotifyNormal, event_mask, MotionNotify);
} }
static void on_mouse_button_event(Client& client_info, WINDOW wid, uint8_t xbutton, bool pressed) static void on_mouse_button_event(WINDOW wid, uint8_t xbutton, bool pressed)
{ {
uint16_t mask = 0; uint16_t mask = 0;
switch (xbutton) switch (xbutton)
@ -1090,7 +1078,6 @@ static void on_mouse_button_event(Client& client_info, WINDOW wid, uint8_t xbutt
s_butmask &= ~mask; s_butmask &= ~mask;
send_key_button_pointer_event( send_key_button_pointer_event(
client_info,
wid, wid,
xbutton, xbutton,
pressed ? ButtonPressMask : ButtonReleaseMask, pressed ? ButtonPressMask : ButtonReleaseMask,
@ -1098,7 +1085,7 @@ static void on_mouse_button_event(Client& client_info, WINDOW wid, uint8_t xbutt
); );
} }
static void on_key_event(Client& client_info, WINDOW wid, LibGUI::EventPacket::KeyEvent::event_t event) static void on_key_event(WINDOW wid, LibGUI::EventPacket::KeyEvent::event_t event)
{ {
const uint8_t xkeycode = event.scancode + g_keymap_min_keycode; const uint8_t xkeycode = event.scancode + g_keymap_min_keycode;
if (xkeycode < g_keymap_min_keycode) if (xkeycode < g_keymap_min_keycode)
@ -1127,7 +1114,6 @@ static void on_key_event(Client& client_info, WINDOW wid, LibGUI::EventPacket::K
s_keymask |= Mod1Mask; s_keymask |= Mod1Mask;
send_key_button_pointer_event( send_key_button_pointer_event(
client_info,
wid, wid,
xkeycode, xkeycode,
event.pressed() ? KeyPressMask : KeyReleaseMask, event.pressed() ? KeyPressMask : KeyReleaseMask,
@ -1135,7 +1121,7 @@ static void on_key_event(Client& client_info, WINDOW wid, LibGUI::EventPacket::K
); );
} }
static void on_window_fullscreen_event(Client& client_info, WINDOW wid, bool is_fullscreen) static void on_window_fullscreen_event(WINDOW wid, bool is_fullscreen)
{ {
static CARD32 _NET_WM_STATE = g_atoms_name_to_id["_NET_WM_STATE"_sv]; static CARD32 _NET_WM_STATE = g_atoms_name_to_id["_NET_WM_STATE"_sv];
static CARD32 _NET_WM_STATE_FULLSCREEN = g_atoms_name_to_id["_NET_WM_STATE_FULLSCREEN"_sv]; static CARD32 _NET_WM_STATE_FULLSCREEN = g_atoms_name_to_id["_NET_WM_STATE_FULLSCREEN"_sv];
@ -1178,26 +1164,16 @@ static void on_window_fullscreen_event(Client& client_info, WINDOW wid, bool is_
reinterpret_cast<CARD32*>(_net_wm_state.data.data())[atom_count] = _NET_WM_STATE_FULLSCREEN; reinterpret_cast<CARD32*>(_net_wm_state.data.data())[atom_count] = _NET_WM_STATE_FULLSCREEN;
} }
if (window.event_mask & PropertyChangeMask) xEvent event = { .u = {
{ .property = {
xEvent event = { .u = { .window = wid,
.property = { .atom = _NET_WM_STATE,
.window = wid, .time = static_cast<CARD32>(time(nullptr)),
.atom = _NET_WM_STATE, .state = PropertyNewValue,
.time = static_cast<CARD32>(time(nullptr)), }
.state = PropertyNewValue, }};
} event.u.u.type = PropertyNotify;
}}; MUST(window.send_event(event, PropertyChangeMask));
event.u.u.type = PropertyNotify;
event.u.u.sequenceNumber = client_info.sequence;
MUST(encode(client_info.output_buffer, event));
dwarnln("sent fullscreen {} to {}", is_fullscreen, wid);
}
else
{
dwarnln("did not send fullscreen {} to {}", is_fullscreen, wid);
}
} }
static void on_root_client_message(const xEvent& event) static void on_root_client_message(const xEvent& event)
@ -1373,7 +1349,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
TRY(parent_window.children.push_back(request.wid)); TRY(parent_window.children.push_back(request.wid));
TRY(client_info.objects.insert(request.wid)); TRY(client_info.objects.insert(request.wid));
TRY(g_objects.insert( auto object_it = TRY(g_objects.insert(
request.wid, request.wid,
TRY(BAN::UniqPtr<Object>::create(Object { TRY(BAN::UniqPtr<Object>::create(Object {
.type = Object::Type::Window, .type = Object::Type::Window,
@ -1381,7 +1357,6 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
.depth = request.depth, .depth = request.depth,
.x = request.x, .x = request.x,
.y = request.y, .y = request.y,
.event_mask = event_mask,
.parent = request.parent, .parent = request.parent,
.cursor = cursor_id, .cursor = cursor_id,
.c_class = request.c_class == CopyFromParent ? parent_window.c_class : request.c_class, .c_class = request.c_class == CopyFromParent ? parent_window.c_class : request.c_class,
@ -1389,6 +1364,8 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
}, },
})) }))
)); ));
if (event_mask != 0)
TRY(object_it->value->object.get<Object::Window>().event_masks.insert(&client_info, event_mask));
if (gui_window_ptr) if (gui_window_ptr)
{ {
@ -1396,17 +1373,17 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
gui_window_ptr->set_close_window_event_callback([&client_info, wid] { gui_window_ptr->set_close_window_event_callback([&client_info, wid] {
on_window_close_event(client_info, wid); on_window_close_event(client_info, wid);
}); });
gui_window_ptr->set_resize_window_event_callback([&client_info, wid]() { gui_window_ptr->set_resize_window_event_callback([wid]() {
on_window_resize_event(client_info, wid); on_window_resize_event(wid);
}); });
gui_window_ptr->set_window_focus_event_callback([&client_info, wid](auto event) { gui_window_ptr->set_window_focus_event_callback([wid](auto event) {
on_window_focus_event(client_info, wid, event.focused); on_window_focus_event(wid, event.focused);
}); });
gui_window_ptr->set_window_fullscreen_event_callback([&client_info, wid](auto event) { gui_window_ptr->set_window_fullscreen_event_callback([wid](auto event) {
on_window_fullscreen_event(client_info, wid, event.fullscreen); on_window_fullscreen_event(wid, event.fullscreen);
}); });
gui_window_ptr->set_mouse_move_event_callback([&client_info, wid](auto event) { gui_window_ptr->set_mouse_move_event_callback([wid](auto event) {
on_mouse_move_event(client_info, wid, event.x, event.y); on_mouse_move_event(wid, event.x, event.y);
}); });
gui_window_ptr->set_mouse_button_event_callback([&client_info, wid](auto event) { gui_window_ptr->set_mouse_button_event_callback([&client_info, wid](auto event) {
uint8_t xbutton = 0; uint8_t xbutton = 0;
@ -1419,35 +1396,31 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
case LibInput::MouseButton::Extra2: xbutton = 9; break; case LibInput::MouseButton::Extra2: xbutton = 9; break;
} }
if (xbutton) if (xbutton)
on_mouse_button_event(client_info, wid, xbutton, event.pressed); on_mouse_button_event(wid, xbutton, event.pressed);
}); });
gui_window_ptr->set_mouse_scroll_event_callback([&client_info, wid](auto event) { gui_window_ptr->set_mouse_scroll_event_callback([wid](auto event) {
on_mouse_button_event(client_info, wid, event.scroll > 0 ? 4 : 5, true); on_mouse_button_event(wid, event.scroll > 0 ? 4 : 5, true);
on_mouse_button_event(client_info, wid, event.scroll > 0 ? 4 : 5, false); on_mouse_button_event(wid, event.scroll > 0 ? 4 : 5, false);
}); });
gui_window_ptr->set_key_event_callback([&client_info, wid](auto event) { gui_window_ptr->set_key_event_callback([wid](auto event) {
on_key_event(client_info, wid, event); on_key_event(wid, event);
}); });
} }
if (parent_window.event_mask & SubstructureNotifyMask) xEvent event = { .u = {
{ .createNotify = {
xEvent event = { .u = { .parent = request.parent,
.createNotify = { .window = request.wid,
.parent = request.parent, .x = request.x,
.window = request.wid, .y = request.y,
.x = request.x, .width = request.width,
.y = request.y, .height = request.height,
.width = request.width, .borderWidth = request.borderWidth,
.height = request.height, .override = false,
.borderWidth = request.borderWidth, }
.override = false, }};
} event.u.u.type = CreateNotify;
}}; TRY(parent_window.send_event(event, SubstructureNotifyMask));
event.u.u.type = CreateNotify;
event.u.u.sequenceNumber = client_info.sequence;
TRY(encode(client_info.output_buffer, event));
}
break; break;
} }
@ -1482,7 +1455,10 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
background = value; background = value;
break; break;
case 11: case 11:
window.event_mask = value; if (value != 0)
TRY(window.event_masks.emplace_or_assign(&client_info, value));
else
window.event_masks.remove(&client_info);
break; break;
case 14: case 14:
cursor_id = value; cursor_id = value;
@ -1522,6 +1498,10 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
const auto& window = TRY_REF(get_window(client_info, wid, opcode)); const auto& window = TRY_REF(get_window(client_info, wid, opcode));
uint32_t my_event_mask = 0;
if (auto it = window.event_masks.find(&client_info); it != window.event_masks.end())
my_event_mask = it->value;
xGetWindowAttributesReply reply { xGetWindowAttributesReply reply {
.type = X_Reply, .type = X_Reply,
.backingStore = 0, .backingStore = 0,
@ -1538,8 +1518,8 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
.mapState = static_cast<CARD8>(is_visible(wid) ? 2 : window.mapped), .mapState = static_cast<CARD8>(is_visible(wid) ? 2 : window.mapped),
.override = 0, .override = 0,
.colormap = 0, .colormap = 0,
.allEventMasks = window.event_mask, .allEventMasks = window.full_event_mask(),
.yourEventMask = window.event_mask, .yourEventMask = my_event_mask,
.doNotPropagateMask = 0, .doNotPropagateMask = 0,
}; };
TRY(encode(client_info.output_buffer, reply)); TRY(encode(client_info.output_buffer, reply));
@ -1597,7 +1577,6 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
if (was_mapped) if (was_mapped)
TRY(map_window(client_info, wid)); TRY(map_window(client_info, wid));
if (old_parent.event_mask & SubstructureNotifyMask)
{ {
xEvent event = { .u = { xEvent event = { .u = {
.reparent = { .reparent = {
@ -1610,11 +1589,9 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
} }
}}; }};
event.u.u.type = ReparentNotify; event.u.u.type = ReparentNotify;
event.u.u.sequenceNumber = client_info.sequence; TRY(old_parent.send_event(event, SubstructureNotifyMask));
TRY(encode(client_info.output_buffer, event));
} }
if (new_parent.event_mask & SubstructureNotifyMask)
{ {
xEvent event = { .u = { xEvent event = { .u = {
.reparent = { .reparent = {
@ -1627,8 +1604,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
} }
}}; }};
event.u.u.type = ReparentNotify; event.u.u.type = ReparentNotify;
event.u.u.sequenceNumber = client_info.sequence; TRY(new_parent.send_event(event, SubstructureNotifyMask));
TRY(encode(client_info.output_buffer, event));
} }
break; break;
@ -1720,9 +1696,6 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
case 3: case 3:
new_height = value; new_height = value;
break; break;
case 11:
window.event_mask = value;
break;
default: default:
dprintln(" {4h}: {4h}", 1 << i, value); dprintln(" {4h}: {4h}", 1 << i, value);
break; break;
@ -1762,7 +1735,6 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
invalidate_window(request.window, min_x, min_y, max_x - min_x, max_y + min_y); invalidate_window(request.window, min_x, min_y, max_x - min_x, max_y + min_y);
if (window.event_mask & StructureNotifyMask)
{ {
xEvent event = { .u = { xEvent event = { .u = {
.configureNotify = { .configureNotify = {
@ -1778,15 +1750,13 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
} }
}}; }};
event.u.u.type = ConfigureNotify; event.u.u.type = ConfigureNotify;
event.u.u.sequenceNumber = client_info.sequence; TRY(window.send_event(event, StructureNotifyMask));
TRY(encode(client_info.output_buffer, event));
} }
auto& parent_object = *g_objects[window.parent]; auto& parent_object = *g_objects[window.parent];
ASSERT(parent_object.type == Object::Type::Window); ASSERT(parent_object.type == Object::Type::Window);
auto& parent_window = parent_object.object.get<Object::Window>(); auto& parent_window = parent_object.object.get<Object::Window>();
if (parent_window.event_mask & SubstructureNotifyMask)
{ {
xEvent event = { .u = { xEvent event = { .u = {
.configureNotify = { .configureNotify = {
@ -1802,8 +1772,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
} }
}}; }};
event.u.u.type = ConfigureNotify; event.u.u.type = ConfigureNotify;
event.u.u.sequenceNumber = client_info.sequence; TRY(parent_window.send_event(event, SubstructureNotifyMask));
TRY(encode(client_info.output_buffer, event));
} }
break; break;
@ -2019,20 +1988,16 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
} }
if (window.event_mask & PropertyChangeMask) xEvent event = { .u = {
{ .property = {
xEvent event = { .u = { .window = request.window,
.property = { .atom = request.property,
.window = request.window, .time = static_cast<CARD32>(time(nullptr)),
.atom = request.property, .state = PropertyNewValue,
.time = static_cast<CARD32>(time(nullptr)), }
.state = PropertyNewValue, }};
} event.u.u.type = PropertyNotify;
}}; TRY(window.send_event(event, PropertyChangeMask));
event.u.u.type = PropertyNotify;
event.u.u.sequenceNumber = client_info.sequence;
TRY(encode(client_info.output_buffer, event));
}
break; break;
} }
@ -2052,20 +2017,16 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
window.properties.remove(it); window.properties.remove(it);
if (window.event_mask & PropertyChangeMask) xEvent event = { .u = {
{ .property = {
xEvent event = { .u = { .window = request.window,
.property = { .atom = request.property,
.window = request.window, .time = static_cast<CARD32>(time(nullptr)),
.atom = request.property, .state = PropertyDelete,
.time = static_cast<CARD32>(time(nullptr)), }
.state = PropertyDelete, }};
} event.u.u.type = PropertyNotify;
}}; TRY(window.send_event(event, PropertyChangeMask));
event.u.u.type = PropertyNotify;
event.u.u.sequenceNumber = client_info.sequence;
TRY(encode(client_info.output_buffer, event));
}
break; break;
} }
@ -2138,20 +2099,16 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
{ {
window.properties.remove(it); window.properties.remove(it);
if (window.event_mask & PropertyChangeMask) xEvent event = { .u = {
{ .property = {
xEvent event = { .u = { .window = request.window,
.property = { .atom = request.property,
.window = request.window, .time = static_cast<CARD32>(time(nullptr)),
.atom = request.property, .state = PropertyDelete,
.time = static_cast<CARD32>(time(nullptr)), }
.state = PropertyDelete, }};
} event.u.u.type = PropertyNotify;
}}; TRY(window.send_event(event, PropertyChangeMask));
event.u.u.type = PropertyNotify;
event.u.u.sequenceNumber = client_info.sequence;
TRY(encode(client_info.output_buffer, event));
}
} }
} }

View File

@ -68,7 +68,6 @@ struct Object
int32_t y { 0 }; int32_t y { 0 };
int32_t cursor_x { -1 }; int32_t cursor_x { -1 };
int32_t cursor_y { -1 }; int32_t cursor_y { -1 };
uint32_t event_mask { 0 };
WINDOW parent; WINDOW parent;
CURSOR cursor; CURSOR cursor;
CARD16 c_class; CARD16 c_class;
@ -78,6 +77,8 @@ struct Object
LibGUI::Texture LibGUI::Texture
> window; > window;
BAN::HashMap<Client*, uint32_t> event_masks;
BAN::HashMap<ATOM, Property> properties; BAN::HashMap<ATOM, Property> properties;
LibGUI::Texture& texture() LibGUI::Texture& texture()
@ -97,6 +98,9 @@ struct Object
return window.get<BAN::UniqPtr<LibGUI::Window>>()->texture(); return window.get<BAN::UniqPtr<LibGUI::Window>>()->texture();
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
} }
uint32_t full_event_mask() const;
BAN::ErrorOr<void> send_event(xEvent event, uint32_t event_mask);
}; };
struct Pixmap struct Pixmap

View File

@ -277,6 +277,16 @@ int main()
dprintln("client {} disconnected", client_fd); dprintln("client {} disconnected", client_fd);
// FIXME: store selected events on client so we dont
// have to loop over all objects
for (auto& [_, object] : g_objects)
{
if (object->type != Object::Type::Window)
continue;
auto& window = object->object.get<Object::Window>();
window.event_masks.remove(&client_info);
}
for (auto id : client_info.objects) for (auto id : client_info.objects)
{ {
auto it = g_objects.find(id); auto it = g_objects.find(id);
@ -332,7 +342,8 @@ int main()
MUST(BAN::UniqPtr<Object>::create(Object { MUST(BAN::UniqPtr<Object>::create(Object {
.type = Object::Type::Window, .type = Object::Type::Window,
.object = Object::Window { .object = Object::Window {
.event_mask = 0, .mapped = true,
.parent = None,
.c_class = InputOutput, .c_class = InputOutput,
.window = {}, .window = {},
} }