Only process paint and resize events on the GUI client side if those events
have the latest up-to-date window size. This drastically reduces async
overdraw during interactive resize.
The WindowServer still holds on to at least one backing store in case it
needs to paint us again before we can render a new one. This ensures that
we don't end up stuck with an undersized backing store.
When resizing a window, we often end up having to paint some part of it
without coverage in the current backing store. This patch makes those cases
look nicer by having a fallback background color for each window, passed
along with the CreateWindow client message.
Any GWidget can have a tooltip and it will automatically pop up below the
center of the widget when hovered. GActions added to GToolBars will use
the action text() as their tooltip automagically. :^)
These events are identical, so it's silly to send both. Just broadcast
window state changes everywhere instead, it doesn't matter when it was
added as clients are learning about this asynchronously anyway.
I originally thought I would do this inside WindowServer, but let's try to
make it as a standalone app that communicates with WindowServer instead.
That will allow us to use LibGUI. :^)
When a mouse button is pressed inside a window, put that window into an
automatic mouse tracking state where all mouse events are sent to that
window until all mouse buttons are released.
This might feel even better if it only cared about the mouse buttons you
actually pressed while *inside* the windows to get released, I don't know.
I'll have to use it for a while and see how it's like.
This patch adds a simple GMessageBox that can run in a nested event loop.
Here's how you use it:
GMessageBox box("Message text here", "Message window title");
int result = box.exec();
The next step is to make the WindowServer respect the modality flag of
these windows and prevent interaction with other windows in the same
process until the modal window has been closed.
This way GWindow doesn't need to do synchronous IPC to fetch the appropriate
size for the window's backing store. This is mostly only relevant during
live resize.
Use this to implement incremental resizing for Terminal so that we only
ever resize to fit a perfect number of rows and columns.
This is very nice. :^)
Windows now learn when the mouse cursor leaves or enters them.
Use this to implement GWidget::{enter,leave}_event() and use that
to implement the CoolBar button effect. :^)
This patch also adds a Format concept to GraphicsBitmap. For now there are
only two formats: RGB32 and RGBA32. Windows with alpha channel have their
backing stores created in the RGBA32 format.
Use this to make Terminal windows semi-transparent for that comfy rice look.
There is one problem here, in that window compositing overdraw incurs
multiple passes of blending of the same pixels. This leads to a mismatch in
opacity which is obviously not good. I will work on this in a later patch.
The alpha blending is currently straight C++. It should be relatively easy
to optimize this using SSE instructions.
For now I'm just happy with the cute effect. :^)
These functions don't exit immediately, but rather on the next iteration
of the event loop.
Since exit() is already used by the standard library, let's call it quit()
instead. That way, saying exit() means the same thing here as anywhere else.
To facilitate listening for action on arbitrary file descriptors,
I've added a GNotifier class. It's quite simple but very useful:
GNotifier notifier(fd, GNotifier::Read);
notifier.on_ready_to_read = [this] (GNotifier& fd) {
// read from fd or whatever else you like :^)
};
The callback will get invoked by GEventLoop when select() says we
have something to read on the fd.
Clicking the button generates a WindowCloseRequest event which the client app
then has to deal with. The default behavior for GWindow is to close() itself.
I also added a flag, GWindow::should_exit_event_loop_on_close() which does
what it sounds like it does.
This patch exposed some bugs in GWindow and GWidget teardown.