FilteringProxyModel is a narrowing projection of its parent model with
a filter applied. That means that updates of FilteringProxyModel should
not propagate to its parent model, but the opposite - updates happening
in the parent model should "trickle down" and trigger an update of the
filtering model.
In particular, malicious programs used to be able to set arbitrary
values as "format", which could cause UB (most likely a crash).
Furthermore, we do not transmit palette data, so an application sending
an indexed bitmap cannot possibly expect the other side to receive a
useful image. Therefore, we refuse to build a bitmap.
The clipboard cannot reasonably contain the empty string. The clipboard
can be empty (i.e. cleared), sure, but that this check was about whether
the clipboard contained the empty string.
This cannot easily happen for two reasons:
- TextEditor GUI elements disable their copy actions when the selection
is empty.
- Clipboard::set_data, through which all text-copying operates,
implicitly forbids empty strings, because Process::sys$anon_create
forbids empty anonymous files.
- Even if it were sent (e.g. by creating a non-empty anonymous file and
sending it manually to the Clipboard server), it would not be
received, because decode(Decoder&, Core::AnonymousBuffer&) goes
through mmap() with a size of 0, which also is forbidden by the
Kernel.
In other words, if the clipboard is never the empty text, therefore
checking this condition is pointless, and we can save a roundtrip to the
Clipboard server.
The FooSettings apps have quite a lot of boilerplate just around
creating a tabbed window with the same styling and the same row of
buttons along the bottom. So, let's extract that out into a class we can
reuse! :^)
You create a SettingsWindow instead of a regular Window, passing a title
and a flag to determine if a "Defaults" button is shown. Then call
add_tab() to add tabs to it. Tabs are widgets extending
SettingsWindow::Tab, which has methods for saving and resetting the
values.
This isn't a complete conversion to ErrorOr<void>, but a good chunk.
The end goal here is to propagate buffer allocation failures to the
caller, and allow the use of TRY() with formatting functions.
Also add slightly richer parse errors now that we can include a string
literal with returned errors.
This will allow us to use TRY() when working with JSON data.
Having the delete key handling be done via an action limits our ability
to support key modifiers (e.g. ctrl+delete deleting the word in front of
the cursor).
The fact that it was an action _did_ allow us to have a delete button in
the TextEditor UI. However, this is an odd choice in the first place
that isn't common in other text editors, so I just removed it.
This makes teardown faster since we don't have to wait for responses to
each destroy_window request. It also avoids doing IPC during teardown,
which is a general source of problems.
Implement, and use internally, content_margins() from Widget.
Since AbstractScrollableWidget already has a method called content_size,
the convenience method, with the same name, in Widget has to be
explicitly called.
Even though they are called content_margins,
they are actually only ever used to determine where
a Widget is supposed to be grabbable.
So all methods and members are renamed accordingly.
Derivatives of Core::Object should be constructed through
ClassName::construct(), to avoid handling ref-counted objects with
refcount zero. Fixing the visibility means that misuses like this are
more difficult.