mirror of
https://github.com/zebrajr/ladybird.git
synced 2025-12-06 00:19:53 +01:00
UI/AppKit: Implement opening child web views from e.g. window.open
This has been implemented in Qt for quite some time. This patch adds the same feature to AppKit. This is needed to run many WPT subtests with the AppKit chrome. This is also needed to handle window.open, target=_blank link clicks, etc.
This commit is contained in:
parent
e6965b11e4
commit
27776c8854
|
|
@ -13,6 +13,7 @@
|
|||
#include <LibWeb/CSS/PreferredContrast.h>
|
||||
#include <LibWeb/CSS/PreferredMotion.h>
|
||||
#include <LibWeb/HTML/ActivateTab.h>
|
||||
#include <LibWebView/Forward.h>
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
|
|
@ -32,6 +33,11 @@
|
|||
fromTab:(nullable Tab*)tab
|
||||
activateTab:(Web::HTML::ActivateTab)activate_tab;
|
||||
|
||||
- (nonnull TabController*)createChildTab:(Optional<URL::URL> const&)url
|
||||
fromTab:(nonnull Tab*)tab
|
||||
activateTab:(Web::HTML::ActivateTab)activate_tab
|
||||
pageIndex:(u64)page_index;
|
||||
|
||||
- (void)setActiveTab:(nonnull Tab*)tab;
|
||||
- (nullable Tab*)activeTab;
|
||||
|
||||
|
|
|
|||
|
|
@ -116,6 +116,20 @@
|
|||
return controller;
|
||||
}
|
||||
|
||||
- (nonnull TabController*)createChildTab:(Optional<URL::URL> const&)url
|
||||
fromTab:(nonnull Tab*)tab
|
||||
activateTab:(Web::HTML::ActivateTab)activate_tab
|
||||
pageIndex:(u64)page_index
|
||||
{
|
||||
auto* controller = [self createChildTab:activate_tab fromTab:tab pageIndex:page_index];
|
||||
|
||||
if (url.has_value()) {
|
||||
[controller loadURL:*url];
|
||||
}
|
||||
|
||||
return controller;
|
||||
}
|
||||
|
||||
- (void)setActiveTab:(Tab*)tab
|
||||
{
|
||||
self.active_tab = tab;
|
||||
|
|
@ -175,6 +189,29 @@
|
|||
fromTab:(nullable Tab*)tab
|
||||
{
|
||||
auto* controller = [[TabController alloc] init];
|
||||
[self initializeTabController:controller
|
||||
activateTab:activate_tab
|
||||
fromTab:tab];
|
||||
|
||||
return controller;
|
||||
}
|
||||
|
||||
- (nonnull TabController*)createChildTab:(Web::HTML::ActivateTab)activate_tab
|
||||
fromTab:(nonnull Tab*)tab
|
||||
pageIndex:(u64)page_index
|
||||
{
|
||||
auto* controller = [[TabController alloc] initAsChild:tab pageIndex:page_index];
|
||||
[self initializeTabController:controller
|
||||
activateTab:activate_tab
|
||||
fromTab:tab];
|
||||
|
||||
return controller;
|
||||
}
|
||||
|
||||
- (void)initializeTabController:(TabController*)controller
|
||||
activateTab:(Web::HTML::ActivateTab)activate_tab
|
||||
fromTab:(nullable Tab*)tab
|
||||
{
|
||||
[controller showWindow:nil];
|
||||
|
||||
if (tab) {
|
||||
|
|
@ -192,7 +229,6 @@
|
|||
|
||||
[self.managed_tabs addObject:controller];
|
||||
[controller onCreateNewTab];
|
||||
return controller;
|
||||
}
|
||||
|
||||
- (void)closeCurrentTab:(id)sender
|
||||
|
|
|
|||
|
|
@ -27,6 +27,10 @@
|
|||
url:(URL::URL const&)url
|
||||
activateTab:(Web::HTML::ActivateTab)activate_tab;
|
||||
|
||||
- (String const&)onCreateChildTab:(Optional<URL::URL> const&)url
|
||||
activateTab:(Web::HTML::ActivateTab)activate_tab
|
||||
pageIndex:(u64)page_index;
|
||||
|
||||
- (void)loadURL:(URL::URL const&)url;
|
||||
- (void)onLoadStart:(URL::URL const&)url isRedirect:(BOOL)is_redirect;
|
||||
- (void)onLoadFinish:(URL::URL const&)url;
|
||||
|
|
@ -47,6 +51,9 @@
|
|||
@interface LadybirdWebView : NSClipView <NSMenuDelegate>
|
||||
|
||||
- (instancetype)init:(id<LadybirdWebViewObserver>)observer;
|
||||
- (instancetype)initAsChild:(id<LadybirdWebViewObserver>)observer
|
||||
parent:(LadybirdWebView*)parent
|
||||
pageIndex:(u64)page_index;
|
||||
|
||||
- (void)loadURL:(URL::URL const&)url;
|
||||
- (void)loadHTML:(StringView)html;
|
||||
|
|
|
|||
|
|
@ -88,6 +88,26 @@ struct HideCursor {
|
|||
@synthesize status_label = _status_label;
|
||||
|
||||
- (instancetype)init:(id<LadybirdWebViewObserver>)observer
|
||||
{
|
||||
if (self = [self initWebView:observer]) {
|
||||
m_web_view_bridge->initialize_client();
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initAsChild:(id<LadybirdWebViewObserver>)observer
|
||||
parent:(LadybirdWebView*)parent
|
||||
pageIndex:(u64)page_index
|
||||
{
|
||||
if (self = [self initWebView:observer]) {
|
||||
m_web_view_bridge->initialize_client_as_child(*parent->m_web_view_bridge, page_index);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWebView:(id<LadybirdWebViewObserver>)observer
|
||||
{
|
||||
if (self = [super init]) {
|
||||
self.observer = observer;
|
||||
|
|
@ -109,8 +129,6 @@ struct HideCursor {
|
|||
m_web_view_bridge = MUST(Ladybird::WebViewBridge::create(move(screen_rects), device_pixel_ratio, [delegate preferredColorScheme], [delegate preferredContrast], [delegate preferredMotion]));
|
||||
[self setWebViewCallbacks];
|
||||
|
||||
m_web_view_bridge->initialize_client();
|
||||
|
||||
auto* area = [[NSTrackingArea alloc] initWithRect:[self bounds]
|
||||
options:NSTrackingActiveInKeyWindow | NSTrackingInVisibleRect | NSTrackingMouseMoved
|
||||
owner:self
|
||||
|
|
@ -317,12 +335,18 @@ static void copy_data_to_clipboard(StringView data, NSPasteboardType pasteboard_
|
|||
[self setNeedsDisplay:YES];
|
||||
};
|
||||
|
||||
m_web_view_bridge->on_new_web_view = [weak_self](auto activate_tab, auto, auto) {
|
||||
m_web_view_bridge->on_new_web_view = [weak_self](auto activate_tab, auto, auto page_index) {
|
||||
LadybirdWebView* self = weak_self;
|
||||
if (self == nil) {
|
||||
return String {};
|
||||
}
|
||||
// FIXME: Create a child tab that re-uses the ConnectionFromClient of the parent tab
|
||||
|
||||
if (page_index.has_value()) {
|
||||
return [self.observer onCreateChildTab:{}
|
||||
activateTab:activate_tab
|
||||
pageIndex:*page_index];
|
||||
}
|
||||
|
||||
return [self.observer onCreateNewTab:{} activateTab:activate_tab];
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -147,15 +147,17 @@ Gfx::IntPoint WebViewBridge::to_widget_position(Gfx::IntPoint content_position)
|
|||
return scale_for_device(content_position, inverse_device_pixel_ratio());
|
||||
}
|
||||
|
||||
void WebViewBridge::initialize_client(CreateNewClient)
|
||||
void WebViewBridge::initialize_client(CreateNewClient create_new_client)
|
||||
{
|
||||
VERIFY(on_request_web_content);
|
||||
|
||||
// FIXME: Don't create a new process when CreateNewClient is false
|
||||
// We should create a new tab/window in the UI instead, and re-use the existing WebContentClient object.
|
||||
m_client_state = {};
|
||||
if (create_new_client == CreateNewClient::Yes) {
|
||||
m_client_state = {};
|
||||
m_client_state.client = on_request_web_content();
|
||||
} else {
|
||||
m_client_state.client->register_view(m_client_state.page_index, *this);
|
||||
}
|
||||
|
||||
m_client_state.client = on_request_web_content();
|
||||
m_client_state.client->on_web_content_process_crash = [this] {
|
||||
Core::deferred_invoke([this] {
|
||||
handle_web_content_process_crash();
|
||||
|
|
@ -184,4 +186,12 @@ void WebViewBridge::initialize_client(CreateNewClient)
|
|||
}
|
||||
}
|
||||
|
||||
void WebViewBridge::initialize_client_as_child(WebViewBridge const& parent, u64 page_index)
|
||||
{
|
||||
m_client_state.client = parent.client();
|
||||
m_client_state.page_index = page_index;
|
||||
|
||||
initialize_client(CreateNewClient::No);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ public:
|
|||
virtual ~WebViewBridge() override;
|
||||
|
||||
virtual void initialize_client(CreateNewClient = CreateNewClient::Yes) override;
|
||||
void initialize_client_as_child(WebViewBridge const& parent, u64 page_index);
|
||||
|
||||
float device_pixel_ratio() const { return m_device_pixel_ratio; }
|
||||
void set_device_pixel_ratio(float device_pixel_ratio);
|
||||
|
|
|
|||
|
|
@ -6,12 +6,18 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Types.h>
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@class LadybirdWebView;
|
||||
|
||||
@interface Tab : NSWindow
|
||||
|
||||
- (instancetype)init;
|
||||
- (instancetype)initAsChild:(Tab*)parent
|
||||
pageIndex:(u64)page_index;
|
||||
|
||||
- (void)tabWillClose;
|
||||
|
||||
- (void)openInspector:(id)sender;
|
||||
|
|
|
|||
|
|
@ -60,6 +60,19 @@ static constexpr CGFloat const WINDOW_HEIGHT = 800;
|
|||
}
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
auto* web_view = [[LadybirdWebView alloc] init:self];
|
||||
return [self initWithWebView:web_view];
|
||||
}
|
||||
|
||||
- (instancetype)initAsChild:(Tab*)parent
|
||||
pageIndex:(u64)page_index
|
||||
{
|
||||
auto* web_view = [[LadybirdWebView alloc] initAsChild:self parent:[parent web_view] pageIndex:page_index];
|
||||
return [self initWithWebView:web_view];
|
||||
}
|
||||
|
||||
- (instancetype)initWithWebView:(LadybirdWebView*)web_view
|
||||
{
|
||||
auto screen_rect = [[NSScreen mainScreen] frame];
|
||||
auto position_x = (NSWidth(screen_rect) - WINDOW_WIDTH) / 2;
|
||||
|
|
@ -77,7 +90,7 @@ static constexpr CGFloat const WINDOW_HEIGHT = 800;
|
|||
// Remember last window position
|
||||
self.frameAutosaveName = @"window";
|
||||
|
||||
self.web_view = [[LadybirdWebView alloc] init:self];
|
||||
self.web_view = web_view;
|
||||
[self.web_view setPostsBoundsChangedNotifications:YES];
|
||||
|
||||
self.favicon = [Tab defaultFavicon];
|
||||
|
|
@ -296,6 +309,21 @@ static constexpr CGFloat const WINDOW_HEIGHT = 800;
|
|||
return [[tab web_view] handle];
|
||||
}
|
||||
|
||||
- (String const&)onCreateChildTab:(Optional<URL::URL> const&)url
|
||||
activateTab:(Web::HTML::ActivateTab)activate_tab
|
||||
pageIndex:(u64)page_index
|
||||
{
|
||||
auto* delegate = (ApplicationDelegate*)[NSApp delegate];
|
||||
|
||||
auto* controller = [delegate createChildTab:url
|
||||
fromTab:self
|
||||
activateTab:activate_tab
|
||||
pageIndex:page_index];
|
||||
|
||||
auto* tab = (Tab*)[controller window];
|
||||
return [[tab web_view] handle];
|
||||
}
|
||||
|
||||
- (void)loadURL:(URL::URL const&)url
|
||||
{
|
||||
[[self tabController] loadURL:url];
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@
|
|||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@class Tab;
|
||||
|
||||
struct TabSettings {
|
||||
BOOL should_show_line_box_borders { NO };
|
||||
BOOL scripting_enabled { YES };
|
||||
|
|
@ -23,6 +25,8 @@ struct TabSettings {
|
|||
@interface TabController : NSWindowController <NSWindowDelegate>
|
||||
|
||||
- (instancetype)init;
|
||||
- (instancetype)initAsChild:(Tab*)parent
|
||||
pageIndex:(u64)page_index;
|
||||
|
||||
- (void)loadURL:(URL::URL const&)url;
|
||||
- (void)loadHTML:(StringView)html url:(URL::URL const&)url;
|
||||
|
|
|
|||
|
|
@ -49,6 +49,8 @@ static NSString* const TOOLBAR_TAB_OVERVIEW_IDENTIFIER = @"ToolbarTabOverviewIde
|
|||
|
||||
@interface TabController () <NSToolbarDelegate, NSSearchFieldDelegate>
|
||||
{
|
||||
u64 m_page_index;
|
||||
|
||||
ByteString m_title;
|
||||
|
||||
TabSettings m_settings;
|
||||
|
|
@ -57,6 +59,8 @@ static NSString* const TOOLBAR_TAB_OVERVIEW_IDENTIFIER = @"ToolbarTabOverviewIde
|
|||
bool m_can_navigate_forward;
|
||||
}
|
||||
|
||||
@property (nonatomic, strong) Tab* parent;
|
||||
|
||||
@property (nonatomic, strong) NSToolbar* toolbar;
|
||||
@property (nonatomic, strong) NSArray* toolbar_identifiers;
|
||||
|
||||
|
|
@ -92,6 +96,8 @@ static NSString* const TOOLBAR_TAB_OVERVIEW_IDENTIFIER = @"ToolbarTabOverviewIde
|
|||
[self.toolbar setAllowsUserCustomization:NO];
|
||||
[self.toolbar setSizeMode:NSToolbarSizeModeRegular];
|
||||
|
||||
m_page_index = 0;
|
||||
|
||||
m_settings = {
|
||||
.scripting_enabled = WebView::Application::chrome_options().disable_scripting == WebView::DisableScripting::Yes ? NO : YES,
|
||||
.block_popups = WebView::Application::chrome_options().allow_popups == WebView::AllowPopups::Yes ? NO : YES,
|
||||
|
|
@ -107,6 +113,17 @@ static NSString* const TOOLBAR_TAB_OVERVIEW_IDENTIFIER = @"ToolbarTabOverviewIde
|
|||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initAsChild:(Tab*)parent
|
||||
pageIndex:(u64)page_index
|
||||
{
|
||||
if (self = [self init]) {
|
||||
self.parent = parent;
|
||||
m_page_index = page_index;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - Public methods
|
||||
|
||||
- (void)loadURL:(URL::URL const&)url
|
||||
|
|
@ -544,7 +561,10 @@ static NSString* const TOOLBAR_TAB_OVERVIEW_IDENTIFIER = @"ToolbarTabOverviewIde
|
|||
|
||||
- (IBAction)showWindow:(id)sender
|
||||
{
|
||||
self.window = [[Tab alloc] init];
|
||||
self.window = self.parent
|
||||
? [[Tab alloc] initAsChild:self.parent pageIndex:m_page_index]
|
||||
: [[Tab alloc] init];
|
||||
|
||||
[self.window setDelegate:self];
|
||||
|
||||
[self.window setToolbar:self.toolbar];
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user