This makes most operations thread safe, especially so that they
can safely be used in the Kernel. This includes obtaining a strong
reference from a weak reference, which now requires an explicit
call to WeakPtr::strong_ref(). Another major change is that
Weakable::make_weak_ref() may require the explicit target type.
Previously we used reinterpret_cast in WeakPtr, assuming that it
can be properly converted. But WeakPtr does not necessarily have
the knowledge to be able to do this. Instead, we now ask the class
itself to deliver a WeakPtr to the type that we want.
Also, WeakLink is no longer specific to a target type. The reason
for this is that we want to be able to safely convert e.g. WeakPtr<T>
to WeakPtr<U>, and before this we just reinterpret_cast the internal
WeakLink<T> to WeakLink<U>, which is a bold assumption that it would
actually produce the correct code. Instead, WeakLink now operates
on just a raw pointer and we only make those constructors/operators
available if we can verify that it can be safely cast.
In order to guarantee thread safety, we now use the least significant
bit in the pointer for locking purposes. This also means that only
properly aligned pointers can be used.
When computing the chain of focusable widgets in a window, only include
each widget once (to avoid loops) and resolve focus proxies immediately
instead of lazily. This prevents the focus from getting stuck when
cycling backwards and hitting a proxy that points forward.
When opening a new window, we'll now try to find a suitable widget for
initial focus by picking the first available mouse-focusable one.
Whenever you press the tab key in a window with no focused widget,
we'll attempt to find a keyboard-focusable widget and give it focus.
This should make all applications keyboard-interactive immediately
without having to manually place focus with the mouse.
Every widget now has a GUI::FocusPolicy that determines how it can
receive focus:
- NoFocus: The widget is not focusable (default)
- TabFocus: The widget can be focused using the tab key.
- ClickFocus: The widget can be focused by clicking on it.
- StrongFocus: Both of the above.
For widgets that have a focus proxy, getting/setting the focus policy
will affect the proxy instead.
Instead of everyone overriding save_to() and set_property() and doing
a pretty asymmetric job of implementing the various properties, let's
add a bit of structure here.
Object properties are now represented by a Core::Property. Properties
are registered with a getter and setter (optional) in constructors.
I've added some convenience macros for creating and registering
properties, but this does still feel a bit bulky. We'll have to
iterate on this and see where it goes.
We got ourselves into a mess by making widgets override the window
cursor whenever they wanted a custom cursor. This patch introduces a
better solution to that issue: per-widget override cursors.
Each widget now has an override cursor that overrides the window
cursor when that widget is hovered.
When a resize_aspect_ratio is specified, and window will only be resized
to a multiple of that ratio. When resize_aspect_ratio is set, windows
cannot be tiled.
Various applications were using the same slightly verbose code to center
themselves on the screen/desktop:
Gfx::IntRect window_rect { 0, 0, width, height };
window_rect.center_within(GUI::Desktop::the().rect());
window->set_rect(window_rect);
Which now becomes:
window->resize(width, height);
window->center_on_screen();
This patch adds GUI::FocusEvent which has a GUI::FocusSource.
The focus source is one of three things:
- Programmatic
- Mouse
- Keyboard
This allows receivers of focus events to implement different behaviors
depending on how they receive/lose focus.
This prevents windows from being opened directly on top of eachother,
and provides default behavior for when window position is not specified.
The new behavior is as follows:
- Windows that have been created without a set position are assigned one
by WindowServer.
- The assigned position is either offset from the last window that is
still in an assigned position, or a default position if no such window
is available.
Accessory windows are windows that, when activated, will activate
their parent and bring all other accessory windows of that parent
to the front of the window stack. Accessory windows can only be
active input windows. The accessory window's parent is always the
active window regardless of whether it is also the active input
window.
In order to route input correctly, input is now sent to the active
input window, which can be any accessory window or their parent,
or any regular window.
During app teardown, the Application object may be destroyed before
something else, and so having Application::the() return a reference was
obscuring the truth about its lifetime.
This patch makes the API more honest by returning a pointer. While
this makes call sites look a bit more sketchy, do note that the global
Application pointer only becomes null during app teardown.
Each window now has an associated progress integer that can be updated
via the SetWindowProgress IPC call.
This can be used by clients to indicate the progress of ongoing tasks.
Any number in the range 0 through 100 indicate a progress percentage.
Any other number means "no progress"
If a window has child windows when it's destroyed, WindowServer will
now automatically tear down all of its children as well.
This is communicated to the client program through a vector of window
ID's included with the response to WindowServer::DestroyWindow.
This does feel a little bit awkward, but managing it on the client side
also seems a bit awkward.
If a window has another window in its Core::Object ancestor chain,
we now communicate that relationship to WindowServer so that it can
act with awareness of parent/child windows.
If the area or size_in_bytes calculation for a Gfx::Bitmap would
overflow, we now refuse to create such a bitmap and return nullptr.
Thanks to @itamar8910 for finding this! :^)
Remember the override cursor in GUI::Window and avoid sending a message
to WindowServer when possible.
This removes a lot of synchronous IPC between Browser and WindowServer,
which noticeably improves DOM event responsiveness. :^)
Because the ID of a hidden window is 0, the window server will
fail to update them when the system theme is changed. This
manifests when an application has multiple windows, some of
which are hidden, and the system theme is changed (see
https://github.com/SerenityOS/serenity/issues/1378).
This PR changes the window code to ignore update messages if
the window has the ID 0--is hidden.
Ideally the window ID would not change, and visibility would be
managed separately.
We should only detach from the cursor tracking widgets on unparenting
if they were the same widget that's being unparented!
Thanks to @agoose77 for spotting this!
Fixes#1354.
Previously the focused widget would only get cleared on replacement or
on destruction (being a WeakPtr and all.) This could lead to window
dispatching events to a focused widget after it had been removed from
the window's widget tree.
The same issue existed for the hovered widget, etc. So this patch
makes sure that we eagerly clear the various widget pointers in Window
immediately when they are removed from the window's widget tree.
This feels a lot more consistent and Unixy:
create_shared_buffer() => shbuf_create()
share_buffer_with() => shbuf_allow_pid()
share_buffer_globally() => shbuf_allow_all()
get_shared_buffer() => shbuf_get()
release_shared_buffer() => shbuf_release()
seal_shared_buffer() => shbuf_seal()
get_shared_buffer_size() => shbuf_get_size()
Also, "shared_buffer_id" is shortened to "shbuf_id" all around.
Previously it was only possible to change these window attributes when
creating a new window. This patch adds an IPC message that allows you
to change them at runtime.
We were not repainting windows that were occluded at the time of the
theme changing. This patch adds a way to bypass occlusion testing when
invalidating window rects.
Fixes#1249.
This allows windows/widgets to learn when something is being dragged
over them. They can then repaint themselves somehow to indicate that
they are willing to accept a drop.
Currently this is piggybacking somewhat on the mouse event mechanism
in WindowServer. I'm not sure that's the best design but it seemed
easier to do it this way right now.