mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-07-28 19:59:17 +00:00
UI/AppKit: Process drag-and-drop events through the web view
This forwards all drag-and-drop events from the UI to the WebContent process. If the page accepts the events, the UI does not handle them. Otherwise, we will open the dropped files as file:// URLs.
This commit is contained in:
parent
948b6de3b1
commit
ac062d0c97
Notes:
github-actions[bot]
2024-08-19 11:30:14 +00:00
Author: https://github.com/trflynn89
Commit: ac062d0c97
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/1111
5 changed files with 138 additions and 3 deletions
|
@ -1,11 +1,13 @@
|
|||
/*
|
||||
* Copyright (c) 2023, Tim Flynn <trflynn89@serenityos.org>
|
||||
* Copyright (c) 2023-2024, Tim Flynn <trflynn89@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Vector.h>
|
||||
#include <LibURL/Forward.h>
|
||||
#include <LibWeb/Page/InputEvent.h>
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
@ -13,6 +15,10 @@
|
|||
namespace Ladybird {
|
||||
|
||||
Web::MouseEvent ns_event_to_mouse_event(Web::MouseEvent::Type, NSEvent*, NSView*, NSScrollView*, Web::UIEvents::MouseButton);
|
||||
|
||||
Web::DragEvent ns_event_to_drag_event(Web::DragEvent::Type, id<NSDraggingInfo>, NSView*);
|
||||
Vector<URL::URL> drag_event_url_list(Web::DragEvent const&);
|
||||
|
||||
Web::KeyEvent ns_event_to_key_event(Web::KeyEvent::Type, NSEvent*);
|
||||
NSEvent* key_event_to_ns_event(Web::KeyEvent const&);
|
||||
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
/*
|
||||
* Copyright (c) 2023, Tim Flynn <trflynn89@serenityos.org>
|
||||
* Copyright (c) 2023-2024, Tim Flynn <trflynn89@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/TypeCasts.h>
|
||||
#include <AK/Utf8View.h>
|
||||
#include <LibURL/URL.h>
|
||||
#include <LibWeb/HTML/SelectedFile.h>
|
||||
#include <LibWeb/UIEvents/KeyCode.h>
|
||||
|
||||
#import <Carbon/Carbon.h>
|
||||
#import <UI/Event.h>
|
||||
|
@ -70,6 +73,66 @@ Web::MouseEvent ns_event_to_mouse_event(Web::MouseEvent::Type type, NSEvent* eve
|
|||
return { type, device_position, device_screen_position, button, button, modifiers, wheel_delta_x, wheel_delta_y, nullptr };
|
||||
}
|
||||
|
||||
struct DragData : public Web::ChromeInputData {
|
||||
explicit DragData(Vector<URL::URL> urls)
|
||||
: urls(move(urls))
|
||||
{
|
||||
}
|
||||
|
||||
Vector<URL::URL> urls;
|
||||
};
|
||||
|
||||
Web::DragEvent ns_event_to_drag_event(Web::DragEvent::Type type, id<NSDraggingInfo> event, NSView* view)
|
||||
{
|
||||
auto position = [view convertPoint:event.draggingLocation fromView:nil];
|
||||
auto device_position = ns_point_to_gfx_point(position).to_type<Web::DevicePixels>();
|
||||
|
||||
auto screen_position = [NSEvent mouseLocation];
|
||||
auto device_screen_position = ns_point_to_gfx_point(screen_position).to_type<Web::DevicePixels>();
|
||||
|
||||
auto button = Web::UIEvents::MouseButton::Primary;
|
||||
auto modifiers = ns_modifiers_to_key_modifiers([NSEvent modifierFlags], button);
|
||||
|
||||
Vector<Web::HTML::SelectedFile> files;
|
||||
OwnPtr<DragData> chrome_data;
|
||||
|
||||
auto for_each_file = [&](auto callback) {
|
||||
NSArray* file_list = [[event draggingPasteboard] readObjectsForClasses:@[ [NSURL class] ]
|
||||
options:nil];
|
||||
|
||||
for (NSURL* file in file_list) {
|
||||
auto file_path = Ladybird::ns_string_to_byte_string([file path]);
|
||||
callback(file_path);
|
||||
}
|
||||
};
|
||||
|
||||
if (type == Web::DragEvent::Type::DragStart) {
|
||||
for_each_file([&](ByteString const& file_path) {
|
||||
if (auto file = Web::HTML::SelectedFile::from_file_path(file_path); file.is_error())
|
||||
warnln("Unable to open file {}: {}", file_path, file.error());
|
||||
else
|
||||
files.append(file.release_value());
|
||||
});
|
||||
} else if (type == Web::DragEvent::Type::Drop) {
|
||||
Vector<URL::URL> urls;
|
||||
|
||||
for_each_file([&](ByteString const& file_path) {
|
||||
if (auto url = URL::create_with_url_or_path(file_path); url.is_valid())
|
||||
urls.append(move(url));
|
||||
});
|
||||
|
||||
chrome_data = make<DragData>(move(urls));
|
||||
}
|
||||
|
||||
return { type, device_position, device_screen_position, button, button, modifiers, move(files), move(chrome_data) };
|
||||
}
|
||||
|
||||
Vector<URL::URL> drag_event_url_list(Web::DragEvent const& event)
|
||||
{
|
||||
auto& chrome_data = verify_cast<DragData>(*event.chrome_data);
|
||||
return move(chrome_data.urls);
|
||||
}
|
||||
|
||||
NSEvent* create_context_menu_mouse_event(NSView* view, Gfx::IntPoint position)
|
||||
{
|
||||
return create_context_menu_mouse_event(view, gfx_point_to_ns_point(position));
|
||||
|
|
|
@ -48,7 +48,7 @@ struct HideCursor {
|
|||
}
|
||||
};
|
||||
|
||||
@interface LadybirdWebView ()
|
||||
@interface LadybirdWebView () <NSDraggingDestination>
|
||||
{
|
||||
OwnPtr<Ladybird::WebViewBridge> m_web_view_bridge;
|
||||
|
||||
|
@ -114,6 +114,8 @@ struct HideCursor {
|
|||
owner:self
|
||||
userInfo:nil];
|
||||
[self addTrackingArea:area];
|
||||
|
||||
[self registerForDraggedTypes:[NSArray arrayWithObjects:NSPasteboardTypeFileURL, nil]];
|
||||
}
|
||||
|
||||
return self;
|
||||
|
@ -417,6 +419,25 @@ static void copy_data_to_clipboard(StringView data, NSPasteboardType pasteboard_
|
|||
self.event_being_redispatched = nil;
|
||||
};
|
||||
|
||||
m_web_view_bridge->on_finish_handling_drag_event = [weak_self](auto const& event) {
|
||||
LadybirdWebView* self = weak_self;
|
||||
if (self == nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.type != Web::DragEvent::Type::Drop) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (auto urls = Ladybird::drag_event_url_list(event); !urls.is_empty()) {
|
||||
[self.observer loadURL:urls[0]];
|
||||
|
||||
for (size_t i = 1; i < urls.size(); ++i) {
|
||||
[self.observer onCreateNewTab:urls[i] activateTab:Web::HTML::ActivateTab::No];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
m_web_view_bridge->on_cursor_change = [weak_self](auto cursor) {
|
||||
LadybirdWebView* self = weak_self;
|
||||
if (self == nil) {
|
||||
|
@ -1669,4 +1690,41 @@ static void copy_data_to_clipboard(StringView data, NSPasteboardType pasteboard_
|
|||
m_web_view_bridge->enqueue_input_event(move(key_event));
|
||||
}
|
||||
|
||||
#pragma mark - NSDraggingDestination
|
||||
|
||||
- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)event
|
||||
{
|
||||
auto drag_event = Ladybird::ns_event_to_drag_event(Web::DragEvent::Type::DragStart, event, self);
|
||||
m_web_view_bridge->enqueue_input_event(move(drag_event));
|
||||
|
||||
return NSDragOperationCopy;
|
||||
}
|
||||
|
||||
- (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)event
|
||||
{
|
||||
auto drag_event = Ladybird::ns_event_to_drag_event(Web::DragEvent::Type::DragMove, event, self);
|
||||
m_web_view_bridge->enqueue_input_event(move(drag_event));
|
||||
|
||||
return NSDragOperationCopy;
|
||||
}
|
||||
|
||||
- (void)draggingExited:(id<NSDraggingInfo>)event
|
||||
{
|
||||
auto drag_event = Ladybird::ns_event_to_drag_event(Web::DragEvent::Type::DragEnd, event, self);
|
||||
m_web_view_bridge->enqueue_input_event(move(drag_event));
|
||||
}
|
||||
|
||||
- (BOOL)performDragOperation:(id<NSDraggingInfo>)event
|
||||
{
|
||||
auto drag_event = Ladybird::ns_event_to_drag_event(Web::DragEvent::Type::Drop, event, self);
|
||||
m_web_view_bridge->enqueue_input_event(move(drag_event));
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)wantsPeriodicDraggingUpdates
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -93,6 +93,13 @@ void WebViewBridge::enqueue_input_event(Web::MouseEvent event)
|
|||
ViewImplementation::enqueue_input_event(move(event));
|
||||
}
|
||||
|
||||
void WebViewBridge::enqueue_input_event(Web::DragEvent event)
|
||||
{
|
||||
event.position = to_content_position(event.position.to_type<int>()).to_type<Web::DevicePixels>();
|
||||
event.screen_position = to_content_position(event.screen_position.to_type<int>()).to_type<Web::DevicePixels>();
|
||||
ViewImplementation::enqueue_input_event(move(event));
|
||||
}
|
||||
|
||||
void WebViewBridge::enqueue_input_event(Web::KeyEvent event)
|
||||
{
|
||||
ViewImplementation::enqueue_input_event(move(event));
|
||||
|
|
|
@ -44,6 +44,7 @@ public:
|
|||
void set_preferred_motion(Web::CSS::PreferredMotion);
|
||||
|
||||
void enqueue_input_event(Web::MouseEvent);
|
||||
void enqueue_input_event(Web::DragEvent);
|
||||
void enqueue_input_event(Web::KeyEvent);
|
||||
|
||||
struct Paintable {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue