LibWeb: Automatically disconnect all testing gamepads on test completion
Connected gamepads are stored on the Navigator, which means that when we navigate to a new test, they stick around, including the virtual ones we create for testing purposes. This caused issues such as the one fixed in #7329 where failing to manually disconnect a virtual gamepad meant that it would interfere with subsequent tests. We don't want to rely on tests cleaning things up correctly, so this commit introduces an automatic clean-up of these virtual gamepads. InternalGamepad objects are now tracked in Internals, and all disconnected in `Internals::perform_per_test_cleanup()`. It's named generically as I'm expecting other systems (eg, localStorage or cookies) to want similar cleanup between tests, but implementing those is left as an exercise for a future person. This method is called from signal_test_is_done(). This method is always called in the case where the test completes. A test that crashes means the WebContent isn't reused. A test that times out should also not have its WebContent process reused, though it's not clear to me what we currently do there. Verified by commenting-out the `gamepad.disconnect()` line from the Text/input/GamepadAPI/gamepad-is-available-in-new-navigables.html test and then running: ```bash for run in {1..20}; do Meta/ladybird.py run test-web -s -j1 -f GamepadAPI; done ```
This commit is contained in:
parent
f2dd3d89d1
commit
5510867d58
4 changed files with 37 additions and 3 deletions
|
|
@ -7,6 +7,7 @@
|
|||
#include <LibWeb/Bindings/InternalGamepadPrototype.h>
|
||||
#include <LibWeb/Bindings/Intrinsics.h>
|
||||
#include <LibWeb/Internals/InternalGamepad.h>
|
||||
#include <LibWeb/Internals/Internals.h>
|
||||
|
||||
#include <SDL3/SDL_gamepad.h>
|
||||
#include <SDL3/SDL_joystick.h>
|
||||
|
|
@ -61,8 +62,9 @@ static SDLCALL bool rumble_triggers(void* user_data, u16 left_rumble, u16 right_
|
|||
return true;
|
||||
}
|
||||
|
||||
InternalGamepad::InternalGamepad(JS::Realm& realm)
|
||||
InternalGamepad::InternalGamepad(JS::Realm& realm, GC::Ref<Internals> internals)
|
||||
: Bindings::PlatformObject(realm)
|
||||
, m_internals(internals)
|
||||
{
|
||||
SDL_VirtualJoystickDesc virtual_joystick_desc {};
|
||||
SDL_INIT_INTERFACE(&virtual_joystick_desc);
|
||||
|
|
@ -108,6 +110,7 @@ void InternalGamepad::visit_edges(Cell::Visitor& visitor)
|
|||
Base::visit_edges(visitor);
|
||||
visitor.visit(m_received_rumble_effects);
|
||||
visitor.visit(m_received_rumble_trigger_effects);
|
||||
visitor.visit(m_internals);
|
||||
}
|
||||
|
||||
void InternalGamepad::finalize()
|
||||
|
|
@ -174,6 +177,7 @@ void InternalGamepad::received_rumble_triggers(u16 left_rumble, u16 right_rumble
|
|||
|
||||
void InternalGamepad::disconnect()
|
||||
{
|
||||
m_internals->disconnect_virtual_gamepad(*this);
|
||||
SDL_CloseJoystick(m_sdl_joystick);
|
||||
SDL_DetachVirtualJoystick(m_sdl_joystick_id);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ public:
|
|||
void disconnect();
|
||||
|
||||
private:
|
||||
InternalGamepad(JS::Realm&);
|
||||
InternalGamepad(JS::Realm&, GC::Ref<Internals>);
|
||||
virtual void initialize(JS::Realm&) override;
|
||||
virtual void visit_edges(Cell::Visitor&) override;
|
||||
virtual void finalize() override;
|
||||
|
|
@ -47,6 +47,7 @@ private:
|
|||
SDL_Joystick* m_sdl_joystick;
|
||||
Vector<GC::Ref<JS::Object>> m_received_rumble_effects;
|
||||
Vector<GC::Ref<JS::Object>> m_received_rumble_trigger_effects;
|
||||
GC::Ref<Internals> m_internals;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,8 +49,15 @@ void Internals::initialize(JS::Realm& realm)
|
|||
Base::initialize(realm);
|
||||
}
|
||||
|
||||
void Internals::visit_edges(Visitor& visitor)
|
||||
{
|
||||
Base::visit_edges(visitor);
|
||||
visitor.visit(m_gamepads);
|
||||
}
|
||||
|
||||
void Internals::signal_test_is_done(String const& text)
|
||||
{
|
||||
perform_per_test_cleanup();
|
||||
page().client().page_did_finish_test(text);
|
||||
}
|
||||
|
||||
|
|
@ -407,7 +414,23 @@ void Internals::handle_sdl_input_events()
|
|||
GC::Ref<InternalGamepad> Internals::connect_virtual_gamepad()
|
||||
{
|
||||
auto& realm = this->realm();
|
||||
return realm.create<InternalGamepad>(realm);
|
||||
auto gamepad = realm.create<InternalGamepad>(realm, *this);
|
||||
m_gamepads.append(gamepad);
|
||||
return gamepad;
|
||||
}
|
||||
|
||||
void Internals::disconnect_virtual_gamepad(GC::Ref<InternalGamepad> gamepad)
|
||||
{
|
||||
if (auto index = m_gamepads.find_first_index(gamepad); index.has_value())
|
||||
m_gamepads.remove(index.value());
|
||||
}
|
||||
|
||||
void Internals::perform_per_test_cleanup()
|
||||
{
|
||||
// Detach any virtual gamepads
|
||||
for (auto gamepad : m_gamepads)
|
||||
gamepad->disconnect();
|
||||
m_gamepads.clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,14 +80,20 @@ public:
|
|||
void handle_sdl_input_events();
|
||||
|
||||
GC::Ref<InternalGamepad> connect_virtual_gamepad();
|
||||
void disconnect_virtual_gamepad(GC::Ref<InternalGamepad>);
|
||||
|
||||
void perform_per_test_cleanup();
|
||||
|
||||
private:
|
||||
explicit Internals(JS::Realm&);
|
||||
|
||||
virtual void initialize(JS::Realm&) override;
|
||||
virtual void visit_edges(Visitor&) override;
|
||||
|
||||
void click(double x, double y, UIEvents::MouseButton);
|
||||
void mouse_down(double x, double y, UIEvents::MouseButton);
|
||||
|
||||
Vector<GC::Ref<InternalGamepad>> m_gamepads;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue