This is essentially a combo widget containing a single-line GTextEditor
and two buttons for increment and decrement. The GTextEditor::on_change
callback is hooked to prevent non-numeric input but it's not entirely
perfect since that callback is asynchronous. This will work until we have
some more sophisticated input validation mechanism though.
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. :^)
If connect() is called on a non-blocking socket, it will "fail" immediately
with -EINPROGRESS. After that, you select() on the socket and wait for it to
become writable.
This code can get a bit confused when the child is destroyed before we
handle the ChildRemoved event. In those cases, the GChildEvent::child()
getter will return nullptr as it's backed by a WeakPtr.
To work around this issue, just always invalidate the layout for now.
This can be made a lot tighter in the future.
I added focus rects to these widgets because I had just started working on
focus support and I was excited but it doesn't really make sense for these
things to have focus rects. :^)
While I was here I also optimized the repaint code to only update the edited
glyph in the glyph map when editing its pixels.
The window is simply ignored in the painting and hit testing traversal
when in minimized state, same as we do for invisible windows.
The WM_SetActiveWindow message (sent by Taskbar) brings it back into the
non-minimized state. :^)
Previously it would just close the window on MouseDown. Now we do the normal
thing where we require a MouseUp inside the button rect before committing.
This was a bit painful to get right. The code is a lot more pleasant to
deal with now that all coordinates are relative to their local system
instead of being absolute screen coordinates.
The window frame is an object that contains a window, its title bar and
window border. This way WSWindowManager doesn't have to know about all the
different types of window borders, titlebar rects, etc.
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.