LibWeb+UI+WebContent: Pipe pinch events from AppKit UI to WebContent

This commit is contained in:
Aliaksandr Kalenik 2025-10-08 23:59:50 +02:00 committed by Alexander Kalenik
parent e6831003c6
commit c630de17ab
Notes: github-actions[bot] 2025-10-10 13:39:44 +00:00
10 changed files with 86 additions and 1 deletions

View file

@ -290,6 +290,9 @@ void EventLoop::process_input_events() const
},
[&](Web::DragEvent& drag_event) {
return page.handle_drag_and_drop_event(drag_event.type, drag_event.position, drag_event.screen_position, drag_event.button, drag_event.buttons, drag_event.modifiers, move(drag_event.files));
},
[&](Web::PinchEvent&) {
return EventResult::Dropped;
});
for (size_t i = 0; i < event.coalesced_event_count; ++i)

View file

@ -105,3 +105,19 @@ ErrorOr<Web::DragEvent> IPC::decode(Decoder& decoder)
return Web::DragEvent { type, position, screen_position, button, buttons, modifiers, move(files), nullptr };
}
template<>
WEB_API ErrorOr<void> IPC::encode(Encoder& encoder, Web::PinchEvent const& event)
{
TRY(encoder.encode(event.position));
TRY(encoder.encode(event.scale_delta));
return {};
}
template<>
WEB_API ErrorOr<Web::PinchEvent> IPC::decode(Decoder& decoder)
{
auto position = TRY(decoder.decode<Web::DevicePixelPoint>());
auto scale_delta = TRY(decoder.decode<double>());
return Web::PinchEvent { position, scale_delta };
}

View file

@ -85,7 +85,12 @@ struct WEB_API DragEvent {
OwnPtr<BrowserInputData> browser_data;
};
using InputEvent = Variant<KeyEvent, MouseEvent, DragEvent>;
struct WEB_API PinchEvent {
Web::DevicePixelPoint position;
double scale_delta;
};
using InputEvent = Variant<KeyEvent, MouseEvent, DragEvent, PinchEvent>;
struct QueuedInputEvent {
u64 page_id { 0 };
@ -115,4 +120,10 @@ WEB_API ErrorOr<void> encode(Encoder&, Web::DragEvent const&);
template<>
WEB_API ErrorOr<Web::DragEvent> decode(Decoder&);
template<>
WEB_API ErrorOr<void> encode(Encoder&, Web::PinchEvent const&);
template<>
WEB_API ErrorOr<Web::PinchEvent> decode(Decoder&);
}

View file

@ -214,6 +214,9 @@ void ViewImplementation::enqueue_input_event(Web::InputEvent event)
cloned_event.files = move(event.files);
client().async_drag_event(m_client_state.page_index, cloned_event);
},
[this](Web::PinchEvent const& event) {
client().async_pinch_event(m_client_state.page_index, event);
});
}

View file

@ -245,6 +245,11 @@ void ConnectionFromClient::drag_event(u64 page_id, Web::DragEvent event)
enqueue_input_event({ page_id, move(event), 0 });
}
void ConnectionFromClient::pinch_event(u64 page_id, Web::PinchEvent event)
{
enqueue_input_event({ page_id, move(event), 0 });
}
void ConnectionFromClient::enqueue_input_event(Web::QueuedInputEvent event)
{
m_input_event_queue.enqueue(move(event));

View file

@ -75,6 +75,7 @@ private:
virtual void key_event(u64 page_id, Web::KeyEvent) override;
virtual void mouse_event(u64 page_id, Web::MouseEvent) override;
virtual void drag_event(u64 page_id, Web::DragEvent) override;
virtual void pinch_event(u64 page_id, Web::PinchEvent) override;
virtual void ready_to_paint(u64 page_id) override;
virtual void debug_request(u64 page_id, ByteString, ByteString) override;
virtual void get_source(u64 page_id) override;

View file

@ -44,6 +44,7 @@ endpoint WebContentServer
key_event(u64 page_id, Web::KeyEvent event) =|
mouse_event(u64 page_id, Web::MouseEvent event) =|
drag_event(u64 page_id, Web::DragEvent event) =|
pinch_event(u64 page_id, Web::PinchEvent event) =|
debug_request(u64 page_id, ByteString request, ByteString argument) =|
get_source(u64 page_id) =|

View file

@ -55,6 +55,7 @@ struct HideCursor {
@property (nonatomic, strong) NSMenu* select_dropdown;
@property (nonatomic, strong) NSTextField* status_label;
@property (nonatomic, strong) NSAlert* dialog;
@property (nonatomic, strong) NSMagnificationGestureRecognizer* pinch_recognizer;
// NSEvent does not provide a way to mark whether it has been handled, nor can we attach user data to the event. So
// when we dispatch the event for a second time after WebContent has had a chance to handle it, we must track that
@ -122,6 +123,10 @@ struct HideCursor {
[self registerForDraggedTypes:[NSArray arrayWithObjects:NSPasteboardTypeFileURL, nil]];
self.pinch_recognizer = [[NSMagnificationGestureRecognizer alloc] initWithTarget:self
action:@selector(onPinch:)];
[self addGestureRecognizer:self.pinch_recognizer];
m_modifier_flags = 0;
}
@ -1155,4 +1160,31 @@ struct HideCursor {
return NO;
}
- (void)onPinch:(NSMagnificationGestureRecognizer*)recognizer
{
double scale_delta = 0;
switch (recognizer.state) {
case NSGestureRecognizerStateBegan:
m_web_view_bridge->pinch_state() = { .previous_scale = recognizer.magnification };
break;
case NSGestureRecognizerStateChanged:
scale_delta = recognizer.magnification - m_web_view_bridge->pinch_state()->previous_scale;
m_web_view_bridge->pinch_state()->previous_scale = recognizer.magnification;
break;
case NSGestureRecognizerStateEnded:
case NSGestureRecognizerStateCancelled:
scale_delta = recognizer.magnification - m_web_view_bridge->pinch_state()->previous_scale;
m_web_view_bridge->pinch_state() = {};
break;
default:
return;
}
NSPoint point = [recognizer locationInView:self];
Web::PinchEvent pinch_event;
pinch_event.position = Ladybird::ns_point_to_gfx_point(point).to_type<Web::DevicePixels>() * m_web_view_bridge->device_pixel_ratio();
pinch_event.scale_delta = scale_delta;
m_web_view_bridge->enqueue_input_event(move(pinch_event));
}
@end

View file

@ -79,6 +79,11 @@ void WebViewBridge::enqueue_input_event(Web::KeyEvent event)
ViewImplementation::enqueue_input_event(move(event));
}
void WebViewBridge::enqueue_input_event(Web::PinchEvent event)
{
ViewImplementation::enqueue_input_event(move(event));
}
Optional<WebViewBridge::Paintable> WebViewBridge::paintable()
{
Gfx::Bitmap const* bitmap = nullptr;

View file

@ -36,6 +36,7 @@ public:
void enqueue_input_event(Web::MouseEvent);
void enqueue_input_event(Web::DragEvent);
void enqueue_input_event(Web::KeyEvent);
void enqueue_input_event(Web::PinchEvent);
struct Paintable {
Gfx::Bitmap const& bitmap;
@ -45,6 +46,8 @@ public:
Function<void()> on_zoom_level_changed;
auto& pinch_state() { return m_pinch_state; }
private:
WebViewBridge(Vector<Web::DevicePixelRect> screen_rects, float device_pixel_ratio, u64 maximum_frames_per_second);
@ -55,6 +58,11 @@ private:
Vector<Web::DevicePixelRect> m_screen_rects;
Gfx::IntSize m_viewport_size;
struct PinchState {
double previous_scale { 1.0 };
};
Optional<PinchState> m_pinch_state;
};
}