Previously, if search was disabled, entering non-URL text would just
silently drop the search query (and on Qt, we would reload the current
URL). We now detect that the query did not result in a navigation and
load an error page instead, which directs the user to enable search.
Tabs opened from links on AppKit can be created before their URL is
loaded. That left background open-url tabs with the location field as
their stored responder, so switching to them later restored address-bar
focus instead of web content focus.
Track each tab's preferred responder, restore it when AppKit makes
the tab key, and mark page-backed open-url tabs to prefer the web view.
Blank new-tab pages still keep the location field focused.
Synthesize an extra AutocompleteSuggestion at the top of the Search
Suggestions section whenever there is a configured search engine and
the typed query is not URL-shaped.
Use the query as the row's primary text, carry a "Search with <engine>"
subtitle, and render that subtitle in the AppKit and Qt popups so the
explicit search fallback stays visible and readable even when history
fills the list.
Render AutocompleteSuggestion rows with section headers, favicons,
titles, and secondary text in the child-window popup instead of just
plain strings.
Move the AppKit popup and inline completion onto the shared suggestion
model, and share the base64 PNG decoding helper with the application
menu icon loading path.
Replace the AppKit popover because it becomes key and steals focus from
the location field while suggestions are visible. Use a borderless
child window anchored to the toolbar item instead, and dismiss it on
resize or focus changes so the browser chrome stays predictable.
Teach LibWebView autocomplete to query HistoryStore before falling back
to remote engines and move the wiring out of the AppKit frontend.
Refine matching so scheme and www. boilerplate do not dominate results,
short title and substring queries stay quiet, and history tracing can
explain what the ranking code is doing.
This page renders the bookmarks as a tree and hook context menu events
up to the UI's bookmarks bar context menus to allow editing bookmarks.
Users can also drag-and-drop bookmark items around.
Generalize the backing store sharing abstraction into SharedImage, which
represents shared GPU memory independently of Skia and can be used to
share memory between different processes or different GPU contexts.
AppKit doesn't need the bookmarks bar reorganization that Qt needed to
handle more mouse events. But let's rename these member fields to match
what they are now called in Qt.
Unfortunately, the NSMenu-based bookmarks implementation cannot support
context menus within arbitrary folders. The NSMenu consumes the right-
click events during its own menu tracking, and we are not able to see
those events from our interface.
This patch replaces the NSMenu for folders with a custom NSPopup. This
implementation makes it much easier to handle context menus.
We initially create the search field with no frame or size constraints.
The causes AppKit to log verbose warnings at start up. Here, we set an
intrinsic size initially, which becomes overridden once the window has
an actual size.
Changing Ctrl+click to a secondary click is incorrect. It prevents
sites from using Ctrl+click themselves. Instead, just maybe open the
context menu in mousedown for primary clicks with Ctrl pressed.
Fixes the autofire shortcut not working in the Humble Mozilla Bundle's
asm.js FTL.
This moves normal/double/triple click checking into WebContent, the
client only has to send a click count in order to activate a double
or triple click in the content. This means that the AppKit UI will no
longer fire multiple double clicks when clicking in place more than 3
times. This matches the behavior of other browsers on macOS.
We will now also fire the click event regardless of whether a dblclick
event will follow, as the spec requires.
When an element is fullscreened, we now hide the application menu and
location bar. The user can hover over the top of the window to make
them show. When fullscreen is requested for the application directly
from the UI, we do not hide the location bar. This matches Safari's
behavior.
We were incorrectly calling presentMetalFrame while force-cpu-painting
was enabled, so updateLayer never had any chance to be called.
However, in addition to that, it turned out that there's a subclass of
CALayer that is used by NSView by default which cannot be created in a
makeBackingLayer override, so updateLayer was never going to be called
anyway. In order to update the layer at the requisite time, a new
LadybirdWebViewContentLayer had to be added to simply call the delegate
on our view.
Setting the contentsRect on the layer was also incorrect, and caused
the contents to shift and stretch until WebContent's backing stores
shrank to fit the new view size.
The set_viewport_size and set_device_pixel_ratio IPC messages were sent
separately, potentially causing a race condition when the DPR changes
(e.g. moving a window between screens): the DPR message would arrive
and use a stale viewport size, computing a temporarily wrong CSS
viewport. Combine both into a single set_viewport IPC that updates the
device viewport size and DPR together.
Instead of copying the Bitmap that wraps the IOSurface, we can just
present the IOSurface directly. This significantly reduces CPU usage in
the UI process, particularly at high refresh rates such as 120Hz where
it would saturate a full CPU core.
This is done by using CAMetalLayer and blitting the IOSurface to the
next drawable buffer, which handles triple buffering, locking the
IOSurface and vsync automatically. This also allows the Metal HUD to
work, but the only accurate stat is the frame intervals/FPS because
it's in the UI layer, not WebContent. However, that's still useful
to detect frame drops.
When triple clicking on text, we should select the entire paragraph, or
entire line in <input>s and <textarea>s. If the mouse button is held
down and the user starts dragging, the selection expands with additional
paragraphs or lines.
This expands on the work of Kai Wildberger (PR #7681) but was adjusted
for the work that happened previously to support double click + drag
moves and includes triple click support for our Qt UI.
Co-authored-by: Kai Wildberger <kiawildberger@gmail.com>
This introduces a simple FileDownloader to download files in the UI
process from RequestServer. We use this to download the context menu
image - this download is likely to hit the disk cache.
When the user focuses the address bar and presses Escape, the original
URL is now restored. Previously, the address bar would show whatever
text the user had typed, or be empty if they had cleared it.
Clicking outside the address bar keeps the typed text (matching
Chrome/Firefox behavior) — only Escape restores the original URL.
Fixes https://github.com/LadybirdBrowser/ladybird/issues/7264
When a shortcut is an alternative key, macOS first fires a key event for
the primary key. Then if it is not handled, it fires an event for the
alternative key. For example, we see these two events in a row when we
press cmd and =/+:
NSEvent: type=KeyDown flags=0x100108 chars="=" keyCode=25
NSEvent: type=KeyDown flags=0x100108 chars="+" keyCode=24
For dead key processing, we don't handle these events right away. By the
time we get to doCommandBySelector, when we call [NSApp currentEvent],
we see the following events:
NSEvent: type=KeyDown flags=0x100108 chars="=" keyCode=24
NSEvent: type=AppDefined flags=0
The AppDefined event is internally posted by our event loop. So it seems
we cannot rely on currentEvent being the key-down event we are looking
for.
Instead, we can store the key-down event that we last saw.
When a new tab is created, the location bar should automatically
receive keyboard focus so users can immediately start typing a URL.
However, the onURLChange callback was stealing focus back to the
web view when loading the new tab page.
This fix:
1. Calls focusLocationToolbarItem when activating a new tab
2. Prevents onURLChange from stealing focus when loading the new
tab page URL
Fixes#1512
The autocomplete popover on macOS was stealing focus from the location
bar when suggestions were displayed. This change saves the current
first responder before showing the popover and restores it immediately
after, ensuring the user can continue typing without interruption.
When trying to build Ladybird on macOS 14.3, it fails with the error:
```
No visible @interface for 'NSToolbar' declares the selector
'setAllowsDisplayModeCustomization:' (clang arc_may_not_respond)
```
This is caused by macOS < 15 not having the @interface definition for
in NSToolbar for setAllowsUserCustomization:(BOOL).
By dynamically calling the method, we can avoid the error altogether.
Clipboard handling largely has nothing to do with the individual web
views. Rather, we interact with the system clipboard at the application
level. So let's move these implementations to the Application.
This lets us avoid each UI needing to handle link clicks directly, and
lets actions stored in LibWebView avoid awkwardly going through the link
click callbacks to open URLs.
On macOS Tahoe, it is now recommended to show menu item icons. We use
system symbols for this now. Symbols do not have constant variable names
and must be found via the SF Symbols app.
The symbols chosen here were to match Safari as close as possible.
On macOS Tahoe, the zoom button's border is visible when the button
itself is hidden. This feels like a macOS bug, but for now let's hide
the borders as well.