From f5981d86949dc74218c60d6e55aa61848653f48d Mon Sep 17 00:00:00 2001 From: Neil Viloria Date: Mon, 9 Sep 2024 23:52:49 -0600 Subject: [PATCH 1/3] AppKit: Refactor inspector methods into own class --- Ladybird/AppKit/CMakeLists.txt | 1 + Ladybird/AppKit/UI/Inspector.h | 2 +- Ladybird/AppKit/UI/Inspector.mm | 33 +---------- Ladybird/AppKit/UI/InspectorController.h | 4 +- Ladybird/AppKit/UI/InspectorController.mm | 15 +++-- Ladybird/AppKit/UI/InspectorWindow.h | 21 +++++++ Ladybird/AppKit/UI/InspectorWindow.mm | 67 +++++++++++++++++++++++ Ladybird/AppKit/UI/Tab.mm | 30 +++++++--- 8 files changed, 125 insertions(+), 48 deletions(-) create mode 100644 Ladybird/AppKit/UI/InspectorWindow.h create mode 100644 Ladybird/AppKit/UI/InspectorWindow.mm diff --git a/Ladybird/AppKit/CMakeLists.txt b/Ladybird/AppKit/CMakeLists.txt index 9fac78816443..0565c92c8375 100644 --- a/Ladybird/AppKit/CMakeLists.txt +++ b/Ladybird/AppKit/CMakeLists.txt @@ -6,6 +6,7 @@ add_library(ladybird_impl STATIC UI/Event.mm UI/Inspector.mm UI/InspectorController.mm + UI/InspectorWindow.mm UI/LadybirdWebView.mm UI/LadybirdWebViewBridge.cpp UI/Palette.mm diff --git a/Ladybird/AppKit/UI/Inspector.h b/Ladybird/AppKit/UI/Inspector.h index 391700ac2f36..6f0c1558abeb 100644 --- a/Ladybird/AppKit/UI/Inspector.h +++ b/Ladybird/AppKit/UI/Inspector.h @@ -11,7 +11,7 @@ @class LadybirdWebView; @class Tab; -@interface Inspector : NSWindow +@interface Inspector : NSScrollView - (instancetype)init:(Tab*)tab; diff --git a/Ladybird/AppKit/UI/Inspector.mm b/Ladybird/AppKit/UI/Inspector.mm index b7437625c67b..adb62ef9e582 100644 --- a/Ladybird/AppKit/UI/Inspector.mm +++ b/Ladybird/AppKit/UI/Inspector.mm @@ -19,9 +19,6 @@ # error "This project requires ARC" #endif -static constexpr CGFloat const WINDOW_WIDTH = 875; -static constexpr CGFloat const WINDOW_HEIGHT = 825; - static constexpr NSInteger CONTEXT_MENU_EDIT_NODE_TAG = 1; static constexpr NSInteger CONTEXT_MENU_REMOVE_ATTRIBUTE_TAG = 2; static constexpr NSInteger CONTEXT_MENU_COPY_ATTRIBUTE_VALUE_TAG = 3; @@ -51,17 +48,7 @@ @implementation Inspector - (instancetype)init:(Tab*)tab { - auto tab_rect = [tab frame]; - auto position_x = tab_rect.origin.x + (tab_rect.size.width - WINDOW_WIDTH) / 2; - auto position_y = tab_rect.origin.y + (tab_rect.size.height - WINDOW_HEIGHT) / 2; - - auto window_rect = NSMakeRect(position_x, position_y, WINDOW_WIDTH, WINDOW_HEIGHT); - auto style_mask = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable; - - self = [super initWithContentRect:window_rect - styleMask:style_mask - backing:NSBackingStoreBuffered - defer:NO]; + self = [super init]; if (self) { self.tab = tab; @@ -138,29 +125,11 @@ - (instancetype)init:(Tab*)tab auto* event = Ladybird::create_context_menu_mouse_event(strong_self.web_view, position); [NSMenu popUpContextMenu:strong_self.cookie_context_menu withEvent:event forView:strong_self.web_view]; }; - - auto* scroll_view = [[NSScrollView alloc] init]; - [scroll_view setHasVerticalScroller:YES]; - [scroll_view setHasHorizontalScroller:YES]; - [scroll_view setLineScroll:24]; - - [scroll_view setContentView:self.web_view]; - [scroll_view setDocumentView:[[NSView alloc] init]]; - - [self setContentView:scroll_view]; - [self setTitle:@"Inspector"]; - [self setIsVisible:YES]; } return self; } -- (void)dealloc -{ - auto& web_view = [[self.tab web_view] view]; - web_view.clear_inspected_dom_node(); -} - #pragma mark - Public methods - (void)inspect diff --git a/Ladybird/AppKit/UI/InspectorController.h b/Ladybird/AppKit/UI/InspectorController.h index ef35cf254e42..b5020656ad13 100644 --- a/Ladybird/AppKit/UI/InspectorController.h +++ b/Ladybird/AppKit/UI/InspectorController.h @@ -7,11 +7,13 @@ #pragma once #import +#import @class Tab; @interface InspectorController : NSWindowController -- (instancetype)init:(Tab*)tab; +- (instancetype)init:(Tab*)tab + inspector:(Inspector*)inspector; @end diff --git a/Ladybird/AppKit/UI/InspectorController.mm b/Ladybird/AppKit/UI/InspectorController.mm index 87c0ab98c458..7c8ab0defd26 100644 --- a/Ladybird/AppKit/UI/InspectorController.mm +++ b/Ladybird/AppKit/UI/InspectorController.mm @@ -4,8 +4,8 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#import #import +#import #import #import @@ -16,15 +16,18 @@ @interface InspectorController () @property (nonatomic, strong) Tab* tab; +@property (nonatomic, strong) Inspector* inspector; @end @implementation InspectorController - (instancetype)init:(Tab*)tab + inspector:(Inspector*)inspector { if (self = [super init]) { self.tab = tab; + self.inspector = inspector; } return self; @@ -32,16 +35,16 @@ - (instancetype)init:(Tab*)tab #pragma mark - Private methods -- (Inspector*)inspector +- (InspectorWindow*)inspectorWindow { - return (Inspector*)[self window]; + return (InspectorWindow*)[self window]; } #pragma mark - NSWindowController - (IBAction)showWindow:(id)sender { - self.window = [[Inspector alloc] init:self.tab]; + self.window = [[InspectorWindow alloc] init:self.tab inspector:self.inspector]; [self.window setDelegate:self]; [self.window makeKeyAndOrderFront:sender]; } @@ -56,13 +59,13 @@ - (void)windowWillClose:(NSNotification*)notification - (void)windowDidResize:(NSNotification*)notification { if (![[self window] inLiveResize]) { - [[[self inspector] web_view] handleResize]; + [[[self tab] web_view] handleResize]; } } - (void)windowDidChangeBackingProperties:(NSNotification*)notification { - [[[self inspector] web_view] handleDevicePixelRatioChange]; + [[[self tab] web_view] handleDevicePixelRatioChange]; } @end diff --git a/Ladybird/AppKit/UI/InspectorWindow.h b/Ladybird/AppKit/UI/InspectorWindow.h new file mode 100644 index 000000000000..f9fdbf136ae7 --- /dev/null +++ b/Ladybird/AppKit/UI/InspectorWindow.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2023, Tim Flynn + * Copyright (c) 2024, Neil Viloria + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#import +#import + +@class LadybirdWebView; +@class Tab; + +@interface InspectorWindow : NSWindow + +- (instancetype)init:(Tab*)tab + inspector:(Inspector*)inspector; + +@end diff --git a/Ladybird/AppKit/UI/InspectorWindow.mm b/Ladybird/AppKit/UI/InspectorWindow.mm new file mode 100644 index 000000000000..dc906357ccb3 --- /dev/null +++ b/Ladybird/AppKit/UI/InspectorWindow.mm @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2023, Tim Flynn + * Copyright (c) 2024, Neil Viloria + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include + +#import +#import +#import + +#if !__has_feature(objc_arc) +# error "This project requires ARC" +#endif + +static constexpr CGFloat const WINDOW_WIDTH = 875; +static constexpr CGFloat const WINDOW_HEIGHT = 825; + +@interface InspectorWindow () +{ + OwnPtr m_inspector_client; +} + +@property (nonatomic, strong) Tab* tab; + +@end + +@implementation InspectorWindow + +@synthesize tab = _tab; + +- (instancetype)init:(Tab*)tab + inspector:(Inspector*)inspector +{ + auto tab_rect = [tab frame]; + auto position_x = tab_rect.origin.x + (tab_rect.size.width - WINDOW_WIDTH) / 2; + auto position_y = tab_rect.origin.y + (tab_rect.size.height - WINDOW_HEIGHT) / 2; + + auto window_rect = NSMakeRect(position_x, position_y, WINDOW_WIDTH, WINDOW_HEIGHT); + auto style_mask = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable; + + self = [super initWithContentRect:window_rect + styleMask:style_mask + backing:NSBackingStoreBuffered + defer:NO]; + + if (self) { + self.tab = tab; + + auto* scroll_view = [[NSScrollView alloc] init]; + [scroll_view setHasVerticalScroller:YES]; + [scroll_view setHasHorizontalScroller:YES]; + [scroll_view setLineScroll:24]; + + [scroll_view setContentView:inspector.web_view]; + [scroll_view setDocumentView:[[NSView alloc] init]]; + + [self setContentView:scroll_view]; + [self setTitle:@"Inspector"]; + [self setIsVisible:YES]; + } + return self; +} + +@end diff --git a/Ladybird/AppKit/UI/Tab.mm b/Ladybird/AppKit/UI/Tab.mm index fdd54f413be7..4f2bfeaa42c7 100644 --- a/Ladybird/AppKit/UI/Tab.mm +++ b/Ladybird/AppKit/UI/Tab.mm @@ -16,6 +16,7 @@ #import #import #import +#import #import #import #import @@ -38,6 +39,10 @@ @interface Tab () @property (nonatomic, strong) InspectorController* inspector_controller; +@property (nonatomic, strong) Inspector* inspector; + +@property (nonatomic, strong) NSSplitView* split_view; + @end @implementation Tab @@ -119,13 +124,21 @@ - (instancetype)initWithWebView:(LadybirdWebView*)web_view [stack_view setOrientation:NSUserInterfaceLayoutOrientationVertical]; [stack_view setSpacing:0]; + NSSplitView* split_view = [[NSSplitView alloc] initWithFrame:window_rect]; + [split_view setVertical:YES]; + [split_view setDividerStyle:NSSplitViewDividerStyleThick]; + + self.split_view = split_view; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onContentScroll:) name:NSViewBoundsDidChangeNotification object:[scroll_view contentView]]; - [self setContentView:stack_view]; + [split_view addSubview:stack_view]; + + [self setContentView:split_view]; [[self.search_panel leadingAnchor] constraintEqualToAnchor:[self.contentView leadingAnchor]].active = YES; } @@ -169,7 +182,11 @@ - (void)openInspector:(id)sender return; } - self.inspector_controller = [[InspectorController alloc] init:self]; + if (self.inspector == nil) { + self.inspector = [[Inspector alloc] init:self]; + } + + self.inspector_controller = [[InspectorController alloc] init:self inspector:self.inspector]; [self.inspector_controller showWindow:nil]; } @@ -182,8 +199,7 @@ - (void)inspectElement:(id)sender { [self openInspector:sender]; - auto* inspector = (Inspector*)[self.inspector_controller window]; - [inspector selectHoveredElement]; + [self.inspector selectHoveredElement]; } #pragma mark - Private methods @@ -343,16 +359,14 @@ - (void)onLoadStart:(URL::URL const&)url isRedirect:(BOOL)is_redirect [[self tabController] onLoadStart:url isRedirect:is_redirect]; if (self.inspector_controller != nil) { - auto* inspector = (Inspector*)[self.inspector_controller window]; - [inspector reset]; + [self.inspector reset]; } } - (void)onLoadFinish:(URL::URL const&)url { if (self.inspector_controller != nil) { - auto* inspector = (Inspector*)[self.inspector_controller window]; - [inspector inspect]; + [self.inspector inspect]; } } From e89dfe594239d9f559a82774072e8104bf438f4d Mon Sep 17 00:00:00 2001 From: Neil Viloria Date: Thu, 12 Sep 2024 00:20:32 -0600 Subject: [PATCH 2/3] AppKit+LibWeb+LibWebView+WebContent: Dock inspector in browser window --- Base/res/ladybird/inspector.css | 14 ++++++ Base/res/ladybird/inspector.html | 2 + Base/res/ladybird/inspector.js | 20 ++++++++ .../AppKit/Application/ApplicationDelegate.mm | 3 ++ Ladybird/AppKit/UI/Inspector.h | 6 ++- Ladybird/AppKit/UI/Inspector.mm | 33 ++++++++++++- Ladybird/AppKit/UI/InspectorController.h | 3 +- Ladybird/AppKit/UI/InspectorController.mm | 17 +++++-- Ladybird/AppKit/UI/InspectorWindow.h | 3 +- Ladybird/AppKit/UI/InspectorWindow.mm | 11 +---- Ladybird/AppKit/UI/Tab.h | 4 ++ Ladybird/AppKit/UI/Tab.mm | 48 +++++++++++++++---- .../Libraries/LibWeb/Internals/Inspector.cpp | 5 ++ .../Libraries/LibWeb/Internals/Inspector.h | 2 + .../Libraries/LibWeb/Internals/Inspector.idl | 1 + Userland/Libraries/LibWeb/Page/Page.h | 1 + .../Libraries/LibWebView/InspectorClient.cpp | 29 ++++++++++- .../Libraries/LibWebView/InspectorClient.h | 6 ++- .../Libraries/LibWebView/ViewImplementation.h | 1 + .../Libraries/LibWebView/WebContentClient.cpp | 8 ++++ .../Libraries/LibWebView/WebContentClient.h | 1 + Userland/Services/WebContent/PageClient.cpp | 5 ++ Userland/Services/WebContent/PageClient.h | 1 + .../Services/WebContent/WebContentClient.ipc | 1 + 24 files changed, 194 insertions(+), 31 deletions(-) diff --git a/Base/res/ladybird/inspector.css b/Base/res/ladybird/inspector.css index 4ac8f35f72d1..76f17eb7c074 100644 --- a/Base/res/ladybird/inspector.css +++ b/Base/res/ladybird/inspector.css @@ -147,6 +147,9 @@ body { } .global-controls { + display: flex; + align-items: center; + gap: 8px; margin: 0 8px 0 8px; } @@ -170,6 +173,17 @@ body { background-color: var(--tab-button-background); } +#close-inspector-button { + background-image: url("resource://icons/16x16/close-tab.png"); + background-position: center; + background-repeat: no-repeat; + background-color: var(--tab-controls); +} + +#close-inspector-button:hover { + background-color: var(--tab-button-background); +} + .tab-content { height: calc(100% - 40px); diff --git a/Base/res/ladybird/inspector.html b/Base/res/ladybird/inspector.html index decc53c00fe5..9e375308685c 100644 --- a/Base/res/ladybird/inspector.html +++ b/Base/res/ladybird/inspector.html @@ -22,6 +22,8 @@
+ + @CLOSE_INSPECTOR_BUTTON@
diff --git a/Base/res/ladybird/inspector.js b/Base/res/ladybird/inspector.js index 14482b328e83..3c243cae30df 100644 --- a/Base/res/ladybird/inspector.js +++ b/Base/res/ladybird/inspector.js @@ -96,6 +96,26 @@ inspector.exportInspector = () => { inspector.exportInspectorHTML(html); }; +inspector.close = () => { + inspector.closeInspector(); +}; + +inspector.setCloseInspectorButtonVisibility = isVisible => { + const closeInspectorButton = document.getElementById("close-inspector-button"); + + if (!closeInspectorButton) { + console.error("Could not find close-inspector-button button"); + return; + } + + let display = "none"; + if (isVisible) { + display = "block"; + } + + closeInspectorButton.style.display = display; +}; + inspector.reset = () => { let domTree = document.getElementById("dom-tree"); domTree.innerHTML = ""; diff --git a/Ladybird/AppKit/Application/ApplicationDelegate.mm b/Ladybird/AppKit/Application/ApplicationDelegate.mm index e01cfa988bf2..aabc5a10c104 100644 --- a/Ladybird/AppKit/Application/ApplicationDelegate.mm +++ b/Ladybird/AppKit/Application/ApplicationDelegate.mm @@ -606,6 +606,9 @@ - (NSMenuItem*)createInspectMenu [submenu addItem:[[NSMenuItem alloc] initWithTitle:@"Open Inspector" action:@selector(openInspector:) keyEquivalent:@"I"]]; + [submenu addItem:[[NSMenuItem alloc] initWithTitle:@"Open Inspector Pane" + action:@selector(openInspectorPane:) + keyEquivalent:@""]]; [submenu addItem:[[NSMenuItem alloc] initWithTitle:@"Open Task Manager" action:@selector(openTaskManager:) keyEquivalent:@"M"]]; diff --git a/Ladybird/AppKit/UI/Inspector.h b/Ladybird/AppKit/UI/Inspector.h index 6f0c1558abeb..fdec718f58cb 100644 --- a/Ladybird/AppKit/UI/Inspector.h +++ b/Ladybird/AppKit/UI/Inspector.h @@ -13,13 +13,17 @@ @interface Inspector : NSScrollView -- (instancetype)init:(Tab*)tab; +- (instancetype)init:(Tab*)tab + isWindowed:(BOOL)is_windowed; - (void)inspect; - (void)reset; - (void)selectHoveredElement; +- (void)setIsWindowed:(BOOL)is_windowed; + +@property (nonatomic, strong) NSScrollView* inspector_scroll_view; @property (nonatomic, strong) LadybirdWebView* web_view; @end diff --git a/Ladybird/AppKit/UI/Inspector.mm b/Ladybird/AppKit/UI/Inspector.mm index adb62ef9e582..0e98c308c386 100644 --- a/Ladybird/AppKit/UI/Inspector.mm +++ b/Ladybird/AppKit/UI/Inspector.mm @@ -47,6 +47,7 @@ @implementation Inspector @synthesize cookie_context_menu = _cookie_context_menu; - (instancetype)init:(Tab*)tab + isWindowed:(BOOL)is_windowed { self = [super init]; @@ -56,7 +57,13 @@ - (instancetype)init:(Tab*)tab self.web_view = [[LadybirdWebView alloc] init:nil]; [self.web_view setPostsBoundsChangedNotifications:YES]; - m_inspector_client = make([[tab web_view] view], [[self web_view] view]); + [self setHasVerticalScroller:YES]; + [self setHasHorizontalScroller:YES]; + [self setLineScroll:24]; + [self setContentView:self.web_view]; + [self setDocumentView:[[NSView alloc] init]]; + + m_inspector_client = make([[tab web_view] view], [[self web_view] view], is_windowed); __weak Inspector* weak_self = self; m_inspector_client->on_requested_dom_node_text_context_menu = [weak_self](auto position) { @@ -125,6 +132,15 @@ - (instancetype)init:(Tab*)tab auto* event = Ladybird::create_context_menu_mouse_event(strong_self.web_view, position); [NSMenu popUpContextMenu:strong_self.cookie_context_menu withEvent:event forView:strong_self.web_view]; }; + + m_inspector_client->on_requested_close = [weak_self]() { + Inspector* strong_self = weak_self; + if (strong_self == nil) { + return; + } + + [strong_self removeFromSuperview]; + }; } return self; @@ -147,6 +163,11 @@ - (void)selectHoveredElement m_inspector_client->select_hovered_node(); } +- (void)setIsWindowed:(BOOL)is_visible +{ + m_inspector_client->set_is_windowed(is_visible); +} + #pragma mark - Private methods - (void)editDOMNode:(id)sender @@ -356,4 +377,14 @@ - (NSMenu*)cookie_context_menu return _cookie_context_menu; } +#pragma mark - NSView + +- (void)viewWillMoveToWindow:(NSWindow*)newWindow +{ + // newWindow being nil indicates the inspector view has been removed from its parent + if (newWindow == nil) { + [self.tab onInspectorClosed]; + } +} + @end diff --git a/Ladybird/AppKit/UI/InspectorController.h b/Ladybird/AppKit/UI/InspectorController.h index b5020656ad13..baa748e7ce27 100644 --- a/Ladybird/AppKit/UI/InspectorController.h +++ b/Ladybird/AppKit/UI/InspectorController.h @@ -13,7 +13,6 @@ @interface InspectorController : NSWindowController -- (instancetype)init:(Tab*)tab - inspector:(Inspector*)inspector; +- (instancetype)init:(Tab*)tab; @end diff --git a/Ladybird/AppKit/UI/InspectorController.mm b/Ladybird/AppKit/UI/InspectorController.mm index 7c8ab0defd26..71e377cf197b 100644 --- a/Ladybird/AppKit/UI/InspectorController.mm +++ b/Ladybird/AppKit/UI/InspectorController.mm @@ -16,18 +16,15 @@ @interface InspectorController () @property (nonatomic, strong) Tab* tab; -@property (nonatomic, strong) Inspector* inspector; @end @implementation InspectorController - (instancetype)init:(Tab*)tab - inspector:(Inspector*)inspector { if (self = [super init]) { self.tab = tab; - self.inspector = inspector; } return self; @@ -44,11 +41,23 @@ - (InspectorWindow*)inspectorWindow - (IBAction)showWindow:(id)sender { - self.window = [[InspectorWindow alloc] init:self.tab inspector:self.inspector]; + self.window = [[InspectorWindow alloc] init:self.tab]; [self.window setDelegate:self]; [self.window makeKeyAndOrderFront:sender]; } +- (void)close +{ + // Temporarily remove the window delegate to prevent `windowWillClose` + // from being called. This avoids deallocating the inspector when + // we just want to move it to the main window and close the + // inspector's window + auto delegate = self.window.delegate; + [self.window setDelegate:nil]; + [self.window close]; + [self.window setDelegate:delegate]; +} + #pragma mark - NSWindowDelegate - (void)windowWillClose:(NSNotification*)notification diff --git a/Ladybird/AppKit/UI/InspectorWindow.h b/Ladybird/AppKit/UI/InspectorWindow.h index f9fdbf136ae7..556e3af239ea 100644 --- a/Ladybird/AppKit/UI/InspectorWindow.h +++ b/Ladybird/AppKit/UI/InspectorWindow.h @@ -15,7 +15,6 @@ @interface InspectorWindow : NSWindow -- (instancetype)init:(Tab*)tab - inspector:(Inspector*)inspector; +- (instancetype)init:(Tab*)tab; @end diff --git a/Ladybird/AppKit/UI/InspectorWindow.mm b/Ladybird/AppKit/UI/InspectorWindow.mm index dc906357ccb3..5899aab787a9 100644 --- a/Ladybird/AppKit/UI/InspectorWindow.mm +++ b/Ladybird/AppKit/UI/InspectorWindow.mm @@ -32,7 +32,6 @@ @implementation InspectorWindow @synthesize tab = _tab; - (instancetype)init:(Tab*)tab - inspector:(Inspector*)inspector { auto tab_rect = [tab frame]; auto position_x = tab_rect.origin.x + (tab_rect.size.width - WINDOW_WIDTH) / 2; @@ -49,15 +48,7 @@ - (instancetype)init:(Tab*)tab if (self) { self.tab = tab; - auto* scroll_view = [[NSScrollView alloc] init]; - [scroll_view setHasVerticalScroller:YES]; - [scroll_view setHasHorizontalScroller:YES]; - [scroll_view setLineScroll:24]; - - [scroll_view setContentView:inspector.web_view]; - [scroll_view setDocumentView:[[NSView alloc] init]]; - - [self setContentView:scroll_view]; + [self setContentView:tab.inspector]; [self setTitle:@"Inspector"]; [self setIsVisible:YES]; } diff --git a/Ladybird/AppKit/UI/Tab.h b/Ladybird/AppKit/UI/Tab.h index 26055b73f82e..6faaf0025c44 100644 --- a/Ladybird/AppKit/UI/Tab.h +++ b/Ladybird/AppKit/UI/Tab.h @@ -10,6 +10,8 @@ #import +@class Inspector; + @class LadybirdWebView; @interface Tab : NSWindow @@ -25,4 +27,6 @@ @property (nonatomic, strong) LadybirdWebView* web_view; +@property (nonatomic, strong) Inspector* inspector; + @end diff --git a/Ladybird/AppKit/UI/Tab.mm b/Ladybird/AppKit/UI/Tab.mm index 4f2bfeaa42c7..95a18e87e808 100644 --- a/Ladybird/AppKit/UI/Tab.mm +++ b/Ladybird/AppKit/UI/Tab.mm @@ -14,7 +14,6 @@ #include #import -#import #import #import #import @@ -39,8 +38,6 @@ @interface Tab () @property (nonatomic, strong) InspectorController* inspector_controller; -@property (nonatomic, strong) Inspector* inspector; - @property (nonatomic, strong) NSSplitView* split_view; @end @@ -182,17 +179,50 @@ - (void)openInspector:(id)sender return; } - if (self.inspector == nil) { - self.inspector = [[Inspector alloc] init:self]; - } + if (self.inspector == nil) + self.inspector = [[Inspector alloc] init:self isWindowed:true]; + else + [self.inspector setIsWindowed:true]; - self.inspector_controller = [[InspectorController alloc] init:self inspector:self.inspector]; + self.inspector_controller = [[InspectorController alloc] init:self]; [self.inspector_controller showWindow:nil]; + + [self.split_view layoutSubtreeIfNeeded]; + [self.web_view handleResize]; +} + +- (void)openInspectorPane:(id)sender +{ + if (self.inspector_controller != nil) { + [self.inspector_controller close]; + self.inspector_controller = nil; + } + + if (self.inspector == nil) + self.inspector = [[Inspector alloc] init:self isWindowed:false]; + else + [self.inspector setIsWindowed:false]; + + [self.split_view addSubview:self.inspector]; + [self.split_view layoutSubtreeIfNeeded]; + + CGFloat web_view_width = 0.66 * self.frame.size.width; + [self.split_view setPosition:web_view_width ofDividerAtIndex:0]; + + [[self.inspector web_view] handleResize]; + [self.web_view handleResize]; } - (void)onInspectorClosed { + self.inspector = nil; self.inspector_controller = nil; + + auto& web_view = [[self web_view] view]; + web_view.clear_inspected_dom_node(); + + [self.split_view layoutSubtreeIfNeeded]; + [self.web_view handleResize]; } - (void)inspectElement:(id)sender @@ -358,14 +388,14 @@ - (void)onLoadStart:(URL::URL const&)url isRedirect:(BOOL)is_redirect [[self tabController] onLoadStart:url isRedirect:is_redirect]; - if (self.inspector_controller != nil) { + if (self.inspector != nil) { [self.inspector reset]; } } - (void)onLoadFinish:(URL::URL const&)url { - if (self.inspector_controller != nil) { + if (self.inspector != nil) { [self.inspector inspect]; } } diff --git a/Userland/Libraries/LibWeb/Internals/Inspector.cpp b/Userland/Libraries/LibWeb/Internals/Inspector.cpp index fca0de7c954f..f35c85576cce 100644 --- a/Userland/Libraries/LibWeb/Internals/Inspector.cpp +++ b/Userland/Libraries/LibWeb/Internals/Inspector.cpp @@ -101,4 +101,9 @@ void Inspector::export_inspector_html(String const& html) inspector_page_client().inspector_did_export_inspector_html(html); } +void Inspector::close_inspector() +{ + inspector_page_client().inspector_did_close(); +} + } diff --git a/Userland/Libraries/LibWeb/Internals/Inspector.h b/Userland/Libraries/LibWeb/Internals/Inspector.h index f17a2a2a224d..1e1dca534e8b 100644 --- a/Userland/Libraries/LibWeb/Internals/Inspector.h +++ b/Userland/Libraries/LibWeb/Internals/Inspector.h @@ -37,6 +37,8 @@ class Inspector final : public Bindings::PlatformObject { void export_inspector_html(String const& html); + void close_inspector(); + private: explicit Inspector(JS::Realm&); diff --git a/Userland/Libraries/LibWeb/Internals/Inspector.idl b/Userland/Libraries/LibWeb/Internals/Inspector.idl index 4b2a2330ea8d..f21e25c7d710 100644 --- a/Userland/Libraries/LibWeb/Internals/Inspector.idl +++ b/Userland/Libraries/LibWeb/Internals/Inspector.idl @@ -20,4 +20,5 @@ undefined exportInspectorHTML(DOMString html); + undefined closeInspector(); }; diff --git a/Userland/Libraries/LibWeb/Page/Page.h b/Userland/Libraries/LibWeb/Page/Page.h index 3242bbca6cca..f648dd4f56b0 100644 --- a/Userland/Libraries/LibWeb/Page/Page.h +++ b/Userland/Libraries/LibWeb/Page/Page.h @@ -383,6 +383,7 @@ class PageClient : public JS::Cell { virtual void inspector_did_request_style_sheet_source([[maybe_unused]] CSS::StyleSheetIdentifier const& identifier) { } virtual void inspector_did_execute_console_script([[maybe_unused]] String const& script) { } virtual void inspector_did_export_inspector_html([[maybe_unused]] String const& html) { } + virtual void inspector_did_close() { } virtual bool is_ready_to_paint() const = 0; diff --git a/Userland/Libraries/LibWebView/InspectorClient.cpp b/Userland/Libraries/LibWebView/InspectorClient.cpp index 622833a64882..fd3224efba69 100644 --- a/Userland/Libraries/LibWebView/InspectorClient.cpp +++ b/Userland/Libraries/LibWebView/InspectorClient.cpp @@ -44,9 +44,10 @@ static String style_sheet_identifier_to_json(Web::CSS::StyleSheetIdentifier cons identifier.url.value_or("undefined"_string))); } -InspectorClient::InspectorClient(ViewImplementation& content_web_view, ViewImplementation& inspector_web_view) +InspectorClient::InspectorClient(ViewImplementation& content_web_view, ViewImplementation& inspector_web_view, bool is_windowed) : m_content_web_view(content_web_view) , m_inspector_web_view(inspector_web_view) + , m_is_windowed(is_windowed) { m_content_web_view.on_received_dom_tree = [this](auto const& dom_tree) { auto result = parse_json_tree(dom_tree); @@ -280,6 +281,10 @@ InspectorClient::InspectorClient(ViewImplementation& content_web_view, ViewImple append_console_message(MUST(String::formatted("Exported Inspector files to {}", inspector_path))); }; + m_inspector_web_view.on_inspector_closed = [this]() { + this->on_requested_close(); + }; + load_inspector(); } @@ -504,6 +509,15 @@ void InspectorClient::context_menu_delete_all_cookies() m_cookie_context_menu_index.clear(); } +void InspectorClient::set_is_windowed(bool is_windowed) +{ + if (!m_inspector_loaded) + return; + + auto const script = MUST(String::formatted("inspector.setCloseInspectorButtonVisibility({});", !is_windowed)); + m_inspector_web_view.run_javascript(script); +} + void InspectorClient::load_inspector() { auto inspector_html = MUST(Core::Resource::load_from_uri(INSPECTOR_HTML)); @@ -535,6 +549,19 @@ void InspectorClient::load_inspector() generator.set("COMPUTED_STYLE"sv, generate_property_table("computed-style"sv)); generator.set("RESOVLED_STYLE"sv, generate_property_table("resolved-style"sv)); generator.set("CUSTOM_PROPERTIES"sv, generate_property_table("custom-properties"sv)); + + auto display = "block"; + if (m_is_windowed) { + display = "none"; + } + + auto button_element = MUST(String::formatted(R"~~~( + +)~~~", + display)); + + generator.set("CLOSE_INSPECTOR_BUTTON"sv, button_element); + generator.append(inspector_html->data()); m_inspector_web_view.load_html(generator.as_string_view()); diff --git a/Userland/Libraries/LibWebView/InspectorClient.h b/Userland/Libraries/LibWebView/InspectorClient.h index 90cf279cb188..7c19c11edfe2 100644 --- a/Userland/Libraries/LibWebView/InspectorClient.h +++ b/Userland/Libraries/LibWebView/InspectorClient.h @@ -19,7 +19,7 @@ namespace WebView { class InspectorClient { public: - InspectorClient(ViewImplementation& content_web_view, ViewImplementation& inspector_web_view); + InspectorClient(ViewImplementation& content_web_view, ViewImplementation& inspector_web_view, bool is_windowed); ~InspectorClient(); void inspect(); @@ -41,11 +41,13 @@ class InspectorClient { void context_menu_copy_dom_node_attribute_value(); void context_menu_delete_cookie(); void context_menu_delete_all_cookies(); + void set_is_windowed(bool is_windowed); Function on_requested_dom_node_text_context_menu; Function on_requested_dom_node_tag_context_menu; Function on_requested_dom_node_attribute_context_menu; Function on_requested_cookie_context_menu; + Function on_requested_close; private: void load_inspector(); @@ -93,6 +95,8 @@ class InspectorClient { i32 m_highest_notified_message_index { -1 }; i32 m_highest_received_message_index { -1 }; bool m_waiting_for_messages { false }; + + bool m_is_windowed { false }; }; } diff --git a/Userland/Libraries/LibWebView/ViewImplementation.h b/Userland/Libraries/LibWebView/ViewImplementation.h index 4ab7090da2ef..15382f18ec06 100644 --- a/Userland/Libraries/LibWebView/ViewImplementation.h +++ b/Userland/Libraries/LibWebView/ViewImplementation.h @@ -226,6 +226,7 @@ class ViewImplementation { Function on_inspector_executed_console_script; Function on_inspector_exported_inspector_html; Function on_request_worker_agent; + Function on_inspector_closed; virtual Web::DevicePixelSize viewport_size() const = 0; virtual Gfx::IntPoint to_content_position(Gfx::IntPoint widget_position) const = 0; diff --git a/Userland/Libraries/LibWebView/WebContentClient.cpp b/Userland/Libraries/LibWebView/WebContentClient.cpp index 5e13efc4f736..f3cae01a087d 100644 --- a/Userland/Libraries/LibWebView/WebContentClient.cpp +++ b/Userland/Libraries/LibWebView/WebContentClient.cpp @@ -694,6 +694,14 @@ void WebContentClient::inspector_did_export_inspector_html(u64 page_id, String c } } +void WebContentClient::inspector_did_close(u64 page_id) +{ + if (auto view = view_for_page_id(page_id); view.has_value()) { + if (view->on_inspector_closed) + view->on_inspector_closed(); + } +} + Messages::WebContentClient::RequestWorkerAgentResponse WebContentClient::request_worker_agent(u64 page_id) { if (auto view = view_for_page_id(page_id); view.has_value()) { diff --git a/Userland/Libraries/LibWebView/WebContentClient.h b/Userland/Libraries/LibWebView/WebContentClient.h index 4b9d84e2f89a..8e03c822a2f3 100644 --- a/Userland/Libraries/LibWebView/WebContentClient.h +++ b/Userland/Libraries/LibWebView/WebContentClient.h @@ -126,6 +126,7 @@ class WebContentClient final virtual void inspector_did_request_cookie_context_menu(u64 page_id, size_t cookie_index, Gfx::IntPoint position) override; virtual void inspector_did_execute_console_script(u64 page_id, String const& script) override; virtual void inspector_did_export_inspector_html(u64 page_id, String const& html) override; + virtual void inspector_did_close(u64 page_id) override; virtual Messages::WebContentClient::RequestWorkerAgentResponse request_worker_agent(u64 page_id) override; virtual void inspector_did_list_style_sheets(u64 page_id, Vector const& stylesheets) override; virtual void inspector_did_request_style_sheet_source(u64 page_id, Web::CSS::StyleSheetIdentifier const& identifier) override; diff --git a/Userland/Services/WebContent/PageClient.cpp b/Userland/Services/WebContent/PageClient.cpp index ca2b9fb502d4..36d315e1c9dd 100644 --- a/Userland/Services/WebContent/PageClient.cpp +++ b/Userland/Services/WebContent/PageClient.cpp @@ -674,6 +674,11 @@ void PageClient::inspector_did_export_inspector_html(String const& html) client().async_inspector_did_export_inspector_html(m_id, html); } +void PageClient::inspector_did_close() +{ + client().async_inspector_did_close(m_id); +} + ErrorOr PageClient::connect_to_webdriver(ByteString const& webdriver_ipc_path) { VERIFY(!m_webdriver); diff --git a/Userland/Services/WebContent/PageClient.h b/Userland/Services/WebContent/PageClient.h index 2875428d799d..1f8b72a61599 100644 --- a/Userland/Services/WebContent/PageClient.h +++ b/Userland/Services/WebContent/PageClient.h @@ -173,6 +173,7 @@ class PageClient final : public Web::PageClient { virtual void inspector_did_request_style_sheet_source(Web::CSS::StyleSheetIdentifier const& stylesheet_source) override; virtual void inspector_did_execute_console_script(String const& script) override; virtual void inspector_did_export_inspector_html(String const& script) override; + virtual void inspector_did_close() override; Web::Layout::Viewport* layout_root(); void setup_palette(); diff --git a/Userland/Services/WebContent/WebContentClient.ipc b/Userland/Services/WebContent/WebContentClient.ipc index 94b346ccac1a..d6f21e56e61c 100644 --- a/Userland/Services/WebContent/WebContentClient.ipc +++ b/Userland/Services/WebContent/WebContentClient.ipc @@ -113,5 +113,6 @@ endpoint WebContentClient inspector_did_request_cookie_context_menu(u64 page_id, size_t cookie_index, Gfx::IntPoint position) =| inspector_did_execute_console_script(u64 page_id, String script) =| inspector_did_export_inspector_html(u64 page_id, String html) =| + inspector_did_close(u64 page_id) =| } From e342700e7de72d2cb5acc17b3bd176d85d6545c2 Mon Sep 17 00:00:00 2001 From: Neil Viloria Date: Wed, 18 Sep 2024 23:54:26 -0600 Subject: [PATCH 3/3] Qt: Dock inspector in browser window --- Ladybird/Qt/BrowserWindow.cpp | 9 +++++++++ Ladybird/Qt/InspectorWidget.cpp | 23 ++++++++++++++++++----- Ladybird/Qt/InspectorWidget.h | 4 +++- Ladybird/Qt/Tab.cpp | 28 +++++++++++++++++++++++----- Ladybird/Qt/Tab.h | 3 +++ 5 files changed, 56 insertions(+), 11 deletions(-) diff --git a/Ladybird/Qt/BrowserWindow.cpp b/Ladybird/Qt/BrowserWindow.cpp index 937ca066e99a..9e55d0448ba8 100644 --- a/Ladybird/Qt/BrowserWindow.cpp +++ b/Ladybird/Qt/BrowserWindow.cpp @@ -363,6 +363,15 @@ BrowserWindow::BrowserWindow(Vector const& initial_urls, IsPopupWindow } }); + auto* inspector_pane_action = new QAction("Open Inspector Pane", this); + inspector_pane_action->setIcon(load_icon_from_uri("resource://icons/browser/dom-tree.png"sv)); + inspect_menu->addAction(inspector_pane_action); + QObject::connect(inspector_pane_action, &QAction::triggered, this, [this] { + if (m_current_tab) { + m_current_tab->show_inspector_pane(); + } + }); + auto* task_manager_action = new QAction("Open Task &Manager", this); task_manager_action->setIcon(load_icon_from_uri("resource://icons/16x16/app-system-monitor.png"sv)); task_manager_action->setShortcuts({ QKeySequence("Ctrl+Shift+M") }); diff --git a/Ladybird/Qt/InspectorWidget.cpp b/Ladybird/Qt/InspectorWidget.cpp index ad61f73f0553..fd8524d81451 100644 --- a/Ladybird/Qt/InspectorWidget.cpp +++ b/Ladybird/Qt/InspectorWidget.cpp @@ -20,15 +20,16 @@ namespace Ladybird { extern bool is_using_dark_system_theme(QWidget&); -InspectorWidget::InspectorWidget(QWidget* tab, WebContentView& content_view) - : QWidget(tab, Qt::Window) +InspectorWidget::InspectorWidget(QWidget* tab, WebContentView& content_view, Qt::WindowType window_type) + : QWidget(tab, window_type) { m_inspector_view = new WebContentView(this); if (is_using_dark_system_theme(*this)) m_inspector_view->update_palette(WebContentView::PaletteMode::Dark); - m_inspector_client = make(content_view, *m_inspector_view); + auto is_windowed = window_type == Qt::Window; + m_inspector_client = make(content_view, *m_inspector_view, is_windowed); m_edit_node_action = new QAction("&Edit node", this); connect(m_edit_node_action, &QAction::triggered, [this]() { m_inspector_client->context_menu_edit_dom_node(); }); @@ -136,11 +137,15 @@ InspectorWidget::InspectorWidget(QWidget* tab, WebContentView& content_view) m_cookie_context_menu->exec(m_inspector_view->map_point_to_global_position(position)); }; + m_inspector_client->on_requested_close = [this]() { + close(); + }; + setLayout(new QVBoxLayout); layout()->addWidget(m_inspector_view); - setWindowTitle("Inspector"); - resize(875, 825); + if (is_windowed) + setWindowTitle("Inspector"); // Listen for DPI changes m_device_pixel_ratio = devicePixelRatio(); @@ -183,6 +188,14 @@ void InspectorWidget::select_default_node() m_inspector_client->select_default_node(); } +void InspectorWidget::setWindowFlag(Qt::WindowType flag, bool on) +{ + QWidget::setWindowFlag(flag, on); + + auto is_windowed = flag == Qt::Window; + m_inspector_client->set_is_windowed(is_windowed); +} + void InspectorWidget::device_pixel_ratio_changed(qreal dpi) { m_device_pixel_ratio = dpi; diff --git a/Ladybird/Qt/InspectorWidget.h b/Ladybird/Qt/InspectorWidget.h index 784b7df524bb..e0f0823d3084 100644 --- a/Ladybird/Qt/InspectorWidget.h +++ b/Ladybird/Qt/InspectorWidget.h @@ -22,7 +22,7 @@ class InspectorWidget final : public QWidget { Q_OBJECT public: - InspectorWidget(QWidget* tab, WebContentView& content_view); + InspectorWidget(QWidget* tab, WebContentView& content_view, Qt::WindowType window_type); virtual ~InspectorWidget() override; void inspect(); @@ -31,6 +31,8 @@ class InspectorWidget final : public QWidget { void select_hovered_node(); void select_default_node(); + void setWindowFlag(Qt::WindowType flag, bool on = true); + public slots: void device_pixel_ratio_changed(qreal dpi); diff --git a/Ladybird/Qt/Tab.cpp b/Ladybird/Qt/Tab.cpp index ee76f673e23e..22045d1ef9a4 100644 --- a/Ladybird/Qt/Tab.cpp +++ b/Ladybird/Qt/Tab.cpp @@ -70,8 +70,11 @@ Tab::Tab(BrowserWindow* window, RefPtr parent_client, focus_location_editor_action->setShortcut(QKeySequence("Ctrl+L")); addAction(focus_location_editor_action); + m_splitter = new QSplitter(this); + m_splitter->addWidget(m_view); + m_layout->addWidget(m_toolbar); - m_layout->addWidget(m_view); + m_layout->addWidget(m_splitter); m_layout->addWidget(m_find_in_page); m_hamburger_button = new QToolButton(m_toolbar); @@ -875,18 +878,33 @@ void Tab::recreate_toolbar_icons() void Tab::show_inspector_window(InspectorTarget inspector_target) { if (!m_inspector_widget) - m_inspector_widget = new InspectorWidget(this, view()); - else - m_inspector_widget->inspect(); + m_inspector_widget = new InspectorWidget(this, view(), Qt::Window); + else { + m_inspector_widget->setParent(nullptr); + m_inspector_widget->setWindowFlag(Qt::Window); + } m_inspector_widget->show(); + m_inspector_widget->resize(875, 825); m_inspector_widget->activateWindow(); m_inspector_widget->raise(); if (inspector_target == InspectorTarget::HoveredElement) m_inspector_widget->select_hovered_node(); +} + +void Tab::show_inspector_pane() +{ + if (!m_inspector_widget) + m_inspector_widget = new InspectorWidget(this, view(), Qt::Widget); else - m_inspector_widget->select_default_node(); + m_inspector_widget->setWindowFlag(Qt::Widget); + + m_splitter->addWidget(m_inspector_widget); + + m_splitter->setSizes({ 200, 100 }); + + m_inspector_widget->show(); } void Tab::show_find_in_page() diff --git a/Ladybird/Qt/Tab.h b/Ladybird/Qt/Tab.h index 2881b90c62d0..bdfc7e111b58 100644 --- a/Ladybird/Qt/Tab.h +++ b/Ladybird/Qt/Tab.h @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -51,6 +52,7 @@ class Tab final : public QWidget { HoveredElement }; void show_inspector_window(InspectorTarget = InspectorTarget::Document); + void show_inspector_pane(); void show_find_in_page(); void find_previous(); @@ -105,6 +107,7 @@ public slots: void close_sub_widgets(); + QSplitter* m_splitter { nullptr }; QBoxLayout* m_layout { nullptr }; QToolBar* m_toolbar { nullptr }; QToolButton* m_hamburger_button { nullptr };