All programs that have a CEventLoop now allow local socket connections
via /tmp/rpc.PID and will dump a serialized JSON array of all the live
CObjects in the program onto connecting sockets.
Also added a small /bin/rpcdump tool that connects to an RPC socket and
produces a raw dump of the JSON that comes out.
It is now possible to unmount file systems from the VFS via `umount`.
It works via looking up the `fsid` of the filesystem from the `Inode`'s
metatdata so I'm not sure how fragile it is. It seems to work for now
though as something to get us going.
You can now set a GTableCellPaintingDelegate per column in GTableView.
For columns with a painting delegate set, the view will defer to the
delegate for painting each cell in that column.
This patch adds the mprotect() syscall to allow changing the protection
flags for memory regions. We don't do any region splitting/merging yet,
so this only works on whole mmap() regions.
Added a "crash -r" flag to verify that we crash when you attempt to
write to read-only memory. :^)
This changes the behavior of the "is_checkable" flag on GAbstractButton
to only be about user interaction checkability. In other words, it now
only prevents the user from checking/unchecking the button, the code.
Now that we're bringing back the in-kernel virtual console, we should
move towards having a single implementation of terminal emulation.
This patch rips out the emulation code from the Terminal application
and turns it into the beginnings of LibVT.
The basic design idea is that users of VT::Terminal will implement and
provide a VT::TerminalClient subclass to handle presentation-specific
things. We'll need to iterate on this, but it's a start. :^)
Originally, it would stop being highlighted if the mouse was moved away from
it, even while in use. Now it will stay highlighted for the duration of
usage.
Now there's just CHttpRequest::set_url(URL), no need to specify the
host, port and path manually anymore.
Updated ChanViewer and Downloader for the API change.
Change the custom data massaging callback to take a const JsonObject&.
This will allow binding together data from multiple fields into one
output in the model. :^)
You can now call GTableView::set_size_columns_to_fit_content(true) and
the table columns will grow to fit the content. They will never shrink,
only grow.
This means I can spend a lot less time fidgeting with column widths :^)
These widgets can only display a single column from the underlying data
model, and it was previously hard-coded to use column 0. Now you can
use any column you like.
This ensures the pipe fds don't leak into child processes.
This manifested as the Shell (and all processes started
from the shell) having two mysterious FIFOs open. This
was happening because of the Terminal, which the shell
was spawned form, leaking its CEventLoop wake pipe fds.
In the userspace, this mimics the Linux pipe2() syscall;
in the kernel, the Process::sys$pipe() now always accepts
a flags argument, the no-argument pipe() syscall is now a
userspace wrapper over pipe2().
Fork the IPC Connection classes into Server:: and Client::ConnectionNG.
The new IPC messages are serialized very snugly instead of using the
same generic data structure for all messages.
Remove ASAPI.h since we now generate all of it from AudioServer.ipc :^)
- Add IEndpoint::handle(IMessage), a big switch table on message type.
handle() will return a response message for synchronous messages,
and return nullptr otherwise.
- Use i32 instead of int for everything
- Make IMessage::encode() const
- Make IEndpoint::decode_message() static, this allows template code to
decode messages without an endpoint instance on hand.
If the underlying variant type is a String, try to parse out a color
when to_color() is called.
This makes VisualBuilder apply the saved colors when loading forms.
This API was returning a "const char*" and it was unclear who took care
of the underlying memory. Returning a String makes that obvious.
Also make sure we close the /etc/passwd file when we're done with it.
It is now possible to mount ext2 `DiskDevice` devices under Serenity on
any folder in the root filesystem. Currently any user can do this with
any permissions. There's a fair amount of assumptions made here too,
that might not be too good, but can be worked on in the future. This is
a good start to allow more dynamic operation under the OS itself.
It is also currently impossible to unmount and such, and devices will
fail to mount in Linux as the FS 'needs to be cleaned'. I'll work on
getting `umount` done ASAP to rectify this (as well as working on less
assumption-making in the mount syscall. We don't want to just be able
to mount DiskDevices!). This could probably be fixed with some `-t`
flag or something similar.
Furthermore, fread() has already handled EOF, so there's no need to do
it again. If we read a character, return it, otherwise return EOF.
Note that EOF means "EOF or error" here.
There's some confusion between the write syscall and CIODevice::write()
here. The internal write() returns a boolean, and has already whined
in case the syscall failed, so we don't need to do that again.
I originally thought I'd have to implement text clipping in Painter for
this, but it seems like I can get away without doing that today. :^)
Fixes#390.
In the event where you want to find the index of a deeply-nested path
with a GFileSystemModel that hasn't yet traversed most of that path, it
is possible for a false negative failure to occur. This failure is
caused by the GFileSystemModel incorrectly bailing out of the search
when it hits the first unseen path segment that is not at the very end
of the path.
This patch fixes this problem by reifying the intermediate nodes during
that search and traversal process.
The goal here is to generate most of this code from IPC protocol
descriptions, but for now I've spelled them all out to get started.
Each message gets a wrapper class in the ASAPI_Client or ASAPI_Server
namespace. They are convertible to and from the old message structs.
The real hotness happens when you want to make a synchronous request
to the other side:
auto response = send_sync<ASAPI_Client::GetMainMixVolume>();
Each request class knows his corresponding response class, so in the
above example, "response" will be an ASAPI_Server::DidGetMainMixVolume
object, and we can get the volume like so:
int volume = response.volume();
For posting messages that don't expect a response, you can still use
post_message() since the message classes are convertible:
post_message(ASAPI_Server::DidGetMainMixVolume(volume));
It's not perfect yet, but I already really like it. :^)
Give the mixer a main volume value (percent) that we scale all the
outgoing samples by (before clipping.)
Also add a simple "avol" program for querying and setting the volume:
- "avol" prints the current volume.
- "avol 200" sets the main mix volume to 200%
We had some kernel-specific gizmos in AK that should really just be in the
Kernel subdirectory instead. The only thing remaining after moving those
was mmx_memcpy() which I moved to the ARCH(i386)-specific section of
LibC/string.cpp.
Processes can now have an icon assigned, which is essentially a 16x16 RGBA32
bitmap exposed as a shared buffer ID.
You set the icon ID by calling set_process_icon(int) and the icon ID will be
exposed through /proc/all.
To make this work, I added a mechanism for making shared buffers globally
accessible. For safety reasons, each app seals the icon buffer before making
it global.
Right now the first call to GWindow::set_icon() is what determines the
process icon. We'll probably change this in the future. :^)
Show some information about the file we're playing, and display how many
samples we've played out of how many total.
This might be a bit buggy as I haven't tested it with many different files,
but it's a start. :^)
This is a total hack, because I haven't really looked into why these are
happening. Somehow we're producing one extra sample and it's glitching
up the sound stream ever so slightly.
Each client connection now sets up an ASBufferQueue, which is basically a
queue of ABuffers. This allows us to immediately start streaming the next
pending buffer whenever our current buffer runs out of samples.
This makes the majority of the skippiness go away for me. :^)
Also get rid of the old PlayBuffer API, since we don't need it anymore.
Now that we can set icons directly "by bitmap", there's no need for passing
around the icon paths anymore, so get rid of all the IPC and API related
to that. :^)
Now that we support more than 2 clients per shared buffer, we can use them
for window icons. I didn't do that previously since it would have made the
Taskbar process unable to access the icons.
This opens up some nice possibilities for programmatically generated icons.
Thanks to Dan for pointing this out on IRC:
<danboid> I see TextEditor still numbers its lines from 0. You're too much of a programmer sometimes kling! :)
< kling> that might be the most extreme form of "programmer design" I've seen in serenity
We were limiting ourselves to only play WAV files smaller than 42 MB
for no particular reason. This patch increases the limit to 1 GB.
Perhaps there should not be any limit at all, but 1GB seems like a
reasonable sanity check at the moment. :^)
This allows us to carry the same buffer all the way from the WAV loader
to the AudioServer mixer.
This alleviates some of the stutter, but there's still a noticeable
skip when switching buffers. We're gonna need to do better. :^)
I had to solve a bunch of things simultaneously to make this work.
Refactor AWavLoader to be a streaming loader rather than a one-shot one.
The constructor parses the header, and if everything looks good, you can
repeatedly ask the AWavLoader for sample buffers until it runs out.
Also send a message from AudioServer when a buffer has finished playing.
That allows us to implement a blocking variant of play().
Use all of this in aplay to play WAV files chunk-at-a-time.
This is definitely not perfect and it's a little glitchy and skippy,
but I think it's a step in the right direction.
It was a tad too bright. Also make sure we're using the same color in
all the different places. At some point it would be nice to improve global
color settings, etc.
We're going to be using dedicated server socket classes instead.
This was only implemented for CLocalSocket, and clients have been switched
over to using CLocalServer.
Use CLocalServer to listen for connections in WindowServer and AudioServer.
This allows us to accept incoming CLocalSocket objects from the CLocalServer
and construct client connections based on those.
Removed COpenedSocket since it's replaced by CLocalSocket.
Instead of trying to support both client and server in CLocalSocket, let's
have a specialized server class.
The basic usage is:
CLocalServer server;
server.listen("/tmp/name-of-portal");
server.on_ready_to_accept = [&] {
CLocalSocket* client = server.accept();
...
};
This will make things a lot simpler, since an accepting socket doesn't need
half of the stuff that a regular CIODevice provides. :^)
Since ChildAdded events originate from the CObject constructor, they are not
fully constructed when their parent learns that they were added.
Added a little comment about this to the child_event() declaration.
Make GWindow::close() so we can override it in GDialog and quit from the
internal event loop when the window manager tells us to close ourselves.
The dialog will return GDialog::ExecCancel in these situations.
This macro goes at the top of every CObject-derived class like so:
class SomeClass : public CObject {
C_OBJECT(SomeClass)
public:
...
At the moment, all it does is create an override for the class_name() getter
but in the future this will be used to automatically insert member functions
into these classes.
If we had already processed a couple of queued events by the time we were
told to un-nest the event loop, we'd put the entire current batch at the
head of the outer queue. This meant that we might end up trying to process
the same events multiple times.
Let's not do that. :^)
This one is a bit mysterious. I can't find any authoritative answer on what
the correct behavior is, but it seems reasonable to me that free() doesn't
step on errno, since it returns "void" and thus the caller won't know to
inspect errno anyway.
Cached tooltip windows were preventing the automatic event loop shutdown.
It's not like we were gaining much by caching these anyway, since we only
cached the GWindow, not anything on the WindowServer side.
This behavior and API was extremely counter-intuitive since our default
behavior was for applications to never exit after you close all of their
windows.
Now that we exit the event loop by default when the very last GWindow is
deleted, we don't have to worry about this.
This behavior is the new opt-out default. If you don't want your app to exit
when the last GWindow is destroyed, call this:
- void GApplication::set_quit_set_quit_when_last_window_deleted(bool)
Also renamed "windows()" to "reified_windows" in GWindow.cpp to reflect that
it only contains GWindows that have a server-side representation. :^)
Use the new watch_file() mechanism to monitor the currently open directory
for changes and refresh the model when notified. This makes FileManager
automagically show newly added files. :^)
The syscall is quite simple:
int watch_file(const char* path, int path_length);
It returns a file descriptor referring to a "InodeWatcher" object in the
kernel. It becomes readable whenever something changes about the inode.
Currently this is implemented by hooking the "metadata dirty bit" in
Inode which isn't perfect, but it's a start. :^)
We were installing libraries into /Libraries/Root, rather than in /Root.
This made the ports system behave rather unpredictable, since I had old
versions of things in /Root and new versions of things in /Libraries/Root.
The "stddbg" stream was a cute idea but we never ended up using it in
practice, so let's simplify this and implement userspace dbgprintf() on top
of a simple dbgputch() syscall instead.
This makes debugging LibC startup a little bit easier. :^)
Add a trivial CSafeSyscall template that calls a callback until it stops
returning EINTR, and use it everywhere we use select() now.
Thanks to Andreas for the suggestion of using a template parameter for
the syscall function to invoke.
This is very simple but already very useful. Now you're able to call to
dump_backtrace() from anywhere userspace to get a nice symbolicated
backtrace in the debugger output. :^)
You now have to pass an Orientation to the GSlider constructor. It's not
possible to change the orientation after construction.
Added some vertical GSliders to the WidgetGallery demo for testing. :^)
These are useful when doing widgets that can be switched between vertical
and horizontal mode, such as GSlider. The idea is that instead of using
"x" and "y" directly, you use the "primary" and "secondary" offset/size
for the Orientation you're configured in.
Rolling with the theme of adding a dialog to shutdown the machine, it is
probably nice to have a way to reboot the machine without performing a full
system powerdown.
A reboot program has been added to `/bin/` as well as a corresponding
`syscall` (SC_reboot). This syscall works by attempting to pulse the 8042
keyboard controller. Note that this is NOT supported on new machines, and
should only be a fallback until we have proper ACPI support.
The implementation causes a triple fault in QEMU, which then restarts the
system. The filesystems are locked and synchronized before this occurs,
so there shouldn't be any corruption etctera.
The only part of this that actually differs between all of them is the
stream -> sample reading, so turn that into a function that the channel
reader can call as it wants.
Instead of LibGUI and WindowServer building their own copies of the drawing
and graphics code, let's it in a separate LibDraw library.
This avoids building the code twice, and will encourage better separation
of concerns. :^)
This allows us to seal a buffer *before* anyone else has access to it
(well, ok, the creating process still does, but you can't win them all).
It also means that a SharedBuffer can be shared with multiple clients:
all you need is to have access to it to share it on again.
This was a mistake, of course. Nested event loops don't need (or want)
independent server connections.
We initialize the connection early in GEventLoop for e.g. users that
want to get the size of a GDesktop before the connection has been
established.
Bug noticed by Andreas, introduced by me ;-)
Sticking these in a namespace allows us to use a more generic
("Connection") term without clashing, which is way easier to understand
than to try to come up with unique names for both.
As a consequence, move to use an explicit handshake() method rather than
calling virtuals from the constructor. This seemed to not bother
AClientConnection, but LibGUI crashes (rightfully) because of it.
The center of this is now an ABuffer class in LibAudio.
ABuffer contains ASample, which has two channels (left/right) in
floating point for mixing purposes, in 44100hz.
This means that the loaders (AWavLoader in this case) needs to do some
manipulation to get things in the right format, but that we don't need
to care after format loading is done.
While we're at it, do some correctness fixes. PCM data is unsigned if
it's 8 bit, but 16 bit is signed. And /dev/audio also wants signed 16
bit audio, so give it what it wants.
On top of this, AudioServer now accepts requests to play a buffer.
The IPC mechanism here is pretty much a 1:1 copy-paste from
LibGUI/WindowServer. It can be generalized more in the future, but for
now I want to get AudioServer working decently first :)
Additionally, add a little "aplay" tool to load and play a WAV file. It
will break with large WAVs (run out of memory, heh...) but it's a start.
Future work needs to make AudioServer block buffer submission from
clients until it has played the buffer they are requesting to play.
Currently the two available input types are:
- GMessageBox::InputType::OK (default)
- GMessageBox::InputType::OKCancel
Based on your choice, GMessageBox::exec() will return ExecOK or ExecCancel.
This way, CNotifier can mutate state to its little heart's content
without destroying the world when the global CNotifier hash changes
during delivery.
If custom I/O is being done outside CIODevice, we need a way to force blocking sometimes.
This also fixes the default of CLocalSocket to be non-blocking, the same
as CTCPSocket.
This is the same as calling FileSystemPath(foo).string(). The majority of
clients only care about canonicalizing a path, so let's have an easy way
to express that.
This patch generalizes the concept used in Piano to wake up the event loop
so it can react to something happening on a secondary thread.
Basically, there's a pipe who is always part of the file descriptor set we
pass to select(), and calling wake() simply writes a little to that pipe.
* Add a LibAudio, and move WAV file parsing there (via AWavFile and AWavLoader)
* Add CLocalSocket, and CSocket::connect() variant for local address types.
We make some small use of this in WindowServer (as that's where we
modelled it from), but don't get too invasive as this PR is already
quite large, and the WS I/O is a bit carefully done
* Add an AClientConnection which will eventually be used to talk to
AudioServer (and make use of it in Piano, though right now it really
doesn't do anything except connect, using our new CLocalSocket...)
Don't process any more events. We already prepend the remaining events in
this loop to the outer loop if needed.
If there were any more events queued after the exit request, the iteration
code would make an invalid access into 'queued_events'.
Fixes#300.
Regardless of mode, made the knob container clickable so the knob position
can be moved without dragging the knob itself.
Added a 3rd GSlider to the WidgetGallery showing the proportional mode in
action.
There's very little reason to take NonnullRefPtr&& in arguments really.
You can avoid ref-count churn in the cases where ownership is transferred
from the caller to the callee, but that's a pretty unusual situation and
not worth optimizing for at this stage.
Instead of computing the path length inside the syscall handler, let the
caller do that work. This allows us to implement to new variants of open()
and creat(), called open_with_path_length() and creat_with_path_length().
These are suitable for use with e.g StringView.