This also adds the ability to query how many virtual desktops are
set up, and for the Taskbar to be notified when the active virtual
desktop has changed.
This creates a 2-dimensional array of WindowStack instances, one for
each virtual desktop. The main desktop 0,0 is the main desktop, which
is the desktop used for all stationary windows (e.g. taskbar, desktop).
When adding windows to a desktop, stationary windows are always added
to the main desktop.
When composing the desktop, there are usually two WindowStacks
involved. For stationary windows, the main desktop will be traversed,
and for everything else the current virtual desktop will be iterated.
Iteration is interweaved to preserve the correct order. During the
transition animation, two WindowStacks will be iterated at the same
time.
Since being tiled means we restrict rendering a window to the screen it
is on (so that we don't "bleed" into an adjacent screen), we need to
untile it if the window either can't fit into the screen, or it is
detached from the screen edges.
The launch_origin_rect parameter to create_window() specifies where on
screen the window was launched from. It's optional, but if you provide
it, the new window will have a short wireframe animation from the origin
to the initial window frame rect.
GUI::Window looks for the "__libgui_launch_origin_rect" environment
variable. Put your launch origin rect in there with the format
"<x>,<y>,<width>,<height>" and the first GUI::Window shown by the app
will use that as the launch origin rect.
Also it looks pretty neat, although I'm sure we can improve it. :^)
This patch adds the WindowServer::Animation class, which represents
a simple animation driven by the compositor.
An animation has a length (in milliseconds) and two hooks:
- on_update: called whenever the animation should render something.
- on_stop: called when the animation is finished and/or stopped.
This patch also ports the window minimization animation to this new
mechanism. :^)
This allows WindowServer to use multiple framebuffer devices and
compose the desktop with any arbitrary layout. Currently, it is assumed
that it is configured contiguous and non-overlapping, but this should
eventually be enforced.
To make rendering efficient, each window now also tracks on which
screens it needs to be rendered. This way we don't have to iterate all
the windows for each screen but instead use the same rendering loop and
then only render to the screen (or screens) that the window actually
uses.
Instead of just answering hit/no-hit when hit testing windows, we now
return a HitTestResult object which tells you which window was hit,
where it was hit, and whether you hit the frame or the content.
We were not substituting the window modified marker ("[*]") in the
title strings we were sending to WM clients. This caused the Taskbar
to show pre-substitution window titles for the Text Editor application.
This patch moves the window title resolution to Window::compute_title()
which is then used throughout.
Instead of trying to update only the little bit that changes, let's
have a function that updates all the window menu items in one go.
It's just a couple of string and boolean assignment, and the real
cost is performing the subsequent menu redraw, which remains the same.
Windows that are marked as modified will now have another (themable)
close button. This gives an additional visual clue that some action
will be required by the user before the window gets closed.
The default window-close-modified icon is an "X" with "..." underneath,
building on the established use of "..." in menus to signify that
additional user input will be required before an action is completed.
SPDX License Identifiers are a more compact / standardized
way of representing file license information.
See: https://spdx.dev/resources/use/#identifiers
This was done with the `ambr` search and replace tool.
ambr --no-parent-ignore --key-from-file --rep-from-file key.txt rep.txt *
With this patch the window manager related functionality is split out
onto a new endpoint pair named WindowManagerServer/Client. This allows
window manager functionality to be potentially privilege separated in
the future. To this end, a new client named WMConnectionClient
is used to maintain a window manager connection. When a process
connects to the endpoint and greets the WindowServer as a window manager
(via Window::make_window_manager(int)), they're subscribed to the events
they requested via the WM event mask.
This patch also removes the hardcoding of the Taskbar WindowType to
receive WM events automatically. However, being a window manager still
requires having an active window, at the moment.
I hereby declare these to be full nouns that we don't split,
neither by space, nor by underscore:
- Breadcrumbbar
- Coolbar
- Menubar
- Progressbar
- Scrollbar
- Statusbar
- Taskbar
- Toolbar
This patch makes everything consistent by replacing every other variant
of these with the proper one. :^)
This patch adds support for opening menus via keyboard shortcuts.
Use an ampersand in a menu name to automatically create a keyboard
shortcut (Alt + the character following the ampersand.)
Menus with an Alt shortcut have a small underline under the shortcut
character for discoverability.
WindowServer now collects applet windows into an "applet area" which is
really just a window that a WM (window management) client can position
via IPC.
This is rather hackish, and I think we should come up with a better
architecture eventually, but this brings back the missing applets since
the global menu where they used to live is gone.
This patch begins the transition away from the global menu towards
per-window menus instead.
The global menu looks neat, but has always felt clunky, and there
are a number of usability problems with it, especially in programs
with multiple windows.
You can now call GUI::Window::set_menubar() to add a menubar to
your window. It will be specific to that one window only.
Tool windows are secondary windows with a smaller title bar. The sit on
the layer above normal windows, and cannot be minimized.
These are intended for complex yet non-modal interactions with the
content of a primary window, such as find/replace windows, property
windows, etc.
Minimum window size can now be customised and set at runtime via the
SetWindowMinimumSize WindowServer message and the set_minimum_size
LibGUI::Window method. The default minimum size remains at 50x50.
Some behind-the-scenes mechanics had to be added to LibGUI::Window to
ensure that the minimum size is remembered if set before the window is
shown. WindowServer sends a resize event to the client if it requests a
size on create that's smaller than it's minimum size.
Merely moving a window shouldn't require re-rendering the window
frame anymore now that we cache the rendered frame in bitmaps. This
reduces CPU usage significantly when moving windows.
Button now can handle middle and right clicks.
Added 2 new handlers in button class: on_right_click for Right mouse
button and on_middle_click for middle mouse button.
Added functionality to vertically maximize window with middle mouse
click on the maximize window button.
Also added a way to vertically maximize window by resizing window
height-wise lower than the maximum window height.
For example, FindInFilesWidget.h mentions GUI::TableView, but did not include
it. On the other hand, all source files that include FindInFilesWidget.h
also include TableView.h, so the issue is only cosmetical.
This commit:
- merges the two(!) places that defined independently the minimum size of a window.
- splits Window::normalize_rect(), which was originally just a function to apply
the minimum size requirement, and has taken on the additional job of nudging
windows back onto the desktop.
This inadvertantly fixes a crash that happens when a malicious program creates a
window of size (0, 0). Now, a window at [0,0 50x50] is created instead.
- Unmaximization/untiling had nearly but not quite code duplication;
this patch replaces the actual "regrabbing" logic with Rect::set_size_around.
- When undoing maximization/untiling, it used to be possible to to grab a window
"outside" of its frame, and thus drag it off the screen. This is no longer
possible. Fixes#4644.
- As a side effect, when untiling from the bottom/left/right, the regrab is now
a much smoother experience.
- Setting the resize aspect ratio while being tiled now untiles and umaximizes
the window, as these things are incompatible. Fixes an undocumented bug
(steps to reproduce: maximize, then set aspect ratio).
- When unmaximizing, spurious WindowLeft events were sent, because that path
didn't set hovered_window. Fixes an undocumented bug.
Since these things are interwoven, this is all a single commit.
Previously, SetWindowRect and SetWindowRect could supply basically arbitrary
x and y coordinates. This could happen either due to a malicious or malfunctioning
program, or even due to the auto-centering feature.
This patch also moves the 'normalization' code out of ClientConnection to Window,
where it belongs better.
Fixes#4135.
Fixes#5052.
This patch replaces the use of shbufs for GUI::Window backing stores
with the new anonymous files mechanism.
Backing bitmaps are now built on memory allocated with anon_create().
They are passed across the IPC socket as IPC::File. This means that
WindowServer now pledges "recvfd" and graphical clients need to pledge
"sendfd" to work.
To support the cached bitmap swapping optimization on the WindowServer
side, each backing store is assigned an incrementing serial number on
the client side. (This allows us to re-use an already mapped file.)