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.
By migrating the debug menu to LibWebView, the AppKit and Qt UIs are now
in sync - the AppKit UI was previously missing some actions.
Further, this inadvertently fixes bugs around applying debug settings to
new web views, especially across site-isolated processes. We were
previously not applying settings appropriately; this now "just works" in
the LibWebView infra.
This migrates all duplicated context menus from the UIs to LibWebView.
The context menu actions are now largely handled directly in LibWebView,
with some UI-specific callbacks added to display e.g. confirmation
dialogs.
Actions that only ever apply to a specific web view are stored on the
ViewImplementation itself. Actions that need to be dynamically applied
to the active web view are stored on the Application.
We currently duplicate a lot of code to handle application/context menus
and actions. The goal here is to hold the data for the menus and actions
in LibWebView. Each UI will then be able to generate menus from the data
on-the-fly.
The structures added here are meant to support generic and checkable
actions, action groups, submenus, etc.
When we manually enter a new URL and hit enter, the web view gets
focused. But when the URL changes for other reasons, such as starting
Ladybird with a URL argument, the location field was still focused.
The faux position we created here is adjusted by the device pixel ratio
later on, which would invoke integer overflow on screens with a DPR
greater than 1.
Instead of creating special data for a mouse move event, let's just add
an explicit leave event handler.
Previously, when the mouse left the WebView, the currently hovered node
would remain hovered (including the scroll bar). This felt a bit awkward
and is not how other browsers behave.
Currently the window resize events are used to resize the webview.
But when extra window items appear, for example: search or DevTools
Bar then the webview is clipped out of the window. This also happens
when the tab bar is opened and closed. Listening to layout events
resolves these clipping issues completely.
We currently have a single IPC to set clipboard data. We will also need
an IPC to retrieve that data from the UI. This defines system clipboard
data in LibWeb to handle this transfer, and adds the IPC to provide it.
This is to prepare for custom search engines. If we use AK::format, it
would be trivial for a user (or bad actor) to come up with a template
search engine URL that ultimately crashes the browser due to internal
assertions in AK::format. For example:
https://example.com/crash={1}
Rather than coming up with a complicated pre-format validator, let's
just not use AK::format. Custom URLs will signify their template query
parameters with "%s". So we can do the same with our built-in engines.
When it comes time to format the URL, we will do a simple string
replacement.
This seems to have broken in some recent-ish AppKit update. When we add
the status label to the view hierarchy / change its visibility state,
the NSApp is resetting the cursor to the standard cursor. By overriding
the cursorUpdate method to do nothing, we prevent this from happening.