Only send key/mouse events to a single window

Firefox was getting mouse clicks as duplicates making every click a
double click
This commit is contained in:
Oskari Alaranta 2026-02-10 03:05:15 +02:00
parent 808e51b855
commit 4801fd3e67
1 changed files with 189 additions and 154 deletions

View File

@ -726,7 +726,7 @@ static BAN::ErrorOr<void> destroy_window(Client& client_info, WINDOW wid)
return {}; return {};
} }
static WINDOW find_child_window(WINDOW wid, int32_t x, int32_t y) static WINDOW find_child_window(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);
@ -754,58 +754,18 @@ static WINDOW find_child_window(WINDOW wid, int32_t x, int32_t y)
ASSERT(child_object.type == Object::Type::Window); ASSERT(child_object.type == Object::Type::Window);
auto& child_window = child_object.object.get<Object::Window>(); auto& child_window = child_object.object.get<Object::Window>();
if (auto result = find_child_window(child_wid, x - child_window.x, y - child_window.y); result != None)
x -= child_window.x;
y -= child_window.y;
if (auto result = find_child_window(child_wid, x, y); result != None)
return result; return result;
x += child_window.x;
y += child_window.y;
} }
return wid; return wid;
} }
static void send_mouse_move_events(Client& client_info, WINDOW wid, WINDOW event_child_wid, int32_t x, int32_t y)
{
auto& object = *g_objects[wid];
ASSERT(object.type == Object::Type::Window);
auto& window = object.object.get<Object::Window>();
window.cursor_x = x;
window.cursor_y = y;
for (auto child_wid : window.children)
{
auto& child_object = *g_objects[child_wid];
ASSERT(child_object.type == Object::Type::Window);
auto& child_window = object.object.get<Object::Window>();
send_mouse_move_events(client_info, child_wid, event_child_wid, x - child_window.x, y - child_window.y);
}
auto& texture = window.texture();
if (x < 0 || y < 0 || x >= texture.width() || y >= texture.height())
return;
if (!(window.event_mask & PointerMotionMask))
return;
xEvent xevent { .u = {
.keyButtonPointer = {
.time = static_cast<CARD32>(time(nullptr)),
.root = g_root.windowId,
.event = wid,
.child = event_child_wid,
.rootX = static_cast<INT16>(x),
.rootY = static_cast<INT16>(y),
.eventX = static_cast<INT16>(x),
.eventY = static_cast<INT16>(y),
.state = 0,
.sameScreen = xTrue,
}
}};
xevent.u.u.type = MotionNotify,
xevent.u.u.detail = NotifyNormal;
xevent.u.u.sequenceNumber = client_info.sequence;
MUST(encode(client_info.output_buffer, xevent));
}
static BAN::Vector<WINDOW> get_path_to_child(WINDOW wid, int32_t x, int32_t y) static BAN::Vector<WINDOW> get_path_to_child(WINDOW wid, int32_t x, int32_t y)
{ {
BAN::Vector<WINDOW> result; BAN::Vector<WINDOW> result;
@ -951,6 +911,92 @@ static void send_enter_and_leave_events(Client& client_info, WINDOW wid, int32_t
} }
} }
static void send_exposure_recursive(Client& client_info, WINDOW wid)
{
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)
send_exposure_recursive(client_info, child_wid);
window.texture().clear();
if (window.event_mask & ExposureMask)
{
xEvent event = { .u = {
.expose = {
.window = wid,
.x = 0,
.y = 0,
.width = static_cast<CARD16>(window.texture().width()),
.height = static_cast<CARD16>(window.texture().height()),
}
}};
event.u.u.type = Expose;
event.u.u.sequenceNumber = client_info.sequence;
MUST(encode(client_info.output_buffer, event));
}
}
static void on_window_resize_event(Client& client_info, WINDOW wid)
{
auto& object = *g_objects[wid];
ASSERT(object.type == Object::Type::Window);
auto& window = object.object.get<Object::Window>();
if (window.event_mask & StructureNotifyMask)
{
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.texture().width()),
.height = static_cast<CARD16>(window.texture().height()),
.borderWidth = 0,
.override = xFalse,
}
}};
event.u.u.type = ConfigureNotify;
event.u.u.sequenceNumber = client_info.sequence;
MUST(encode(client_info.output_buffer, event));
}
auto& parent_object = *g_objects[window.parent];
ASSERT(parent_object.type == Object::Type::Window);
auto& parent_window = parent_object.object.get<Object::Window>();
if (parent_window.event_mask & SubstructureNotifyMask)
{
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.texture().width()),
.height = static_cast<CARD16>(window.texture().height()),
.borderWidth = 0,
.override = xFalse,
}
}};
event.u.u.type = ConfigureNotify;
event.u.u.sequenceNumber = client_info.sequence;
MUST(encode(client_info.output_buffer, event));
}
send_exposure_recursive(client_info, wid);
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(Client& client_info, WINDOW wid, bool focused)
{ {
if (focused) if (focused)
@ -982,67 +1028,106 @@ static void on_window_focus_event(Client& client_info, WINDOW wid, bool focused)
MUST(encode(client_info.output_buffer, xevent)); MUST(encode(client_info.output_buffer, xevent));
} }
static void on_mouse_move_event(Client& client_info, WINDOW wid, int32_t x, int32_t y) static void send_key_button_pointer_event(Client& client_info, WINDOW wid, KeyButMask state, BYTE detail, uint32_t event_mask, BYTE event_type)
{
int32_t root_x, root_y;
int32_t event_x, event_y;
{ {
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>();
send_enter_and_leave_events(client_info, wid, window.cursor_x, window.cursor_y, x, y); root_x = event_x = window.cursor_x;
send_mouse_move_events(client_info, wid, find_child_window(wid, x, y), x, y); root_y = event_y = window.cursor_y;
} }
static void on_mouse_button_event(Client& client_info, WINDOW wid, uint8_t xbutton, bool pressed) const auto child_wid = find_child_window(wid, event_x, event_y);
wid = child_wid;
while (wid != None)
{ {
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)
break;
for (auto child_wid : window.children) event_x += window.x;
on_mouse_button_event(client_info, child_wid, xbutton, pressed); event_y += window.y;
wid = window.parent;
}
if (!(window.event_mask & (pressed ? ButtonPressMask : ButtonReleaseMask))) if (wid == None)
return; return;
const auto child_wid = find_child_window(wid, window.cursor_x, window.cursor_y);
xEvent xevent { .u = { xEvent xevent { .u = {
.keyButtonPointer = { .keyButtonPointer = {
.time = static_cast<CARD32>(time(nullptr)), .time = static_cast<CARD32>(time(nullptr)),
.root = g_root.windowId, .root = g_root.windowId,
.event = wid, .event = wid,
.child = child_wid, .child = child_wid,
.rootX = static_cast<INT16>(window.cursor_x), .rootX = static_cast<INT16>(root_x),
.rootY = static_cast<INT16>(window.cursor_y), .rootY = static_cast<INT16>(root_y),
.eventX = static_cast<INT16>(child_wid == None ? 0 : window.cursor_x), .eventX = static_cast<INT16>(event_x),
.eventY = static_cast<INT16>(child_wid == None ? 0 : window.cursor_y), .eventY = static_cast<INT16>(event_y),
.state = 0, .state = state,
.sameScreen = xTrue, .sameScreen = xTrue,
} }
}}; }};
xevent.u.u.type = pressed ? ButtonPress : ButtonRelease, xevent.u.u.type = event_type,
xevent.u.u.detail = xbutton; xevent.u.u.detail = detail;
xevent.u.u.sequenceNumber = client_info.sequence; xevent.u.u.sequenceNumber = client_info.sequence;
MUST(encode(client_info.output_buffer, xevent)); MUST(encode(client_info.output_buffer, xevent));
} }
static void update_cursor_position_recursive(WINDOW wid, int32_t new_x, int32_t new_y)
{
auto& object = *g_objects[wid];
ASSERT(object.type == Object::Type::Window);
auto& window = object.object.get<Object::Window>();
window.cursor_x = new_x;
window.cursor_y = new_y;
for (auto child_wid : window.children)
{
auto& child_object = *g_objects[child_wid];
ASSERT(child_object.type == Object::Type::Window);
auto& child_window = child_object.object.get<Object::Window>();
update_cursor_position_recursive(child_wid, new_x - child_window.x, new_y - child_window.y);
}
}
static void on_mouse_move_event(Client& client_info, WINDOW wid, int32_t x, int32_t y)
{
auto& object = *g_objects[wid];
ASSERT(object.type == Object::Type::Window);
auto& window = object.object.get<Object::Window>();
send_enter_and_leave_events(client_info, wid, window.cursor_x, window.cursor_y, x, y);
update_cursor_position_recursive(wid, x, y);
send_key_button_pointer_event(client_info, wid, 0, NotifyNormal, PointerMotionMask, MotionNotify);
}
static void on_mouse_button_event(Client& client_info, WINDOW wid, uint8_t xbutton, bool pressed)
{
send_key_button_pointer_event(
client_info,
wid,
0,
xbutton,
pressed ? ButtonPressMask : ButtonReleaseMask,
pressed ? ButtonPress : ButtonRelease
);
}
static void on_key_event(Client& client_info, WINDOW wid, LibGUI::EventPacket::KeyEvent::event_t event) static void on_key_event(Client& client_info, WINDOW wid, LibGUI::EventPacket::KeyEvent::event_t event)
{ {
if (g_keymap.map[static_cast<BYTE>(event.key)] == XK_VoidSymbol) if (g_keymap.map[static_cast<BYTE>(event.key)] == XK_VoidSymbol)
return; return;
auto& object = *g_objects[wid];
ASSERT(object.type == Object::Type::Window);
auto& window = object.object.get<Object::Window>();
for (auto child_wid : window.children)
on_key_event(client_info, child_wid, event);
if (!(window.event_mask & (event.pressed() ? KeyPressMask : KeyReleaseMask)))
return;
CARD8 xmodifier = 0; CARD8 xmodifier = 0;
if (event.shift()) if (event.shift())
xmodifier |= ShiftMask; xmodifier |= ShiftMask;
@ -1051,24 +1136,14 @@ static void on_key_event(Client& client_info, WINDOW wid, LibGUI::EventPacket::K
if (event.ctrl()) if (event.ctrl())
xmodifier |= ControlMask; xmodifier |= ControlMask;
xEvent xevent { .u = { send_key_button_pointer_event(
.keyButtonPointer = { client_info,
.time = static_cast<CARD32>(time(nullptr)), wid,
.root = g_root.windowId, xmodifier,
.event = wid, static_cast<BYTE>(event.key),
.child = find_child_window(wid, window.cursor_x, window.cursor_y), event.pressed() ? KeyPressMask : KeyReleaseMask,
.rootX = static_cast<INT16>(window.cursor_x), event.pressed() ? KeyPress : KeyRelease
.rootY = static_cast<INT16>(window.cursor_y), );
.eventX = static_cast<INT16>(window.cursor_x),
.eventY = static_cast<INT16>(window.cursor_y),
.state = xmodifier,
.sameScreen = xTrue,
}
}};
xevent.u.u.type = event.pressed() ? KeyPress : KeyRelease,
xevent.u.u.detail = static_cast<BYTE>(event.key);
xevent.u.u.sequenceNumber = client_info.sequence;
MUST(encode(client_info.output_buffer, xevent));
} }
BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet) BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
@ -1261,6 +1336,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
attributes.shown = false; attributes.shown = false;
attributes.title_bar = false; attributes.title_bar = false;
attributes.alpha_channel = true; attributes.alpha_channel = true;
attributes.resizable = true;
auto gui_window = TRY(LibGUI::Window::create(request.width, request.height, "window?"_sv, attributes)); auto gui_window = TRY(LibGUI::Window::create(request.width, request.height, "window?"_sv, attributes));
gui_window->texture().set_bg_color(background); gui_window->texture().set_bg_color(background);
@ -1304,55 +1380,7 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
const WINDOW wid = request.wid; const WINDOW wid = request.wid;
gui_window_ptr->set_close_window_event_callback([]{}); gui_window_ptr->set_close_window_event_callback([]{});
gui_window_ptr->set_resize_window_event_callback([&client_info, wid]() { gui_window_ptr->set_resize_window_event_callback([&client_info, wid]() {
auto& object = *g_objects[wid]; on_window_resize_event(client_info, wid);
ASSERT(object.type == Object::Type::Window);
auto& window = object.object.get<Object::Window>();
if (window.event_mask & StructureNotifyMask)
{
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.texture().width()),
.height = static_cast<CARD16>(window.texture().height()),
.borderWidth = 0,
.override = xFalse,
}
}};
event.u.u.type = ConfigureNotify;
event.u.u.sequenceNumber = client_info.sequence;
MUST(encode(client_info.output_buffer, event));
}
auto& parent_object = *g_objects[window.parent];
ASSERT(parent_object.type == Object::Type::Window);
auto& parent_window = parent_object.object.get<Object::Window>();
if (parent_window.event_mask & SubstructureNotifyMask)
{
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.texture().width()),
.height = static_cast<CARD16>(window.texture().height()),
.borderWidth = 0,
.override = xFalse,
}
}};
event.u.u.type = ConfigureNotify;
event.u.u.sequenceNumber = client_info.sequence;
MUST(encode(client_info.output_buffer, event));
}
invalidate_window(wid, 0, 0, window.texture().width(), window.texture().height());
}); });
gui_window_ptr->set_window_focus_event_callback([&client_info, wid](auto event) { gui_window_ptr->set_window_focus_event_callback([&client_info, wid](auto event) {
on_window_focus_event(client_info, wid, event.focused); on_window_focus_event(client_info, wid, event.focused);
@ -2210,17 +2238,24 @@ BAN::ErrorOr<void> handle_packet(Client& client_info, BAN::ConstByteSpan packet)
const auto& window = TRY_REF(get_window(wid)); const auto& window = TRY_REF(get_window(wid));
int32_t root_x, root_y;
int32_t event_x, event_y;
root_x = event_x = window.cursor_x;
root_y = event_y = window.cursor_y;
const auto child_wid = find_child_window(wid, event_x, event_y);
xQueryPointerReply reply { xQueryPointerReply reply {
.type = X_Reply, .type = X_Reply,
.sameScreen = xTrue, .sameScreen = xTrue,
.sequenceNumber = client_info.sequence, .sequenceNumber = client_info.sequence,
.length = 0, .length = 0,
.root = g_root.windowId, .root = g_root.windowId,
.child = find_child_window(wid, window.cursor_x, window.cursor_y), .child = static_cast<CARD32>(child_wid == wid ? None : child_wid),
.rootX = static_cast<INT16>(window.cursor_x), .rootX = static_cast<INT16>(root_x),
.rootY = static_cast<INT16>(window.cursor_y), .rootY = static_cast<INT16>(root_y),
.winX = static_cast<INT16>(window.cursor_x), .winX = static_cast<INT16>(event_x),
.winY = static_cast<INT16>(window.cursor_y), .winY = static_cast<INT16>(event_y),
.mask = 0, .mask = 0,
}; };
TRY(encode(client_info.output_buffer, reply)); TRY(encode(client_info.output_buffer, reply));