diff --git a/Ladybird/AppKit/Application/ApplicationBridge.cpp b/Ladybird/AppKit/Application/ApplicationBridge.cpp index cadc17d7e809e..a1141487d056c 100644 --- a/Ladybird/AppKit/Application/ApplicationBridge.cpp +++ b/Ladybird/AppKit/Application/ApplicationBridge.cpp @@ -49,26 +49,6 @@ ErrorOr ApplicationBridge::launch_image_decoder() { m_impl->image_decoder_client = TRY(launch_new_image_decoder()); - m_impl->image_decoder_client->on_death = [this] { - m_impl->image_decoder_client = nullptr; - if (auto err = this->launch_image_decoder(); err.is_error()) { - dbgln("Failed to restart image decoder: {}", err.error()); - VERIFY_NOT_REACHED(); - } - - auto num_clients = WebView::WebContentClient::client_count(); - auto new_sockets = m_impl->image_decoder_client->send_sync_but_allow_failure(num_clients); - if (!new_sockets || new_sockets->sockets().size() == 0) { - dbgln("Failed to connect {} new clients to ImageDecoder", num_clients); - VERIFY_NOT_REACHED(); - } - - WebView::WebContentClient::for_each_client([sockets = new_sockets->take_sockets()](WebView::WebContentClient& client) mutable { - client.async_connect_to_image_decoder(sockets.take_last()); - return IterationDecision::Continue; - }); - }; - return {}; } diff --git a/Ladybird/AppKit/Application/ApplicationDelegate.mm b/Ladybird/AppKit/Application/ApplicationDelegate.mm index 1193fcc2718c3..fcbc5cc675534 100644 --- a/Ladybird/AppKit/Application/ApplicationDelegate.mm +++ b/Ladybird/AppKit/Application/ApplicationDelegate.mm @@ -37,7 +37,7 @@ @interface ApplicationDelegate () } @property (nonatomic, strong) NSMutableArray* managed_tabs; -@property (nonatomic, strong) Tab* active_tab; +@property (nonatomic, weak) Tab* active_tab; @property (nonatomic, strong) TaskManagerController* task_manager_controller; diff --git a/Ladybird/AppKit/Application/EventLoopImplementation.mm b/Ladybird/AppKit/Application/EventLoopImplementation.mm index d97b22ef2afcc..188390784fb56 100644 --- a/Ladybird/AppKit/Application/EventLoopImplementation.mm +++ b/Ladybird/AppKit/Application/EventLoopImplementation.mm @@ -91,7 +91,7 @@ bool have(int handler_id) const SignalHandlers::SignalHandlers(int signal_number, CFFileDescriptorCallBack handle_signal) : m_signal_number(signal_number) - , m_original_handler(signal(signal_number, SIG_IGN)) + , m_original_handler(signal(signal_number, [](int) {})) { m_kevent_fd = kqueue(); if (m_kevent_fd < 0) { @@ -100,14 +100,14 @@ bool have(int handler_id) const } struct kevent changes = {}; - EV_SET(&changes, signal_number, EVFILT_SIGNAL, EV_ADD | EV_RECEIPT, NOTE_EXIT, 0, NULL); + EV_SET(&changes, signal_number, EVFILT_SIGNAL, EV_ADD | EV_RECEIPT, 0, 0, nullptr); if (auto res = kevent(m_kevent_fd, &changes, 1, &changes, 1, NULL); res < 0) { dbgln("Unable to register signal {}: {}", signal_number, strerror(errno)); VERIFY_NOT_REACHED(); } CFFileDescriptorContext context = { 0, this, nullptr, nullptr, nullptr }; - CFFileDescriptorRef kq_ref = CFFileDescriptorCreate(kCFAllocatorDefault, m_kevent_fd, TRUE, handle_signal, &context); + CFFileDescriptorRef kq_ref = CFFileDescriptorCreate(kCFAllocatorDefault, m_kevent_fd, FALSE, handle_signal, &context); m_source = CFFileDescriptorCreateRunLoopSource(kCFAllocatorDefault, kq_ref, 0); CFRunLoopAddSource(CFRunLoopGetMain(), m_source, kCFRunLoopDefaultMode); @@ -137,6 +137,7 @@ bool have(int handler_id) const void SignalHandlers::dispatch() { + dbgln("Dispatching signal {}", m_signal_number); TemporaryChange change(m_calling_handlers, true); for (auto& handler : m_handlers) handler.value(m_signal_number); @@ -156,6 +157,7 @@ bool have(int handler_id) const int SignalHandlers::add(Function&& handler) { + dbgln("Add signal handler for {}", m_signal_number); int id = ++signals_info()->next_signal_id; // TODO: worry about wrapping and duplicates? if (m_calling_handlers) m_handlers_pending.set(id, move(handler)); @@ -166,6 +168,7 @@ bool have(int handler_id) const bool SignalHandlers::remove(int handler_id) { + dbgln("remove signal handler for {}", m_signal_number); VERIFY(handler_id != 0); if (m_calling_handlers) { auto it = m_handlers.find(handler_id); @@ -316,6 +319,7 @@ static void socket_notifier(CFSocketRef socket, CFSocketCallBackType notificatio static void handle_signal(CFFileDescriptorRef f, CFOptionFlags callback_types, void* info) { + dbgln("Handle signal callback"); VERIFY(callback_types & kCFFileDescriptorReadCallBack); auto* signal_handlers = static_cast(info); @@ -330,6 +334,7 @@ static void handle_signal(CFFileDescriptorRef f, CFOptionFlags callback_types, v int CFEventLoopManager::register_signal(int signal_number, Function handler) { + dbgln("register signal {}", signal_number); VERIFY(signal_number != 0); auto& info = *signals_info(); auto handlers = info.signal_handlers.find(signal_number); diff --git a/Ladybird/AppKit/UI/LadybirdWebView.mm b/Ladybird/AppKit/UI/LadybirdWebView.mm index 726ab0201aed4..040243519758f 100644 --- a/Ladybird/AppKit/UI/LadybirdWebView.mm +++ b/Ladybird/AppKit/UI/LadybirdWebView.mm @@ -119,6 +119,11 @@ - (instancetype)init:(id)observer return self; } +- (void)dealloc +{ + dbgln("Deallocating LadybirdWebView"); +} + #pragma mark - Public methods - (void)loadURL:(URL::URL const&)url @@ -292,23 +297,26 @@ - (void)updateStatusLabelPosition - (void)setWebViewCallbacks { - m_web_view_bridge->on_did_layout = [self](auto content_size) { + __weak LadybirdWebView* weak_self = self; + m_web_view_bridge->on_did_layout = [weak_self](auto content_size) { + LadybirdWebView* self = weak_self; auto inverse_device_pixel_ratio = m_web_view_bridge->inverse_device_pixel_ratio(); - [[self documentView] setFrameSize:NSMakeSize(content_size.width() * inverse_device_pixel_ratio, content_size.height() * inverse_device_pixel_ratio)]; + [[weak_self documentView] setFrameSize:NSMakeSize(content_size.width() * inverse_device_pixel_ratio, content_size.height() * inverse_device_pixel_ratio)]; }; - m_web_view_bridge->on_ready_to_paint = [self]() { - [self setNeedsDisplay:YES]; + m_web_view_bridge->on_ready_to_paint = [weak_self]() { + [weak_self setNeedsDisplay:YES]; }; - m_web_view_bridge->on_new_web_view = [self](auto activate_tab, auto, auto) { + m_web_view_bridge->on_new_web_view = [weak_self](auto activate_tab, auto, auto) { // FIXME: Create a child tab that re-uses the ConnectionFromClient of the parent tab - return [self.observer onCreateNewTab:"about:blank"sv activateTab:activate_tab]; + return [weak_self.observer onCreateNewTab:"about:blank"sv activateTab:activate_tab]; }; - m_web_view_bridge->on_request_web_content = [self]() { + m_web_view_bridge->on_request_web_content = [weak_self]() { Application* application = NSApp; - return [application launchWebContent:*m_web_view_bridge].release_value_but_fixme_should_propagate_errors(); + LadybirdWebView* self = weak_self; + return [application launchWebContent:*(self->m_web_view_bridge)].release_value_but_fixme_should_propagate_errors(); }; m_web_view_bridge->on_request_worker_agent = []() { @@ -316,15 +324,16 @@ - (void)setWebViewCallbacks return [application launchWebWorker].release_value_but_fixme_should_propagate_errors(); }; - m_web_view_bridge->on_activate_tab = [self]() { - [[self window] orderFront:nil]; + m_web_view_bridge->on_activate_tab = [weak_self]() { + [[weak_self window] orderFront:nil]; }; - m_web_view_bridge->on_close = [self]() { - [[self window] close]; + m_web_view_bridge->on_close = [weak_self]() { + [[weak_self window] close]; }; - m_web_view_bridge->on_load_start = [self](auto const& url, bool is_redirect) { + m_web_view_bridge->on_load_start = [weak_self](auto const& url, bool is_redirect) { + LadybirdWebView* self = weak_self; [self.observer onLoadStart:url isRedirect:is_redirect]; if (_status_label != nil) { @@ -332,36 +341,37 @@ - (void)setWebViewCallbacks } }; - m_web_view_bridge->on_load_finish = [self](auto const& url) { - [self.observer onLoadFinish:url]; + m_web_view_bridge->on_load_finish = [weak_self](auto const& url) { + [weak_self.observer onLoadFinish:url]; }; - m_web_view_bridge->on_url_change = [self](auto const& url) { - [self.observer onURLChange:url]; + m_web_view_bridge->on_url_change = [weak_self](auto const& url) { + [weak_self.observer onURLChange:url]; }; - m_web_view_bridge->on_navigation_buttons_state_changed = [self](auto back_enabled, auto forward_enabled) { - [self.observer onBackNavigationEnabled:back_enabled - forwardNavigationEnabled:forward_enabled]; + m_web_view_bridge->on_navigation_buttons_state_changed = [weak_self](auto back_enabled, auto forward_enabled) { + [weak_self.observer onBackNavigationEnabled:back_enabled + forwardNavigationEnabled:forward_enabled]; }; - m_web_view_bridge->on_title_change = [self](auto const& title) { - [self.observer onTitleChange:title]; + m_web_view_bridge->on_title_change = [weak_self](auto const& title) { + [weak_self.observer onTitleChange:title]; }; - m_web_view_bridge->on_favicon_change = [self](auto const& bitmap) { - [self.observer onFaviconChange:bitmap]; + m_web_view_bridge->on_favicon_change = [weak_self](auto const& bitmap) { + [weak_self.observer onFaviconChange:bitmap]; }; - m_web_view_bridge->on_finish_handling_key_event = [self](auto const& key_event) { + m_web_view_bridge->on_finish_handling_key_event = [weak_self](auto const& key_event) { NSEvent* event = Ladybird::key_event_to_ns_event(key_event); - self.event_being_redispatched = event; + weak_self.event_being_redispatched = event; [NSApp sendEvent:event]; - self.event_being_redispatched = nil; + weak_self.event_being_redispatched = nil; }; - m_web_view_bridge->on_cursor_change = [self](auto cursor) { + m_web_view_bridge->on_cursor_change = [weak_self](auto cursor) { + LadybirdWebView* self = weak_self; if (cursor == Gfx::StandardCursor::Hidden) { if (!m_hidden_cursor.has_value()) { m_hidden_cursor.emplace(); @@ -440,58 +450,59 @@ - (void)setWebViewCallbacks } }; - m_web_view_bridge->on_zoom_level_changed = [self]() { - [self updateViewportRect:Ladybird::WebViewBridge::ForResize::Yes]; + m_web_view_bridge->on_zoom_level_changed = [weak_self]() { + [weak_self updateViewportRect:Ladybird::WebViewBridge::ForResize::Yes]; }; - m_web_view_bridge->on_navigate_back = [self]() { - [self navigateBack]; + m_web_view_bridge->on_navigate_back = [weak_self]() { + [weak_self navigateBack]; }; - m_web_view_bridge->on_navigate_forward = [self]() { - [self navigateForward]; + m_web_view_bridge->on_navigate_forward = [weak_self]() { + [weak_self navigateForward]; }; - m_web_view_bridge->on_refresh = [self]() { - [self reload]; + m_web_view_bridge->on_refresh = [weak_self]() { + [weak_self reload]; }; - m_web_view_bridge->on_enter_tooltip_area = [self](auto, auto const& tooltip) { - self.toolTip = Ladybird::string_to_ns_string(tooltip); + m_web_view_bridge->on_enter_tooltip_area = [weak_self](auto, auto const& tooltip) { + weak_self.toolTip = Ladybird::string_to_ns_string(tooltip); }; - m_web_view_bridge->on_leave_tooltip_area = [self]() { - self.toolTip = nil; + m_web_view_bridge->on_leave_tooltip_area = [weak_self]() { + weak_self.toolTip = nil; }; - m_web_view_bridge->on_link_hover = [self](auto const& url) { + m_web_view_bridge->on_link_hover = [weak_self](auto const& url) { auto* url_string = Ladybird::string_to_ns_string(url.serialize()); - [self.status_label setStringValue:url_string]; - [self.status_label sizeToFit]; - [self.status_label setHidden:NO]; + [weak_self.status_label setStringValue:url_string]; + [weak_self.status_label sizeToFit]; + [weak_self.status_label setHidden:NO]; - [self updateStatusLabelPosition]; + [weak_self updateStatusLabelPosition]; }; - m_web_view_bridge->on_link_unhover = [self]() { - [self.status_label setHidden:YES]; + m_web_view_bridge->on_link_unhover = [weak_self]() { + [weak_self.status_label setHidden:YES]; }; - m_web_view_bridge->on_link_click = [self](auto const& url, auto const& target, unsigned modifiers) { + m_web_view_bridge->on_link_click = [weak_self](auto const& url, auto const& target, unsigned modifiers) { if (modifiers == Web::UIEvents::KeyModifier::Mod_Super) { - [self.observer onCreateNewTab:url activateTab:Web::HTML::ActivateTab::No]; + [weak_self.observer onCreateNewTab:url activateTab:Web::HTML::ActivateTab::No]; } else if (target == "_blank"sv) { - [self.observer onCreateNewTab:url activateTab:Web::HTML::ActivateTab::Yes]; + [weak_self.observer onCreateNewTab:url activateTab:Web::HTML::ActivateTab::Yes]; } else { - [self.observer loadURL:url]; + [weak_self.observer loadURL:url]; } }; - m_web_view_bridge->on_link_middle_click = [self](auto url, auto, unsigned) { - [self.observer onCreateNewTab:url activateTab:Web::HTML::ActivateTab::No]; + m_web_view_bridge->on_link_middle_click = [weak_self](auto url, auto, unsigned) { + [weak_self.observer onCreateNewTab:url activateTab:Web::HTML::ActivateTab::No]; }; - m_web_view_bridge->on_context_menu_request = [self](auto position) { + m_web_view_bridge->on_context_menu_request = [weak_self](auto position) { + LadybirdWebView* self = weak_self; auto* search_selected_text_menu_item = [self.page_context_menu itemWithTag:CONTEXT_MENU_SEARCH_SELECTED_TEXT_TAG]; auto selected_text = self.observer @@ -513,7 +524,8 @@ - (void)setWebViewCallbacks [NSMenu popUpContextMenu:self.page_context_menu withEvent:event forView:self]; }; - m_web_view_bridge->on_link_context_menu_request = [self](auto const& url, auto position) { + m_web_view_bridge->on_link_context_menu_request = [weak_self](auto const& url, auto position) { + LadybirdWebView* self = weak_self; TemporaryChange change_url { m_context_menu_url, url }; auto* copy_link_menu_item = [self.link_context_menu itemWithTag:CONTEXT_MENU_COPY_LINK_TAG]; @@ -531,10 +543,11 @@ - (void)setWebViewCallbacks } auto* event = Ladybird::create_context_menu_mouse_event(self, position); - [NSMenu popUpContextMenu:self.link_context_menu withEvent:event forView:self]; + [NSMenu popUpContextMenu:weak_self.link_context_menu withEvent:event forView:self]; }; - m_web_view_bridge->on_image_context_menu_request = [self](auto const& url, auto position, auto const& bitmap) { + m_web_view_bridge->on_image_context_menu_request = [weak_self](auto const& url, auto position, auto const& bitmap) { + LadybirdWebView* self = weak_self; TemporaryChange change_url { m_context_menu_url, url }; TemporaryChange change_bitmap { m_context_menu_bitmap, bitmap }; @@ -542,7 +555,8 @@ - (void)setWebViewCallbacks [NSMenu popUpContextMenu:self.image_context_menu withEvent:event forView:self]; }; - m_web_view_bridge->on_media_context_menu_request = [self](auto position, auto const& menu) { + m_web_view_bridge->on_media_context_menu_request = [weak_self](auto position, auto const& menu) { + LadybirdWebView* self = weak_self; TemporaryChange change_url { m_context_menu_url, menu.media_url }; auto* context_menu = menu.is_video ? self.video_context_menu : self.audio_context_menu; @@ -573,7 +587,8 @@ - (void)setWebViewCallbacks [NSMenu popUpContextMenu:context_menu withEvent:event forView:self]; }; - m_web_view_bridge->on_request_alert = [self](auto const& message) { + m_web_view_bridge->on_request_alert = [weak_self](auto const& message) { + LadybirdWebView* self = weak_self; auto* ns_message = Ladybird::string_to_ns_string(message); self.dialog = [[NSAlert alloc] init]; @@ -586,7 +601,8 @@ - (void)setWebViewCallbacks }]; }; - m_web_view_bridge->on_request_confirm = [self](auto const& message) { + m_web_view_bridge->on_request_confirm = [weak_self](auto const& message) { + LadybirdWebView* self = weak_self; auto* ns_message = Ladybird::string_to_ns_string(message); self.dialog = [[NSAlert alloc] init]; @@ -601,7 +617,8 @@ - (void)setWebViewCallbacks }]; }; - m_web_view_bridge->on_request_prompt = [self](auto const& message, auto const& default_) { + m_web_view_bridge->on_request_prompt = [weak_self](auto const& message, auto const& default_) { + LadybirdWebView* self = weak_self; auto* ns_message = Ladybird::string_to_ns_string(message); auto* ns_default = Ladybird::string_to_ns_string(default_); @@ -629,44 +646,44 @@ - (void)setWebViewCallbacks }]; }; - m_web_view_bridge->on_request_set_prompt_text = [self](auto const& message) { - if (self.dialog == nil || [self.dialog accessoryView] == nil) { + m_web_view_bridge->on_request_set_prompt_text = [weak_self](auto const& message) { + if (weak_self.dialog == nil || [weak_self.dialog accessoryView] == nil) { return; } auto* ns_message = Ladybird::string_to_ns_string(message); - auto* input = (NSTextField*)[self.dialog accessoryView]; + auto* input = (NSTextField*)[weak_self.dialog accessoryView]; [input setStringValue:ns_message]; }; - m_web_view_bridge->on_request_accept_dialog = [self]() { - if (self.dialog == nil) { + m_web_view_bridge->on_request_accept_dialog = [weak_self]() { + if (weak_self.dialog == nil) { return; } - [[self window] endSheet:[[self dialog] window] - returnCode:NSModalResponseOK]; + [[weak_self window] endSheet:[[weak_self dialog] window] + returnCode:NSModalResponseOK]; }; - m_web_view_bridge->on_request_dismiss_dialog = [self]() { - if (self.dialog == nil) { + m_web_view_bridge->on_request_dismiss_dialog = [weak_self]() { + if (weak_self.dialog == nil) { return; } - [[self window] endSheet:[[self dialog] window] - returnCode:NSModalResponseCancel]; + [[weak_self window] endSheet:[[weak_self dialog] window] + returnCode:NSModalResponseCancel]; }; - m_web_view_bridge->on_request_color_picker = [self](Color current_color) { + m_web_view_bridge->on_request_color_picker = [weak_self](Color current_color) { auto* panel = [NSColorPanel sharedColorPanel]; [panel setColor:Ladybird::gfx_color_to_ns_color(current_color)]; [panel setShowsAlpha:NO]; - [panel setTarget:self]; + [panel setTarget:weak_self]; [panel setAction:@selector(colorPickerUpdate:)]; NSNotificationCenter* notification_center = [NSNotificationCenter defaultCenter]; - [notification_center addObserver:self + [notification_center addObserver:weak_self selector:@selector(colorPickerClosed:) name:NSWindowWillCloseNotification object:panel]; @@ -674,7 +691,8 @@ - (void)setWebViewCallbacks [panel makeKeyAndOrderFront:nil]; }; - m_web_view_bridge->on_request_file_picker = [self](auto const& accepted_file_types, auto allow_multiple_files) { + m_web_view_bridge->on_request_file_picker = [weak_self](auto const& accepted_file_types, auto allow_multiple_files) { + LadybirdWebView* self = weak_self; auto* panel = [NSOpenPanel openPanel]; [panel setCanChooseFiles:YES]; [panel setCanChooseDirectories:NO]; @@ -750,7 +768,8 @@ - (void)setWebViewCallbacks self.select_dropdown = [[NSMenu alloc] initWithTitle:@"Select Dropdown"]; [self.select_dropdown setDelegate:self]; - m_web_view_bridge->on_request_select_dropdown = [self](Gfx::IntPoint content_position, i32 minimum_width, Vector items) { + m_web_view_bridge->on_request_select_dropdown = [weak_self](Gfx::IntPoint content_position, i32 minimum_width, Vector items) { + LadybirdWebView* self = weak_self; [self.select_dropdown removeAllItems]; self.select_dropdown.minimumWidth = minimum_width; @@ -814,63 +833,63 @@ - (void)setWebViewCallbacks [delegate cookieJar].update_cookie(cookie); }; - m_web_view_bridge->on_restore_window = [self]() { - [[self window] setIsMiniaturized:NO]; - [[self window] orderFront:nil]; + m_web_view_bridge->on_restore_window = [weak_self]() { + [[weak_self window] setIsMiniaturized:NO]; + [[weak_self window] orderFront:nil]; }; - m_web_view_bridge->on_reposition_window = [self](auto const& position) { - auto frame = [[self window] frame]; + m_web_view_bridge->on_reposition_window = [weak_self](auto const& position) { + auto frame = [[weak_self window] frame]; frame.origin = Ladybird::gfx_point_to_ns_point(position); - [[self window] setFrame:frame display:YES]; + [[weak_self window] setFrame:frame display:YES]; - return Ladybird::ns_point_to_gfx_point([[self window] frame].origin); + return Ladybird::ns_point_to_gfx_point([[weak_self window] frame].origin); }; - m_web_view_bridge->on_resize_window = [self](auto const& size) { - auto frame = [[self window] frame]; + m_web_view_bridge->on_resize_window = [weak_self](auto const& size) { + auto frame = [[weak_self window] frame]; frame.size = Ladybird::gfx_size_to_ns_size(size); - [[self window] setFrame:frame display:YES]; + [[weak_self window] setFrame:frame display:YES]; - return Ladybird::ns_size_to_gfx_size([[self window] frame].size); + return Ladybird::ns_size_to_gfx_size([[weak_self window] frame].size); }; - m_web_view_bridge->on_maximize_window = [self]() { + m_web_view_bridge->on_maximize_window = [weak_self]() { auto frame = [[NSScreen mainScreen] frame]; - [[self window] setFrame:frame display:YES]; + [[weak_self window] setFrame:frame display:YES]; - return Ladybird::ns_rect_to_gfx_rect([[self window] frame]); + return Ladybird::ns_rect_to_gfx_rect([[weak_self window] frame]); }; - m_web_view_bridge->on_minimize_window = [self]() { - [[self window] setIsMiniaturized:YES]; + m_web_view_bridge->on_minimize_window = [weak_self]() { + [[weak_self window] setIsMiniaturized:YES]; - return Ladybird::ns_rect_to_gfx_rect([[self window] frame]); + return Ladybird::ns_rect_to_gfx_rect([[weak_self window] frame]); }; - m_web_view_bridge->on_fullscreen_window = [self]() { - if (([[self window] styleMask] & NSWindowStyleMaskFullScreen) == 0) { - [[self window] toggleFullScreen:nil]; + m_web_view_bridge->on_fullscreen_window = [weak_self]() { + if (([[weak_self window] styleMask] & NSWindowStyleMaskFullScreen) == 0) { + [[weak_self window] toggleFullScreen:nil]; } - return Ladybird::ns_rect_to_gfx_rect([[self window] frame]); + return Ladybird::ns_rect_to_gfx_rect([[weak_self window] frame]); }; - m_web_view_bridge->on_received_source = [self](auto const& url, auto const& source) { + m_web_view_bridge->on_received_source = [weak_self](auto const& url, auto const& source) { auto html = WebView::highlight_source(url, source); - [self.observer onCreateNewTab:html - url:url - activateTab:Web::HTML::ActivateTab::Yes]; + [weak_self.observer onCreateNewTab:html + url:url + activateTab:Web::HTML::ActivateTab::Yes]; }; - m_web_view_bridge->on_theme_color_change = [self](auto color) { - self.backgroundColor = Ladybird::gfx_color_to_ns_color(color); + m_web_view_bridge->on_theme_color_change = [weak_self](auto color) { + weak_self.backgroundColor = Ladybird::gfx_color_to_ns_color(color); }; - m_web_view_bridge->on_find_in_page = [self](auto current_match_index, auto const& total_match_count) { - [self.observer onFindInPageResult:current_match_index + 1 - totalMatchCount:total_match_count]; + m_web_view_bridge->on_find_in_page = [weak_self](auto current_match_index, auto const& total_match_count) { + [weak_self.observer onFindInPageResult:current_match_index + 1 + totalMatchCount:total_match_count]; }; m_web_view_bridge->on_insert_clipboard_entry = [](auto const& data, auto const&, auto const& mime_type) { @@ -888,8 +907,8 @@ - (void)setWebViewCallbacks copy_data_to_clipboard(data, pasteboard_type); }; - m_web_view_bridge->on_audio_play_state_changed = [self](auto play_state) { - [self.observer onAudioPlayStateChange:play_state]; + m_web_view_bridge->on_audio_play_state_changed = [weak_self](auto play_state) { + [weak_self.observer onAudioPlayStateChange:play_state]; }; } diff --git a/Ladybird/AppKit/UI/LadybirdWebViewBridge.cpp b/Ladybird/AppKit/UI/LadybirdWebViewBridge.cpp index 5f7f874df0f62..5726b9f6827ab 100644 --- a/Ladybird/AppKit/UI/LadybirdWebViewBridge.cpp +++ b/Ladybird/AppKit/UI/LadybirdWebViewBridge.cpp @@ -39,7 +39,10 @@ WebViewBridge::WebViewBridge(Vector screen_rects, float de m_device_pixel_ratio = device_pixel_ratio; } -WebViewBridge::~WebViewBridge() = default; +WebViewBridge::~WebViewBridge() +{ + dbgln("WebViewBridge: Destroying WebViewBridge"); +} void WebViewBridge::set_device_pixel_ratio(float device_pixel_ratio) { diff --git a/Ladybird/AppKit/UI/Tab.mm b/Ladybird/AppKit/UI/Tab.mm index 19a18d2c91599..41f878b60583b 100644 --- a/Ladybird/AppKit/UI/Tab.mm +++ b/Ladybird/AppKit/UI/Tab.mm @@ -120,6 +120,11 @@ - (instancetype)init return self; } +- (void)dealloc +{ + dbgln("tab destroyed"); +} + #pragma mark - Public methods - (void)find:(id)sender diff --git a/Ladybird/AppKit/UI/TaskManager.mm b/Ladybird/AppKit/UI/TaskManager.mm index a72b5f134b617..32bb0f16e481f 100644 --- a/Ladybird/AppKit/UI/TaskManager.mm +++ b/Ladybird/AppKit/UI/TaskManager.mm @@ -6,7 +6,7 @@ #include #include -#include +#include #import #import @@ -77,8 +77,8 @@ - (instancetype)init - (void)updateStatistics { - WebView::ProcessManager::the().update_all_processes(); - [self.web_view loadHTML:WebView::ProcessManager::the().generate_html()]; + WebView::Application::the().update_process_statistics(); + [self.web_view loadHTML:WebView::Application::the().generate_process_statistics_html()]; } @end diff --git a/Ladybird/AppKit/main.mm b/Ladybird/AppKit/main.mm index 9bf170dcc8de2..c4c10c4b5e428 100644 --- a/Ladybird/AppKit/main.mm +++ b/Ladybird/AppKit/main.mm @@ -13,10 +13,10 @@ #include #include #include +#include #include #include #include -#include #include #include #include @@ -77,7 +77,7 @@ static void open_urls_from_client(Vector const& raw_urls, NewWindow Application* application = [Application sharedApplication]; Core::EventLoopManager::install(*new Ladybird::CFEventLoopManager); - Core::EventLoop event_loop; + WebView::Application web_view_app(arguments.argc, arguments.argv); platform_init(); @@ -118,16 +118,14 @@ static void open_urls_from_client(Vector const& raw_urls, NewWindow open_urls_from_client(raw_urls, NewWindow::Yes); }; - WebView::ProcessManager::initialize(); - auto mach_port_server = make(); set_mach_server_name(mach_port_server->server_port_name()); - mach_port_server->on_receive_child_mach_port = [](auto pid, auto port) { - WebView::ProcessManager::the().add_process(pid, move(port)); + mach_port_server->on_receive_child_mach_port = [&web_view_app](auto pid, auto port) { + web_view_app.set_process_mach_port(pid, move(port)); }; mach_port_server->on_receive_backing_stores = [](Ladybird::MachPortServer::BackingStoresMessage message) { - auto view = WebView::WebContentClient::view_for_pid_and_page_id(message.pid, message.page_id); - view->did_allocate_iosurface_backing_stores(message.front_backing_store_id, move(message.front_backing_store_port), message.back_backing_store_id, move(message.back_backing_store_port)); + if (auto view = WebView::WebContentClient::view_for_pid_and_page_id(message.pid, message.page_id); view.has_value()) + view->did_allocate_iosurface_backing_stores(message.front_backing_store_id, move(message.front_backing_store_port), message.back_backing_store_id, move(message.back_backing_store_port)); }; auto database = TRY(WebView::Database::create()); @@ -158,5 +156,5 @@ static void open_urls_from_client(Vector const& raw_urls, NewWindow [NSApp setDelegate:delegate]; - return event_loop.exec(); + return web_view_app.exec(); } diff --git a/Ladybird/HelperProcess.cpp b/Ladybird/HelperProcess.cpp index 48b77a879f551..26afaef75c061 100644 --- a/Ladybird/HelperProcess.cpp +++ b/Ladybird/HelperProcess.cpp @@ -8,7 +8,7 @@ #include "Utilities.h" #include #include -#include +#include template static ErrorOr> launch_server_process( @@ -45,7 +45,7 @@ static ErrorOr> launch_server_process( if constexpr (requires { process.client->set_pid(pid_t {}); }) process.client->set_pid(process.process.pid()); - WebView::ProcessManager::the().add_process(WebView::process_type_from_name(server_name), process.process.pid()); + WebView::Application::the().add_child_process(WebView::Process { WebView::process_type_from_name(server_name), process.client, move(process.process) }); if (enable_callgrind_profiling == Ladybird::EnableCallgrindProfiling::Yes) { dbgln(); diff --git a/Userland/Libraries/LibCore/EventLoopImplementationUnix.cpp b/Userland/Libraries/LibCore/EventLoopImplementationUnix.cpp index f630c1139e4e4..6680a1f6e691e 100644 --- a/Userland/Libraries/LibCore/EventLoopImplementationUnix.cpp +++ b/Userland/Libraries/LibCore/EventLoopImplementationUnix.cpp @@ -491,7 +491,6 @@ struct SignalHandlersInfo { }; static Singleton s_signals; -template inline SignalHandlersInfo* signals_info() { return s_signals.ptr(); @@ -518,7 +517,7 @@ void EventLoopImplementationUnix::notify_forked_and_in_child() thread_data.notifier_by_ptr.clear(); thread_data.notifier_by_index.clear(); thread_data.initialize_wake_pipe(); - if (auto* info = signals_info()) { + if (auto* info = signals_info()) { info->signal_handlers.clear(); info->next_signal_id = 0; } diff --git a/Userland/Libraries/LibCore/Forward.h b/Userland/Libraries/LibCore/Forward.h index 6805d60ba6d05..d9455edf896a1 100644 --- a/Userland/Libraries/LibCore/Forward.h +++ b/Userland/Libraries/LibCore/Forward.h @@ -31,6 +31,7 @@ class MimeData; class NetworkJob; class NetworkResponse; class Notifier; +class Process; class ProcessStatisticsReader; class Resource; class ResourceImplementation; diff --git a/Userland/Libraries/LibCore/Platform/ProcessInfo.h b/Userland/Libraries/LibCore/Platform/ProcessInfo.h index 937b1f64c8676..d6a97237340b8 100644 --- a/Userland/Libraries/LibCore/Platform/ProcessInfo.h +++ b/Userland/Libraries/LibCore/Platform/ProcessInfo.h @@ -20,8 +20,6 @@ struct ProcessInfo { { } - virtual ~ProcessInfo() = default; - pid_t pid { 0 }; u64 memory_usage_bytes { 0 }; @@ -30,12 +28,6 @@ struct ProcessInfo { u64 time_spent_in_process { 0 }; #if defined(AK_OS_MACH) - ProcessInfo(pid_t pid, Core::MachPort&& port) - : pid(pid) - , child_task_port(move(port)) - { - } - Core::MachPort child_task_port; #endif }; diff --git a/Userland/Libraries/LibCore/Platform/ProcessStatistics.h b/Userland/Libraries/LibCore/Platform/ProcessStatistics.h index f3b54846bf0b9..ccd51a7313259 100644 --- a/Userland/Libraries/LibCore/Platform/ProcessStatistics.h +++ b/Userland/Libraries/LibCore/Platform/ProcessStatistics.h @@ -15,11 +15,11 @@ namespace Core::Platform { struct ProcessStatistics { - template + template void for_each_process(Callback&& callback) { for (auto& process : processes) - callback(verify_cast(*process)); + callback(*process); } u64 total_time_scheduled { 0 }; diff --git a/Userland/Libraries/LibCore/Process.cpp b/Userland/Libraries/LibCore/Process.cpp index 65d0c8fb095fe..11f988b95f8d1 100644 --- a/Userland/Libraries/LibCore/Process.cpp +++ b/Userland/Libraries/LibCore/Process.cpp @@ -64,6 +64,13 @@ struct ArgvList { } }; +Process Process::current() +{ + auto p = Process { getpid() }; + p.m_should_disown = false; + return p; +} + ErrorOr Process::spawn(ProcessSpawnOptions const& options) { #define CHECK(invocation) \ diff --git a/Userland/Libraries/LibCore/Process.h b/Userland/Libraries/LibCore/Process.h index 7b71fcb3115f6..ebb2ca54b074d 100644 --- a/Userland/Libraries/LibCore/Process.h +++ b/Userland/Libraries/LibCore/Process.h @@ -74,6 +74,7 @@ class Process { } static ErrorOr spawn(ProcessSpawnOptions const& options); + static Process current(); // FIXME: Make the following 2 functions return Process instance or delete them. static ErrorOr spawn(StringView path, ReadonlySpan arguments, ByteString working_directory = {}, KeepAsChild keep_as_child = KeepAsChild::No); diff --git a/Userland/Libraries/LibProtocol/RequestClient.cpp b/Userland/Libraries/LibProtocol/RequestClient.cpp index e2b3c60518f32..b214f53a5f7b1 100644 --- a/Userland/Libraries/LibProtocol/RequestClient.cpp +++ b/Userland/Libraries/LibProtocol/RequestClient.cpp @@ -19,8 +19,7 @@ RequestClient::~RequestClient() = default; void RequestClient::die() { // FIXME: Gracefully handle this, or relaunch and reconnect to RequestServer. - warnln("\033[31;1mLost connection to RequestServer\033[0m"); - VERIFY_NOT_REACHED(); + warnln("\033[31;1m {} Lost connection to RequestServer\033[0m", getpid()); } void RequestClient::ensure_connection(URL::URL const& url, ::RequestServer::CacheLevel cache_level) diff --git a/Userland/Libraries/LibWebView/Application.cpp b/Userland/Libraries/LibWebView/Application.cpp new file mode 100644 index 0000000000000..058758c72e74f --- /dev/null +++ b/Userland/Libraries/LibWebView/Application.cpp @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2024, Andrew Kaster + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include + +namespace WebView { + +Application* Application::s_the = nullptr; + +Application::Application(int, char**) +{ + VERIFY(!s_the); + s_the = this; + + m_process_manager.on_process_exited = [this](Process&& process) { + dbgln("ProcessManager: Process{}: {} ({}) exited", process.pid(), process.title().value_or("Untitled"_string), process_name_from_type(process.type())); + process_did_exit(move(process)); + }; +} + +Application::~Application() +{ + s_the = nullptr; +} + +int Application::exec() +{ + int ret = m_event_loop.exec(); + m_in_shutdown = true; + return ret; +} + +void Application::add_child_process(WebView::Process&& process) +{ + auto& p = m_process_manager.add_process(move(process)); + + // Cache these single-instance processes + if (p.type() == ProcessType::RequestServer) { + m_request_server_process = p; + } else if (p.type() == ProcessType::ImageDecoder) { + m_image_decoder_process = p; + } +} + +#if defined(AK_OS_MACH) +void Application::set_process_mach_port(pid_t pid, Core::MachPort&& port) +{ + m_process_manager.set_process_mach_port(pid, move(port)); +} +#endif + +Optional Application::find_process(pid_t pid) +{ + return m_process_manager.find_process(pid); +} + +void Application::update_process_statistics() +{ + m_process_manager.update_all_process_statistics(); +} + +String Application::generate_process_statistics_html() +{ + return m_process_manager.generate_html(); +} + +void Application::process_did_exit(Process&& process) +{ + if (m_in_shutdown) + return; + if (m_image_decoder_process.has_value() && &process == &m_image_decoder_process.value()) { + dbgln("FIXME: Restart image decoder"); + } + if (m_request_server_process.has_value() && &process == &m_request_server_process.value()) { + dbgln("FIXME: Restart request server"); + } + if (process.type() == ProcessType::WebContent) { + if (auto client = process.client(); client.has_value()) { + dbgln("Restart WebContent process"); + if (client->on_web_content_process_crash) + client->on_web_content_process_crash(); + } + } + + dbgln("bye {}", process.pid()); +} + +} + +#if 0 +m_impl->image_decoder_client = nullptr; +if (auto err = this->launch_image_decoder(); err.is_error()) { + dbgln("Failed to restart image decoder: {}", err.error()); + VERIFY_NOT_REACHED(); +} + +auto num_clients = WebView::WebContentClient::client_count(); +auto new_sockets = m_impl->image_decoder_client->send_sync_but_allow_failure(num_clients); +if (!new_sockets || new_sockets->sockets().size() == 0) { + dbgln("Failed to connect {} new clients to ImageDecoder", num_clients); + VERIFY_NOT_REACHED(); +} + +WebView::WebContentClient::for_each_client([sockets = new_sockets->take_sockets()](WebView::WebContentClient& client) mutable { + client.async_connect_to_image_decoder(sockets.take_last()); + return IterationDecision::Continue; +}); +#endif diff --git a/Userland/Libraries/LibWebView/Application.h b/Userland/Libraries/LibWebView/Application.h new file mode 100644 index 0000000000000..d2504950f988d --- /dev/null +++ b/Userland/Libraries/LibWebView/Application.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2024, Andrew Kaster + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include + +namespace WebView { + +class Application { + AK_MAKE_NONCOPYABLE(Application); + +public: + Application(int argc, char** argv); + virtual ~Application(); + + int exec(); + + static Application& the() { return *s_the; } + + Core::EventLoop& event_loop() { return m_event_loop; } + + void add_child_process(Process&&); + + // FIXME: Should these methods be part of Application, instead of deferring to ProcessManager? +#if defined(AK_OS_MACH) + void set_process_mach_port(pid_t, Core::MachPort&&); +#endif + Optional find_process(pid_t); + + // FIXME: Should we just expose the ProcessManager via a getter? + void update_process_statistics(); + String generate_process_statistics_html(); + +protected: + virtual void process_did_exit(Process&&); + +private: + static Application* s_the; + + Core::EventLoop m_event_loop; + + Optional m_request_server_process; + Optional m_image_decoder_process; + + ProcessManager m_process_manager; + bool m_in_shutdown { false }; +}; + +} diff --git a/Userland/Libraries/LibWebView/CMakeLists.txt b/Userland/Libraries/LibWebView/CMakeLists.txt index ba3bd70ae620c..56358b807e345 100644 --- a/Userland/Libraries/LibWebView/CMakeLists.txt +++ b/Userland/Libraries/LibWebView/CMakeLists.txt @@ -1,12 +1,14 @@ include(${SerenityOS_SOURCE_DIR}/Meta/CMake/public_suffix.cmake) set(SOURCES + Application.cpp Attribute.cpp ChromeProcess.cpp CookieJar.cpp Database.cpp InspectorClient.cpp ProcessHandle.cpp + Process.cpp ProcessManager.cpp RequestServerAdapter.cpp SearchEngine.cpp diff --git a/Userland/Libraries/LibWebView/Process.cpp b/Userland/Libraries/LibWebView/Process.cpp new file mode 100644 index 0000000000000..49ff8480d73e6 --- /dev/null +++ b/Userland/Libraries/LibWebView/Process.cpp @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2024, Andrew Kaster + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include + +namespace WebView { + +Process::Process(ProcessType type, RefPtr connection, Core::Process process) + : m_process(move(process)) + , m_type(type) + , m_connection(move(connection)) +{ +} + +Process::~Process() +{ + if (m_connection) + m_connection->shutdown(); +} + +} diff --git a/Userland/Libraries/LibWebView/Process.h b/Userland/Libraries/LibWebView/Process.h new file mode 100644 index 0000000000000..ae9346c7dd040 --- /dev/null +++ b/Userland/Libraries/LibWebView/Process.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2024, Andrew Kaster + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace WebView { + +class Process { + AK_MAKE_NONCOPYABLE(Process); + AK_MAKE_DEFAULT_MOVABLE(Process); + +public: + Process(ProcessType type, RefPtr connection, Core::Process process); + ~Process(); + + ProcessType type() const { return m_type; } + Optional const& title() const { return m_title; } + void set_title(Optional title) { m_title = move(title); } + + template + Optional client() + { + if (auto strong_connection = m_connection.strong_ref()) + return verify_cast(*strong_connection); + return {}; + } + + pid_t pid() const { return m_process.pid(); } + +private: + Core::Process m_process; + ProcessType m_type; + Optional m_title; + WeakPtr m_connection; +}; + +} diff --git a/Userland/Libraries/LibWebView/ProcessInfo.h b/Userland/Libraries/LibWebView/ProcessInfo.h deleted file mode 100644 index c48cb2a1da506..0000000000000 --- a/Userland/Libraries/LibWebView/ProcessInfo.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2024, Andrew Kaster - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include - -#if defined(AK_OS_MACH) -# include -#endif - -namespace WebView { - -enum class ProcessType { - Chrome, - WebContent, - WebWorker, - RequestServer, - ImageDecoder, -}; - -struct ProcessInfo : public Core::Platform::ProcessInfo { - using Core::Platform::ProcessInfo::ProcessInfo; - - ProcessInfo(ProcessType type, pid_t pid) - : Core::Platform::ProcessInfo(pid) - , type(type) - { - } - - ProcessType type { ProcessType::WebContent }; - Optional title; -}; - -} diff --git a/Userland/Libraries/LibWebView/ProcessManager.cpp b/Userland/Libraries/LibWebView/ProcessManager.cpp index 33d2c62c48c86..c51c5a1057603 100644 --- a/Userland/Libraries/LibWebView/ProcessManager.cpp +++ b/Userland/Libraries/LibWebView/ProcessManager.cpp @@ -12,8 +12,6 @@ namespace WebView { -static sig_atomic_t s_received_sigchld = 0; - ProcessType process_type_from_name(StringView name) { if (name == "Chrome"sv) @@ -49,96 +47,74 @@ StringView process_name_from_type(ProcessType type) } ProcessManager::ProcessManager() + : on_process_exited([](Process&&) {}) { -} - -ProcessManager::~ProcessManager() -{ -} - -ProcessManager& ProcessManager::the() -{ - static ProcessManager s_the; - return s_the; -} - -void ProcessManager::initialize() -{ - // FIXME: Should we change this to call EventLoop::register_signal? - // Note that only EventLoopImplementationUnix has a working register_signal - - struct sigaction action { }; - action.sa_flags = SA_RESTART; - action.sa_sigaction = [](int, auto*, auto) { - s_received_sigchld = 1; - }; + m_signal_handle = Core::EventLoop::register_signal(SIGCHLD, [this](int) { + auto result = Core::System::waitpid(-1, WNOHANG); + while (!result.is_error() && result.value().pid > 0) { + auto& [pid, status] = result.value(); + if (WIFEXITED(status) || WIFSIGNALED(status)) { + if (auto process = remove_process(pid); process.has_value()) + on_process_exited(process.release_value()); + } + result = Core::System::waitpid(-1, WNOHANG); + } + }); - MUST(Core::System::sigaction(SIGCHLD, &action, nullptr)); + add_process(Process(WebView::ProcessType::Chrome, nullptr, Core::Process::current())); - the().add_process(WebView::ProcessType::Chrome, getpid()); #ifdef AK_OS_MACH auto self_send_port = mach_task_self(); auto res = mach_port_mod_refs(mach_task_self(), self_send_port, MACH_PORT_RIGHT_SEND, +1); VERIFY(res == KERN_SUCCESS); - the().add_process(getpid(), Core::MachPort::adopt_right(self_send_port, Core::MachPort::PortRight::Send)); + set_process_mach_port(getpid(), Core::MachPort::adopt_right(self_send_port, Core::MachPort::PortRight::Send)); #endif } -ProcessInfo* ProcessManager::find_process(pid_t pid) +ProcessManager::~ProcessManager() { - if (auto existing_process = m_statistics.processes.find_if([&](auto& info) { return info->pid == pid; }); !existing_process.is_end()) - return verify_cast(existing_process->ptr()); + Core::EventLoop::unregister_signal(m_signal_handle); +} - return nullptr; +Optional ProcessManager::find_process(pid_t pid) +{ + return m_processes.get(pid); } -void ProcessManager::add_process(ProcessType type, pid_t pid) +Process& ProcessManager::add_process(WebView::Process&& process) { Threading::MutexLocker locker { m_lock }; - if (auto* existing_process = find_process(pid)) { - existing_process->type = type; - return; - } - m_statistics.processes.append(make(type, pid)); + + auto pid = process.pid(); + auto& result = m_processes.ensure(pid, [p = move(process)]() mutable { return move(p); }); + m_statistics.processes.append(make(pid)); + return result; } #if defined(AK_OS_MACH) -void ProcessManager::add_process(pid_t pid, Core::MachPort&& port) +void ProcessManager::set_process_mach_port(pid_t pid, Core::MachPort&& port) { Threading::MutexLocker locker { m_lock }; - if (auto* existing_process = find_process(pid)) { - existing_process->child_task_port = move(port); - return; + for (auto const& info : m_statistics.processes) { + if (info->pid == pid) { + info->child_task_port = move(port); + return; + } } - m_statistics.processes.append(make(pid, move(port))); } #endif -void ProcessManager::remove_process(pid_t pid) +Optional ProcessManager::remove_process(pid_t pid) { Threading::MutexLocker locker { m_lock }; m_statistics.processes.remove_first_matching([&](auto const& info) { - if (info->pid == pid) { - return true; - } - return false; + return (info->pid == pid); }); + return m_processes.take(pid); } -void ProcessManager::update_all_processes() +void ProcessManager::update_all_process_statistics() { - if (s_received_sigchld) { - s_received_sigchld = 0; - auto result = Core::System::waitpid(-1, WNOHANG); - while (!result.is_error() && result.value().pid > 0) { - auto& [pid, status] = result.value(); - if (WIFEXITED(status) || WIFSIGNALED(status)) { - remove_process(pid); - } - result = Core::System::waitpid(-1, WNOHANG); - } - } - Threading::MutexLocker locker { m_lock }; (void)update_process_statistics(m_statistics); } @@ -198,12 +174,13 @@ String ProcessManager::generate_html() )"sv); - m_statistics.for_each_process([&](auto const& process) { + m_statistics.for_each_process([&](auto const& process) { builder.append(""sv); builder.append(""sv); - builder.append(WebView::process_name_from_type(process.type)); - if (process.title.has_value()) - builder.appendff(" - {}", escape_html_entities(*process.title)); + auto& process_handle = this->find_process(process.pid).value(); + builder.append(WebView::process_name_from_type(process_handle.type())); + if (process_handle.title().has_value()) + builder.appendff(" - {}", escape_html_entities(*process_handle.title())); builder.append(""sv); builder.append(""sv); builder.append(MUST(String::number(process.pid))); diff --git a/Userland/Libraries/LibWebView/ProcessManager.h b/Userland/Libraries/LibWebView/ProcessManager.h index 87a5ab1ab87f4..ff387dc9e1635 100644 --- a/Userland/Libraries/LibWebView/ProcessManager.h +++ b/Userland/Libraries/LibWebView/ProcessManager.h @@ -12,7 +12,8 @@ #include #include #include -#include +#include +#include namespace WebView { @@ -20,26 +21,29 @@ ProcessType process_type_from_name(StringView); StringView process_name_from_type(ProcessType type); class ProcessManager { + AK_MAKE_NONCOPYABLE(ProcessManager); + public: - static ProcessManager& the(); - static void initialize(); + ProcessManager(); + ~ProcessManager(); - void add_process(WebView::ProcessType, pid_t); - void remove_process(pid_t); - ProcessInfo* find_process(pid_t); + Process& add_process(Process&&); + Optional remove_process(pid_t); + Optional find_process(pid_t); #if defined(AK_OS_MACH) - void add_process(pid_t, Core::MachPort&&); + void set_process_mach_port(pid_t, Core::MachPort&&); #endif - void update_all_processes(); + void update_all_process_statistics(); String generate_html(); -private: - ProcessManager(); - ~ProcessManager(); + Function on_process_exited; +private: Core::Platform::ProcessStatistics m_statistics; + HashMap m_processes; + int m_signal_handle { -1 }; Threading::Mutex m_lock; }; diff --git a/Userland/Libraries/LibWebView/ProcessType.h b/Userland/Libraries/LibWebView/ProcessType.h new file mode 100644 index 0000000000000..7ab98c8e20d40 --- /dev/null +++ b/Userland/Libraries/LibWebView/ProcessType.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2024, Andrew Kaster + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include + +namespace WebView { + +enum class ProcessType : u8 { + Chrome, + WebContent, + WebWorker, + RequestServer, + ImageDecoder, +}; + +} diff --git a/Userland/Libraries/LibWebView/ViewImplementation.cpp b/Userland/Libraries/LibWebView/ViewImplementation.cpp index 7987a6b83bfdd..da4856382bfd1 100644 --- a/Userland/Libraries/LibWebView/ViewImplementation.cpp +++ b/Userland/Libraries/LibWebView/ViewImplementation.cpp @@ -22,6 +22,7 @@ namespace WebView { ViewImplementation::ViewImplementation() { + dbgln("created WebView::ViewImplementation({})", this); m_repeated_crash_timer = Core::Timer::create_single_shot(1000, [this] { // Reset the "crashing a lot" counter after 1 second in case we just // happen to be visiting crashy websites a lot. @@ -40,6 +41,7 @@ ViewImplementation::ViewImplementation() ViewImplementation::~ViewImplementation() { + dbgln("Destroying WebView::ViewImplementation({})", this); if (m_client_state.client) m_client_state.client->unregister_view(m_client_state.page_index); } diff --git a/Userland/Libraries/LibWebView/WebContentClient.cpp b/Userland/Libraries/LibWebView/WebContentClient.cpp index 3b36a777bcf22..0a45e2423323b 100644 --- a/Userland/Libraries/LibWebView/WebContentClient.cpp +++ b/Userland/Libraries/LibWebView/WebContentClient.cpp @@ -5,6 +5,7 @@ */ #include "WebContentClient.h" +#include "Application.h" #include "ProcessManager.h" #include "ViewImplementation.h" #include @@ -25,19 +26,21 @@ Optional WebContentClient::view_for_pid_and_page_id(pid_t p WebContentClient::WebContentClient(NonnullOwnPtr socket, ViewImplementation& view) : IPC::ConnectionToServer(*this, move(socket)) { + dbgln("hello, new webcontent client {}", this); s_clients.set(this); m_views.set(0, &view); } WebContentClient::~WebContentClient() { + dbgln("bye from webcontent client {}", this); s_clients.remove(this); } void WebContentClient::die() { - VERIFY(on_web_content_process_crash); - on_web_content_process_crash(); + // VERIFY(on_web_content_process_crash); + // on_web_content_process_crash(); } void WebContentClient::register_view(u64 page_id, ViewImplementation& view) @@ -48,7 +51,12 @@ void WebContentClient::register_view(u64 page_id, ViewImplementation& view) void WebContentClient::unregister_view(u64 page_id) { + dbgln("unregsistering view for page_id: {}", page_id); m_views.remove(page_id); + if (m_views.is_empty()) { + dbgln("No more views, disconnecting process re-launch logic"); + on_web_content_process_crash = nullptr; + } } void WebContentClient::did_paint(u64 page_id, Gfx::IntRect const& rect, i32 bitmap_id) @@ -59,8 +67,8 @@ void WebContentClient::did_paint(u64 page_id, Gfx::IntRect const& rect, i32 bitm void WebContentClient::did_start_loading(u64 page_id, URL::URL const& url, bool is_redirect) { - if (auto* process = WebView::ProcessManager::the().find_process(m_process_handle.pid)) - process->title.clear(); + if (auto process = WebView::Application::the().find_process(m_process_handle.pid); process.has_value()) + process->set_title(OptionalNone {}); if (auto view = view_for_page_id(page_id); view.has_value()) { view->set_url({}, url); @@ -143,8 +151,8 @@ void WebContentClient::did_layout(u64 page_id, Gfx::IntSize content_size) void WebContentClient::did_change_title(u64 page_id, ByteString const& title) { - if (auto* process = WebView::ProcessManager::the().find_process(m_process_handle.pid)) - process->title = MUST(String::from_byte_string(title)); + if (auto process = WebView::Application::the().find_process(m_process_handle.pid); process.has_value()) + process->set_title(MUST(String::from_byte_string(title))); if (auto view = view_for_page_id(page_id); view.has_value()) { if (!view->on_title_change)