summaryrefslogtreecommitdiff
path: root/Services
diff options
context:
space:
mode:
authorAndreas Kling <kling@serenityos.org>2021-01-12 12:23:01 +0100
committerAndreas Kling <kling@serenityos.org>2021-01-12 12:23:01 +0100
commitc7ac7e6eaff862c1ea4f99e0c6ce75e095106d9c (patch)
treece2a3fef96f0b8eebe907743f1e03739457c11a6 /Services
parent4055b0329117c1a280080bbd638eb48bafe29638 (diff)
downloadserenity-c7ac7e6eaff862c1ea4f99e0c6ce75e095106d9c.zip
Services: Move to Userland/Services/
Diffstat (limited to 'Services')
-rw-r--r--Services/AudioServer/AudioClient.ipc6
-rw-r--r--Services/AudioServer/AudioServer.ipc21
-rw-r--r--Services/AudioServer/CMakeLists.txt13
-rw-r--r--Services/AudioServer/ClientConnection.cpp168
-rw-r--r--Services/AudioServer/ClientConnection.h75
-rw-r--r--Services/AudioServer/Mixer.cpp166
-rw-r--r--Services/AudioServer/Mixer.h144
-rw-r--r--Services/AudioServer/main.cpp63
-rw-r--r--Services/CMakeLists.txt18
-rw-r--r--Services/ChessEngine/CMakeLists.txt8
-rw-r--r--Services/ChessEngine/ChessEngine.cpp76
-rw-r--r--Services/ChessEngine/ChessEngine.h49
-rw-r--r--Services/ChessEngine/MCTSTree.cpp180
-rw-r--r--Services/ChessEngine/MCTSTree.h67
-rw-r--r--Services/ChessEngine/main.cpp49
-rw-r--r--Services/Clipboard/CMakeLists.txt13
-rw-r--r--Services/Clipboard/ClientConnection.cpp103
-rw-r--r--Services/Clipboard/ClientConnection.h60
-rw-r--r--Services/Clipboard/ClipboardClient.ipc4
-rw-r--r--Services/Clipboard/ClipboardServer.ipc7
-rw-r--r--Services/Clipboard/Storage.cpp62
-rw-r--r--Services/Clipboard/Storage.h73
-rw-r--r--Services/Clipboard/main.cpp76
-rw-r--r--Services/CrashDaemon/CMakeLists.txt6
-rw-r--r--Services/CrashDaemon/main.cpp94
-rw-r--r--Services/DHCPClient/CMakeLists.txt8
-rw-r--r--Services/DHCPClient/DHCPv4.cpp59
-rw-r--r--Services/DHCPClient/DHCPv4.h299
-rw-r--r--Services/DHCPClient/DHCPv4Client.cpp289
-rw-r--r--Services/DHCPClient/DHCPv4Client.h79
-rw-r--r--Services/DHCPClient/main.cpp99
-rw-r--r--Services/EchoServer/CMakeLists.txt7
-rw-r--r--Services/EchoServer/Client.cpp58
-rw-r--r--Services/EchoServer/Client.h49
-rw-r--r--Services/EchoServer/main.cpp99
-rw-r--r--Services/ImageDecoder/CMakeLists.txt12
-rw-r--r--Services/ImageDecoder/ClientConnection.cpp102
-rw-r--r--Services/ImageDecoder/ClientConnection.h56
-rw-r--r--Services/ImageDecoder/Forward.h34
-rw-r--r--Services/ImageDecoder/ImageDecoderClient.ipc4
-rw-r--r--Services/ImageDecoder/ImageDecoderServer.ipc7
-rw-r--r--Services/ImageDecoder/main.cpp51
-rw-r--r--Services/LaunchServer/CMakeLists.txt13
-rw-r--r--Services/LaunchServer/ClientConnection.cpp159
-rw-r--r--Services/LaunchServer/ClientConnection.h64
-rw-r--r--Services/LaunchServer/LaunchClient.ipc4
-rw-r--r--Services/LaunchServer/LaunchServer.ipc12
-rw-r--r--Services/LaunchServer/Launcher.cpp309
-rw-r--r--Services/LaunchServer/Launcher.h78
-rw-r--r--Services/LaunchServer/main.cpp65
-rw-r--r--Services/LookupServer/CMakeLists.txt10
-rw-r--r--Services/LookupServer/DNSAnswer.cpp46
-rw-r--r--Services/LookupServer/DNSAnswer.h51
-rw-r--r--Services/LookupServer/DNSPacket.h115
-rw-r--r--Services/LookupServer/DNSQuestion.h59
-rw-r--r--Services/LookupServer/DNSRequest.cpp96
-rw-r--r--Services/LookupServer/DNSRequest.h65
-rw-r--r--Services/LookupServer/DNSResponse.cpp152
-rw-r--r--Services/LookupServer/DNSResponse.h77
-rw-r--r--Services/LookupServer/LookupServer.cpp278
-rw-r--r--Services/LookupServer/LookupServer.h56
-rw-r--r--Services/LookupServer/main.cpp50
-rw-r--r--Services/NotificationServer/CMakeLists.txt13
-rw-r--r--Services/NotificationServer/ClientConnection.cpp63
-rw-r--r--Services/NotificationServer/ClientConnection.h50
-rw-r--r--Services/NotificationServer/NotificationClient.ipc4
-rw-r--r--Services/NotificationServer/NotificationServer.ipc7
-rw-r--r--Services/NotificationServer/NotificationWindow.cpp123
-rw-r--r--Services/NotificationServer/NotificationWindow.h48
-rw-r--r--Services/NotificationServer/main.cpp74
-rw-r--r--Services/ProtocolServer/CMakeLists.txt20
-rw-r--r--Services/ProtocolServer/ClientConnection.cpp142
-rw-r--r--Services/ProtocolServer/ClientConnection.h63
-rw-r--r--Services/ProtocolServer/Download.cpp79
-rw-r--r--Services/ProtocolServer/Download.h81
-rw-r--r--Services/ProtocolServer/Forward.h40
-rw-r--r--Services/ProtocolServer/GeminiDownload.cpp84
-rw-r--r--Services/ProtocolServer/GeminiDownload.h49
-rw-r--r--Services/ProtocolServer/GeminiProtocol.cpp62
-rw-r--r--Services/ProtocolServer/GeminiProtocol.h41
-rw-r--r--Services/ProtocolServer/HttpDownload.cpp74
-rw-r--r--Services/ProtocolServer/HttpDownload.h47
-rw-r--r--Services/ProtocolServer/HttpProtocol.cpp67
-rw-r--r--Services/ProtocolServer/HttpProtocol.h41
-rw-r--r--Services/ProtocolServer/HttpsDownload.cpp82
-rw-r--r--Services/ProtocolServer/HttpsDownload.h49
-rw-r--r--Services/ProtocolServer/HttpsProtocol.cpp67
-rw-r--r--Services/ProtocolServer/HttpsProtocol.h41
-rw-r--r--Services/ProtocolServer/Protocol.cpp67
-rw-r--r--Services/ProtocolServer/Protocol.h57
-rw-r--r--Services/ProtocolServer/ProtocolClient.ipc10
-rw-r--r--Services/ProtocolServer/ProtocolServer.ipc13
-rw-r--r--Services/ProtocolServer/main.cpp69
-rw-r--r--Services/SystemMenu/CMakeLists.txt7
-rw-r--r--Services/SystemMenu/ShutdownDialog.cpp117
-rw-r--r--Services/SystemMenu/ShutdownDialog.h43
-rw-r--r--Services/SystemMenu/main.cpp232
-rw-r--r--Services/SystemServer/CMakeLists.txt7
-rw-r--r--Services/SystemServer/Service.cpp376
-rw-r--r--Services/SystemServer/Service.h102
-rw-r--r--Services/SystemServer/main.cpp242
-rw-r--r--Services/Taskbar/CMakeLists.txt9
-rw-r--r--Services/Taskbar/TaskbarButton.cpp162
-rw-r--r--Services/Taskbar/TaskbarButton.h48
-rw-r--r--Services/Taskbar/TaskbarWindow.cpp314
-rw-r--r--Services/Taskbar/TaskbarWindow.h53
-rw-r--r--Services/Taskbar/WindowIdentifier.h63
-rw-r--r--Services/Taskbar/WindowList.cpp71
-rw-r--r--Services/Taskbar/WindowList.h115
-rw-r--r--Services/Taskbar/main.cpp57
-rw-r--r--Services/TelnetServer/CMakeLists.txt8
-rw-r--r--Services/TelnetServer/Client.cpp190
-rw-r--r--Services/TelnetServer/Client.h69
-rw-r--r--Services/TelnetServer/Command.h82
-rw-r--r--Services/TelnetServer/Parser.cpp89
-rw-r--r--Services/TelnetServer/Parser.h59
-rw-r--r--Services/TelnetServer/main.cpp172
-rw-r--r--Services/WebContent/CMakeLists.txt13
-rw-r--r--Services/WebContent/ClientConnection.cpp169
-rw-r--r--Services/WebContent/ClientConnection.h76
-rw-r--r--Services/WebContent/Documentation.txt27
-rw-r--r--Services/WebContent/Forward.h34
-rw-r--r--Services/WebContent/PageHost.cpp182
-rw-r--r--Services/WebContent/PageHost.h79
-rw-r--r--Services/WebContent/WebContentClient.ipc18
-rw-r--r--Services/WebContent/WebContentServer.ipc18
-rw-r--r--Services/WebContent/main.cpp60
-rw-r--r--Services/WebServer/CMakeLists.txt7
-rw-r--r--Services/WebServer/Client.cpp270
-rw-r--r--Services/WebServer/Client.h56
-rw-r--r--Services/WebServer/main.cpp101
-rw-r--r--Services/WindowServer/AppletManager.cpp141
-rw-r--r--Services/WindowServer/AppletManager.h56
-rw-r--r--Services/WindowServer/Button.cpp116
-rw-r--r--Services/WindowServer/Button.h69
-rw-r--r--Services/WindowServer/CMakeLists.txt26
-rw-r--r--Services/WindowServer/ClientConnection.cpp941
-rw-r--r--Services/WindowServer/ClientConnection.h170
-rw-r--r--Services/WindowServer/Compositor.cpp1040
-rw-r--r--Services/WindowServer/Compositor.h135
-rw-r--r--Services/WindowServer/Cursor.cpp185
-rw-r--r--Services/WindowServer/Cursor.h81
-rw-r--r--Services/WindowServer/Event.h166
-rw-r--r--Services/WindowServer/EventLoop.cpp149
-rw-r--r--Services/WindowServer/EventLoop.h57
-rw-r--r--Services/WindowServer/Menu.cpp568
-rw-r--r--Services/WindowServer/Menu.h169
-rw-r--r--Services/WindowServer/MenuBar.cpp55
-rw-r--r--Services/WindowServer/MenuBar.h61
-rw-r--r--Services/WindowServer/MenuItem.cpp111
-rw-r--r--Services/WindowServer/MenuItem.h104
-rw-r--r--Services/WindowServer/MenuManager.cpp497
-rw-r--r--Services/WindowServer/MenuManager.h123
-rw-r--r--Services/WindowServer/Screen.cpp186
-rw-r--r--Services/WindowServer/Screen.h98
-rw-r--r--Services/WindowServer/Window.cpp776
-rw-r--r--Services/WindowServer/Window.h363
-rw-r--r--Services/WindowServer/WindowClient.ipc42
-rw-r--r--Services/WindowServer/WindowFrame.cpp382
-rw-r--r--Services/WindowServer/WindowFrame.h81
-rw-r--r--Services/WindowServer/WindowManager.cpp1509
-rw-r--r--Services/WindowServer/WindowManager.h479
-rw-r--r--Services/WindowServer/WindowServer.ipc117
-rw-r--r--Services/WindowServer/WindowSwitcher.cpp257
-rw-r--r--Services/WindowServer/WindowSwitcher.h84
-rw-r--r--Services/WindowServer/WindowType.h41
-rw-r--r--Services/WindowServer/main.cpp119
167 files changed, 0 insertions, 19750 deletions
diff --git a/Services/AudioServer/AudioClient.ipc b/Services/AudioServer/AudioClient.ipc
deleted file mode 100644
index b43db52dd0..0000000000
--- a/Services/AudioServer/AudioClient.ipc
+++ /dev/null
@@ -1,6 +0,0 @@
-endpoint AudioClient = 82
-{
- FinishedPlayingBuffer(i32 buffer_id) =|
- MutedStateChanged(bool muted) =|
- MainMixVolumeChanged(i32 volume) =|
-}
diff --git a/Services/AudioServer/AudioServer.ipc b/Services/AudioServer/AudioServer.ipc
deleted file mode 100644
index b48dcd7e46..0000000000
--- a/Services/AudioServer/AudioServer.ipc
+++ /dev/null
@@ -1,21 +0,0 @@
-endpoint AudioServer = 85
-{
- // Basic protocol
- Greet() => (i32 client_id)
-
- // Mixer functions
- SetMuted(bool muted) => ()
- GetMuted() => (bool muted)
- GetMainMixVolume() => (i32 volume)
- SetMainMixVolume(i32 volume) => ()
-
- // Buffer playback
- EnqueueBuffer(i32 buffer_id, int sample_count) => (bool success)
- SetPaused(bool paused) => ()
- ClearBuffer(bool paused) => ()
-
- //Buffer information
- GetRemainingSamples() => (int remaining_samples)
- GetPlayedSamples() => (int played_samples)
- GetPlayingBuffer() => (i32 buffer_id)
-}
diff --git a/Services/AudioServer/CMakeLists.txt b/Services/AudioServer/CMakeLists.txt
deleted file mode 100644
index 9c71197b62..0000000000
--- a/Services/AudioServer/CMakeLists.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-compile_ipc(AudioServer.ipc AudioServerEndpoint.h)
-compile_ipc(AudioClient.ipc AudioClientEndpoint.h)
-
-set(SOURCES
- ClientConnection.cpp
- Mixer.cpp
- main.cpp
- AudioServerEndpoint.h
- AudioClientEndpoint.h
-)
-
-serenity_bin(AudioServer)
-target_link_libraries(AudioServer LibCore LibThread LibIPC)
diff --git a/Services/AudioServer/ClientConnection.cpp b/Services/AudioServer/ClientConnection.cpp
deleted file mode 100644
index c034dc5199..0000000000
--- a/Services/AudioServer/ClientConnection.cpp
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "ClientConnection.h"
-#include "Mixer.h"
-#include <AK/SharedBuffer.h>
-#include <AudioServer/AudioClientEndpoint.h>
-#include <LibAudio/Buffer.h>
-#include <errno.h>
-#include <stdio.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <sys/uio.h>
-#include <unistd.h>
-
-namespace AudioServer {
-
-static HashMap<int, RefPtr<ClientConnection>> s_connections;
-
-void ClientConnection::for_each(Function<void(ClientConnection&)> callback)
-{
- NonnullRefPtrVector<ClientConnection> connections;
- for (auto& it : s_connections)
- connections.append(*it.value);
- for (auto& connection : connections)
- callback(connection);
-}
-
-ClientConnection::ClientConnection(NonnullRefPtr<Core::LocalSocket> client_socket, int client_id, Mixer& mixer)
- : IPC::ClientConnection<AudioClientEndpoint, AudioServerEndpoint>(*this, move(client_socket), client_id)
- , m_mixer(mixer)
-{
- s_connections.set(client_id, *this);
-}
-
-ClientConnection::~ClientConnection()
-{
-}
-
-void ClientConnection::die()
-{
- s_connections.remove(client_id());
-}
-
-void ClientConnection::did_finish_playing_buffer(Badge<BufferQueue>, int buffer_id)
-{
- post_message(Messages::AudioClient::FinishedPlayingBuffer(buffer_id));
-}
-
-void ClientConnection::did_change_muted_state(Badge<Mixer>, bool muted)
-{
- post_message(Messages::AudioClient::MutedStateChanged(muted));
-}
-
-void ClientConnection::did_change_main_mix_volume(Badge<Mixer>, int volume)
-{
- post_message(Messages::AudioClient::MainMixVolumeChanged(volume));
-}
-
-OwnPtr<Messages::AudioServer::GreetResponse> ClientConnection::handle(const Messages::AudioServer::Greet&)
-{
- return make<Messages::AudioServer::GreetResponse>(client_id());
-}
-
-OwnPtr<Messages::AudioServer::GetMainMixVolumeResponse> ClientConnection::handle(const Messages::AudioServer::GetMainMixVolume&)
-{
- return make<Messages::AudioServer::GetMainMixVolumeResponse>(m_mixer.main_volume());
-}
-
-OwnPtr<Messages::AudioServer::SetMainMixVolumeResponse> ClientConnection::handle(const Messages::AudioServer::SetMainMixVolume& message)
-{
- m_mixer.set_main_volume(message.volume());
- return make<Messages::AudioServer::SetMainMixVolumeResponse>();
-}
-
-OwnPtr<Messages::AudioServer::EnqueueBufferResponse> ClientConnection::handle(const Messages::AudioServer::EnqueueBuffer& message)
-{
- auto shared_buffer = SharedBuffer::create_from_shbuf_id(message.buffer_id());
- if (!shared_buffer) {
- // FIXME: The shared buffer should have been retrieved for us already.
- // We don't want to do IPC error checking at this layer.
- ASSERT_NOT_REACHED();
- }
-
- if (!m_queue)
- m_queue = m_mixer.create_queue(*this);
-
- if (m_queue->is_full())
- return make<Messages::AudioServer::EnqueueBufferResponse>(false);
-
- m_queue->enqueue(Audio::Buffer::create_with_shared_buffer(*shared_buffer, message.sample_count()));
- return make<Messages::AudioServer::EnqueueBufferResponse>(true);
-}
-
-OwnPtr<Messages::AudioServer::GetRemainingSamplesResponse> ClientConnection::handle(const Messages::AudioServer::GetRemainingSamples&)
-{
- int remaining = 0;
- if (m_queue)
- remaining = m_queue->get_remaining_samples();
-
- return make<Messages::AudioServer::GetRemainingSamplesResponse>(remaining);
-}
-
-OwnPtr<Messages::AudioServer::GetPlayedSamplesResponse> ClientConnection::handle(const Messages::AudioServer::GetPlayedSamples&)
-{
- int played = 0;
- if (m_queue)
- played = m_queue->get_played_samples();
-
- return make<Messages::AudioServer::GetPlayedSamplesResponse>(played);
-}
-
-OwnPtr<Messages::AudioServer::SetPausedResponse> ClientConnection::handle(const Messages::AudioServer::SetPaused& message)
-{
- if (m_queue)
- m_queue->set_paused(message.paused());
- return make<Messages::AudioServer::SetPausedResponse>();
-}
-
-OwnPtr<Messages::AudioServer::ClearBufferResponse> ClientConnection::handle(const Messages::AudioServer::ClearBuffer& message)
-{
- if (m_queue)
- m_queue->clear(message.paused());
- return make<Messages::AudioServer::ClearBufferResponse>();
-}
-
-OwnPtr<Messages::AudioServer::GetPlayingBufferResponse> ClientConnection::handle(const Messages::AudioServer::GetPlayingBuffer&)
-{
- int id = -1;
- if (m_queue)
- id = m_queue->get_playing_buffer();
- return make<Messages::AudioServer::GetPlayingBufferResponse>(id);
-}
-
-OwnPtr<Messages::AudioServer::GetMutedResponse> ClientConnection::handle(const Messages::AudioServer::GetMuted&)
-{
- return make<Messages::AudioServer::GetMutedResponse>(m_mixer.is_muted());
-}
-
-OwnPtr<Messages::AudioServer::SetMutedResponse> ClientConnection::handle(const Messages::AudioServer::SetMuted& message)
-{
- m_mixer.set_muted(message.muted());
- return make<Messages::AudioServer::SetMutedResponse>();
-}
-}
diff --git a/Services/AudioServer/ClientConnection.h b/Services/AudioServer/ClientConnection.h
deleted file mode 100644
index f08aab49d3..0000000000
--- a/Services/AudioServer/ClientConnection.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <AK/HashMap.h>
-#include <AudioServer/AudioClientEndpoint.h>
-#include <AudioServer/AudioServerEndpoint.h>
-#include <LibIPC/ClientConnection.h>
-
-namespace Audio {
-class Buffer;
-}
-
-namespace AudioServer {
-
-class BufferQueue;
-class Mixer;
-
-class ClientConnection final : public IPC::ClientConnection<AudioClientEndpoint, AudioServerEndpoint>
- , public AudioServerEndpoint {
- C_OBJECT(ClientConnection)
-public:
- explicit ClientConnection(NonnullRefPtr<Core::LocalSocket>, int client_id, Mixer& mixer);
- ~ClientConnection() override;
-
- void did_finish_playing_buffer(Badge<BufferQueue>, int buffer_id);
- void did_change_muted_state(Badge<Mixer>, bool muted);
- void did_change_main_mix_volume(Badge<Mixer>, int volume);
-
- virtual void die() override;
-
- static void for_each(Function<void(ClientConnection&)>);
-
-private:
- virtual OwnPtr<Messages::AudioServer::GreetResponse> handle(const Messages::AudioServer::Greet&) override;
- virtual OwnPtr<Messages::AudioServer::GetMainMixVolumeResponse> handle(const Messages::AudioServer::GetMainMixVolume&) override;
- virtual OwnPtr<Messages::AudioServer::SetMainMixVolumeResponse> handle(const Messages::AudioServer::SetMainMixVolume&) override;
- virtual OwnPtr<Messages::AudioServer::EnqueueBufferResponse> handle(const Messages::AudioServer::EnqueueBuffer&) override;
- virtual OwnPtr<Messages::AudioServer::GetRemainingSamplesResponse> handle(const Messages::AudioServer::GetRemainingSamples&) override;
- virtual OwnPtr<Messages::AudioServer::GetPlayedSamplesResponse> handle(const Messages::AudioServer::GetPlayedSamples&) override;
- virtual OwnPtr<Messages::AudioServer::SetPausedResponse> handle(const Messages::AudioServer::SetPaused&) override;
- virtual OwnPtr<Messages::AudioServer::ClearBufferResponse> handle(const Messages::AudioServer::ClearBuffer&) override;
- virtual OwnPtr<Messages::AudioServer::GetPlayingBufferResponse> handle(const Messages::AudioServer::GetPlayingBuffer&) override;
- virtual OwnPtr<Messages::AudioServer::GetMutedResponse> handle(const Messages::AudioServer::GetMuted&) override;
- virtual OwnPtr<Messages::AudioServer::SetMutedResponse> handle(const Messages::AudioServer::SetMuted&) override;
-
- Mixer& m_mixer;
- RefPtr<BufferQueue> m_queue;
-};
-
-}
diff --git a/Services/AudioServer/Mixer.cpp b/Services/AudioServer/Mixer.cpp
deleted file mode 100644
index 66a33ed23d..0000000000
--- a/Services/AudioServer/Mixer.cpp
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <AK/Array.h>
-#include <AK/MemoryStream.h>
-#include <AK/NumericLimits.h>
-#include <AudioServer/ClientConnection.h>
-#include <AudioServer/Mixer.h>
-#include <pthread.h>
-#include <strings.h>
-
-namespace AudioServer {
-
-Mixer::Mixer()
- : m_device(Core::File::construct("/dev/audio", this))
- , m_sound_thread(LibThread::Thread::construct(
- [this] {
- mix();
- return 0;
- },
- "AudioServer[mixer]"))
-{
- if (!m_device->open(Core::IODevice::WriteOnly)) {
- dbgln("Can't open audio device: {}", m_device->error_string());
- return;
- }
-
- pthread_mutex_init(&m_pending_mutex, nullptr);
- pthread_cond_init(&m_pending_cond, nullptr);
-
- m_zero_filled_buffer = (u8*)malloc(4096);
- bzero(m_zero_filled_buffer, 4096);
- m_sound_thread->start();
-}
-
-Mixer::~Mixer()
-{
-}
-
-NonnullRefPtr<BufferQueue> Mixer::create_queue(ClientConnection& client)
-{
- auto queue = adopt(*new BufferQueue(client));
- pthread_mutex_lock(&m_pending_mutex);
- m_pending_mixing.append(*queue);
- m_added_queue = true;
- pthread_cond_signal(&m_pending_cond);
- pthread_mutex_unlock(&m_pending_mutex);
- return queue;
-}
-
-void Mixer::mix()
-{
- decltype(m_pending_mixing) active_mix_queues;
-
- for (;;) {
- if (active_mix_queues.is_empty() || m_added_queue) {
- pthread_mutex_lock(&m_pending_mutex);
- pthread_cond_wait(&m_pending_cond, &m_pending_mutex);
- active_mix_queues.append(move(m_pending_mixing));
- pthread_mutex_unlock(&m_pending_mutex);
- m_added_queue = false;
- }
-
- active_mix_queues.remove_all_matching([&](auto& entry) { return !entry->client(); });
-
- Audio::Sample mixed_buffer[1024];
- auto mixed_buffer_length = (int)(sizeof(mixed_buffer) / sizeof(Audio::Sample));
-
- // Mix the buffers together into the output
- for (auto& queue : active_mix_queues) {
- if (!queue->client()) {
- queue->clear();
- continue;
- }
-
- for (int i = 0; i < mixed_buffer_length; ++i) {
- auto& mixed_sample = mixed_buffer[i];
- Audio::Sample sample;
- if (!queue->get_next_sample(sample))
- break;
- mixed_sample += sample;
- }
- }
-
- if (m_muted) {
- m_device->write(m_zero_filled_buffer, 4096);
- } else {
- Array<u8, 4096> buffer;
- OutputMemoryStream stream { buffer };
-
- for (int i = 0; i < mixed_buffer_length; ++i) {
- auto& mixed_sample = mixed_buffer[i];
-
- mixed_sample.scale(m_main_volume);
- mixed_sample.clip();
-
- LittleEndian<i16> out_sample;
- out_sample = mixed_sample.left * NumericLimits<i16>::max();
- stream << out_sample;
-
- out_sample = mixed_sample.right * NumericLimits<i16>::max();
- stream << out_sample;
- }
-
- ASSERT(stream.is_end());
- ASSERT(!stream.has_any_error());
- m_device->write(stream.data(), stream.size());
- }
- }
-}
-
-void Mixer::set_main_volume(int volume)
-{
- if (volume > 100)
- m_main_volume = 100;
- else
- m_main_volume = volume;
- ClientConnection::for_each([volume](ClientConnection& client) {
- client.did_change_main_mix_volume({}, volume);
- });
-}
-
-void Mixer::set_muted(bool muted)
-{
- if (m_muted == muted)
- return;
- m_muted = muted;
- ClientConnection::for_each([muted](ClientConnection& client) {
- client.did_change_muted_state({}, muted);
- });
-}
-
-BufferQueue::BufferQueue(ClientConnection& client)
- : m_client(client)
-{
-}
-
-void BufferQueue::enqueue(NonnullRefPtr<Audio::Buffer>&& buffer)
-{
- m_remaining_samples += buffer->sample_count();
- m_queue.enqueue(move(buffer));
-}
-}
diff --git a/Services/AudioServer/Mixer.h b/Services/AudioServer/Mixer.h
deleted file mode 100644
index 74fbba6ede..0000000000
--- a/Services/AudioServer/Mixer.h
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include "ClientConnection.h"
-#include <AK/Atomic.h>
-#include <AK/Badge.h>
-#include <AK/ByteBuffer.h>
-#include <AK/NonnullRefPtrVector.h>
-#include <AK/Queue.h>
-#include <AK/RefCounted.h>
-#include <AK/WeakPtr.h>
-#include <LibAudio/Buffer.h>
-#include <LibCore/File.h>
-#include <LibThread/Lock.h>
-#include <LibThread/Thread.h>
-
-namespace AudioServer {
-
-class ClientConnection;
-
-class BufferQueue : public RefCounted<BufferQueue> {
-public:
- explicit BufferQueue(ClientConnection&);
- ~BufferQueue() { }
-
- bool is_full() const { return m_queue.size() >= 3; }
- void enqueue(NonnullRefPtr<Audio::Buffer>&&);
-
- bool get_next_sample(Audio::Sample& sample)
- {
- if (m_paused)
- return false;
-
- while (!m_current && !m_queue.is_empty())
- m_current = m_queue.dequeue();
-
- if (!m_current)
- return false;
-
- sample = m_current->samples()[m_position++];
- --m_remaining_samples;
- ++m_played_samples;
-
- if (m_position >= m_current->sample_count()) {
- m_client->did_finish_playing_buffer({}, m_current->shbuf_id());
- m_current = nullptr;
- m_position = 0;
- }
- return true;
- }
-
- ClientConnection* client() { return m_client.ptr(); }
-
- void clear(bool paused = false)
- {
- m_queue.clear();
- m_position = 0;
- m_remaining_samples = 0;
- m_played_samples = 0;
- m_current = nullptr;
- m_paused = paused;
- }
-
- void set_paused(bool paused)
- {
- m_paused = paused;
- }
-
- int get_remaining_samples() const { return m_remaining_samples; }
- int get_played_samples() const { return m_played_samples; }
- int get_playing_buffer() const
- {
- if (m_current)
- return m_current->shbuf_id();
- return -1;
- }
-
-private:
- RefPtr<Audio::Buffer> m_current;
- Queue<NonnullRefPtr<Audio::Buffer>> m_queue;
- int m_position { 0 };
- int m_remaining_samples { 0 };
- int m_played_samples { 0 };
- bool m_paused { false };
- WeakPtr<ClientConnection> m_client;
-};
-
-class Mixer : public Core::Object {
- C_OBJECT(Mixer)
-public:
- Mixer();
- virtual ~Mixer() override;
-
- NonnullRefPtr<BufferQueue> create_queue(ClientConnection&);
-
- int main_volume() const { return m_main_volume; }
- void set_main_volume(int volume);
-
- bool is_muted() const { return m_muted; }
- void set_muted(bool);
-
-private:
- Vector<NonnullRefPtr<BufferQueue>> m_pending_mixing;
- Atomic<bool> m_added_queue { false };
- pthread_mutex_t m_pending_mutex;
- pthread_cond_t m_pending_cond;
-
- RefPtr<Core::File> m_device;
-
- NonnullRefPtr<LibThread::Thread> m_sound_thread;
-
- bool m_muted { false };
- int m_main_volume { 100 };
-
- u8* m_zero_filled_buffer { nullptr };
-
- void mix();
-};
-}
diff --git a/Services/AudioServer/main.cpp b/Services/AudioServer/main.cpp
deleted file mode 100644
index 9eca20bfd3..0000000000
--- a/Services/AudioServer/main.cpp
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "Mixer.h"
-#include <LibCore/File.h>
-#include <LibCore/LocalServer.h>
-
-int main(int, char**)
-{
- if (pledge("stdio thread shared_buffer accept rpath wpath cpath unix fattr", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- Core::EventLoop event_loop;
- AudioServer::Mixer mixer;
-
- auto server = Core::LocalServer::construct();
- bool ok = server->take_over_from_system_server();
- ASSERT(ok);
- server->on_ready_to_accept = [&] {
- auto client_socket = server->accept();
- if (!client_socket) {
- dbgln("AudioServer: accept failed.");
- return;
- }
- static int s_next_client_id = 0;
- int client_id = ++s_next_client_id;
- IPC::new_client_connection<AudioServer::ClientConnection>(client_socket.release_nonnull(), client_id, mixer);
- };
-
- if (pledge("stdio thread shared_buffer accept", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- unveil(nullptr, nullptr);
-
- return event_loop.exec();
-}
diff --git a/Services/CMakeLists.txt b/Services/CMakeLists.txt
deleted file mode 100644
index 26003a7d55..0000000000
--- a/Services/CMakeLists.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-add_subdirectory(AudioServer)
-add_subdirectory(ChessEngine)
-add_subdirectory(Clipboard)
-add_subdirectory(CrashDaemon)
-add_subdirectory(DHCPClient)
-add_subdirectory(EchoServer)
-add_subdirectory(ImageDecoder)
-add_subdirectory(LaunchServer)
-add_subdirectory(LookupServer)
-add_subdirectory(NotificationServer)
-add_subdirectory(ProtocolServer)
-add_subdirectory(SystemMenu)
-add_subdirectory(SystemServer)
-add_subdirectory(Taskbar)
-add_subdirectory(TelnetServer)
-add_subdirectory(WebContent)
-add_subdirectory(WebServer)
-add_subdirectory(WindowServer)
diff --git a/Services/ChessEngine/CMakeLists.txt b/Services/ChessEngine/CMakeLists.txt
deleted file mode 100644
index 288529a100..0000000000
--- a/Services/ChessEngine/CMakeLists.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-set(SOURCES
- ChessEngine.cpp
- main.cpp
- MCTSTree.cpp
-)
-
-serenity_bin(ChessEngine)
-target_link_libraries(ChessEngine LibChess LibCore)
diff --git a/Services/ChessEngine/ChessEngine.cpp b/Services/ChessEngine/ChessEngine.cpp
deleted file mode 100644
index 16394d443c..0000000000
--- a/Services/ChessEngine/ChessEngine.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "ChessEngine.h"
-#include "MCTSTree.h"
-#include <LibCore/ElapsedTimer.h>
-
-using namespace Chess::UCI;
-
-void ChessEngine::handle_uci()
-{
- send_command(IdCommand(IdCommand::Type::Name, "ChessEngine"));
- send_command(IdCommand(IdCommand::Type::Author, "the SerenityOS developers"));
- send_command(UCIOkCommand());
-}
-
-void ChessEngine::handle_position(const PositionCommand& command)
-{
- // FIXME: Implement fen board position.
- ASSERT(!command.fen().has_value());
- m_board = Chess::Board();
- for (auto& move : command.moves()) {
- ASSERT(m_board.apply_move(move));
- }
-}
-
-void ChessEngine::handle_go(const GoCommand& command)
-{
- // FIXME: A better algorithm than naive mcts.
- // FIXME: Add different ways to terminate search.
- ASSERT(command.movetime.has_value());
-
- srand(arc4random());
-
- Core::ElapsedTimer elapsed_time;
- elapsed_time.start();
-
- MCTSTree mcts(m_board);
-
- // FIXME: optimize simulations enough for use.
- mcts.set_eval_method(MCTSTree::EvalMethod::Heuristic);
-
- int rounds = 0;
- while (elapsed_time.elapsed() <= command.movetime.value()) {
- mcts.do_round();
- ++rounds;
- }
- dbg() << "MCTS finished " << rounds << " rounds.";
- dbg() << "MCTS evaluation " << mcts.expected_value();
- auto best_move = mcts.best_move();
- dbg() << "MCTS best move " << best_move.to_long_algebraic();
- send_command(BestMoveCommand(best_move));
-}
diff --git a/Services/ChessEngine/ChessEngine.h b/Services/ChessEngine/ChessEngine.h
deleted file mode 100644
index 54c0cb7c8a..0000000000
--- a/Services/ChessEngine/ChessEngine.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <LibChess/Chess.h>
-#include <LibChess/UCIEndpoint.h>
-
-class ChessEngine : public Chess::UCI::Endpoint {
- C_OBJECT(ChessEngine)
-public:
- virtual ~ChessEngine() override { }
-
- ChessEngine() { }
- ChessEngine(NonnullRefPtr<Core::IODevice> in, NonnullRefPtr<Core::IODevice> out)
- : Endpoint(in, out)
- {
- }
-
- virtual void handle_uci();
- virtual void handle_position(const Chess::UCI::PositionCommand&);
- virtual void handle_go(const Chess::UCI::GoCommand&);
-
-private:
- Chess::Board m_board;
-};
diff --git a/Services/ChessEngine/MCTSTree.cpp b/Services/ChessEngine/MCTSTree.cpp
deleted file mode 100644
index dc195089fe..0000000000
--- a/Services/ChessEngine/MCTSTree.cpp
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "MCTSTree.h"
-#include <AK/String.h>
-#include <stdlib.h>
-
-MCTSTree::MCTSTree(const Chess::Board& board, double exploration_parameter, MCTSTree* parent)
- : m_parent(parent)
- , m_exploration_parameter(exploration_parameter)
- , m_board(board)
-{
- if (m_parent)
- m_eval_method = m_parent->eval_method();
-}
-
-MCTSTree& MCTSTree::select_leaf()
-{
- if (!expanded() || m_children.size() == 0)
- return *this;
-
- MCTSTree* node = nullptr;
- double max_uct = -double(INFINITY);
- for (auto& child : m_children) {
- double uct = child.uct(m_board.turn());
- if (uct >= max_uct) {
- max_uct = uct;
- node = &child;
- }
- }
- ASSERT(node);
- return node->select_leaf();
-}
-
-MCTSTree& MCTSTree::expand()
-{
- ASSERT(!expanded() || m_children.size() == 0);
-
- if (!m_moves_generated) {
- m_board.generate_moves([&](Chess::Move move) {
- Chess::Board clone = m_board;
- clone.apply_move(move);
- m_children.append(make<MCTSTree>(clone, m_exploration_parameter, this));
- return IterationDecision::Continue;
- });
- m_moves_generated = true;
- }
-
- if (m_children.size() == 0) {
- return *this;
- }
-
- for (auto& child : m_children) {
- if (child.m_simulations == 0) {
- return child;
- }
- }
- ASSERT_NOT_REACHED();
-}
-
-int MCTSTree::simulate_game() const
-{
- ASSERT_NOT_REACHED();
- Chess::Board clone = m_board;
- while (!clone.game_finished()) {
- clone.apply_move(clone.random_move());
- }
- return clone.game_score();
-}
-
-int MCTSTree::heuristic() const
-{
- if (m_board.game_finished())
- return m_board.game_score();
-
- double winchance = max(min(double(m_board.material_imbalance()) / 6, 1.0), -1.0);
-
- double random = double(rand()) / RAND_MAX;
- if (winchance >= random)
- return 1;
- if (winchance <= -random)
- return -1;
-
- return 0;
-}
-
-void MCTSTree::apply_result(int game_score)
-{
- m_simulations++;
- m_white_points += game_score;
-
- if (m_parent)
- m_parent->apply_result(game_score);
-}
-
-void MCTSTree::do_round()
-{
- auto& node = select_leaf().expand();
-
- int result;
- if (m_eval_method == EvalMethod::Simulation) {
- result = node.simulate_game();
- } else {
- result = node.heuristic();
- }
- node.apply_result(result);
-}
-
-Chess::Move MCTSTree::best_move() const
-{
- int score_multiplier = (m_board.turn() == Chess::Color::White) ? 1 : -1;
-
- Chess::Move best_move = { { 0, 0 }, { 0, 0 } };
- double best_score = -double(INFINITY);
- ASSERT(m_children.size());
- for (auto& node : m_children) {
- double node_score = node.expected_value() * score_multiplier;
- if (node_score >= best_score) {
- // The best move is the last move made in the child.
- best_move = node.m_board.moves()[node.m_board.moves().size() - 1];
- best_score = node_score;
- }
- }
-
- return best_move;
-}
-
-double MCTSTree::expected_value() const
-{
- if (m_simulations == 0)
- return 0;
-
- return double(m_white_points) / m_simulations;
-}
-
-double MCTSTree::uct(Chess::Color color) const
-{
- // UCT: Upper Confidence Bound Applied to Trees.
- // Kocsis, Levente; Szepesvári, Csaba (2006). "Bandit based Monte-Carlo Planning"
-
- // Fun fact: Szepesvári was my data structures professor.
- double expected = expected_value() * ((color == Chess::Color::White) ? 1 : -1);
- return expected + m_exploration_parameter * sqrt(log(m_parent->m_simulations) / m_simulations);
-}
-
-bool MCTSTree::expanded() const
-{
- if (!m_moves_generated)
- return false;
-
- for (auto& child : m_children) {
- if (child.m_simulations == 0)
- return false;
- }
-
- return true;
-}
diff --git a/Services/ChessEngine/MCTSTree.h b/Services/ChessEngine/MCTSTree.h
deleted file mode 100644
index 0ae68eae8f..0000000000
--- a/Services/ChessEngine/MCTSTree.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <AK/Function.h>
-#include <AK/NonnullOwnPtrVector.h>
-#include <LibChess/Chess.h>
-#include <math.h>
-
-class MCTSTree {
-public:
- enum EvalMethod {
- Simulation,
- Heuristic,
- };
-
- MCTSTree(const Chess::Board& board, double exploration_parameter = sqrt(2), MCTSTree* parent = nullptr);
-
- MCTSTree& select_leaf();
- MCTSTree& expand();
- int simulate_game() const;
- int heuristic() const;
- void apply_result(int game_score);
- void do_round();
-
- Chess::Move best_move() const;
- double expected_value() const;
- double uct(Chess::Color color) const;
- bool expanded() const;
-
- EvalMethod eval_method() const { return m_eval_method; }
- void set_eval_method(EvalMethod method) { m_eval_method = method; }
-
-private:
- NonnullOwnPtrVector<MCTSTree> m_children;
- MCTSTree* m_parent { nullptr };
- int m_white_points { 0 };
- int m_simulations { 0 };
- bool m_moves_generated { false };
- double m_exploration_parameter;
- EvalMethod m_eval_method { EvalMethod::Simulation };
- Chess::Board m_board;
-};
diff --git a/Services/ChessEngine/main.cpp b/Services/ChessEngine/main.cpp
deleted file mode 100644
index 60d6ec8397..0000000000
--- a/Services/ChessEngine/main.cpp
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "ChessEngine.h"
-#include <LibCore/EventLoop.h>
-#include <LibCore/File.h>
-
-int main()
-{
- if (pledge("stdio shared_buffer accept unix rpath cpath fattr", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
- Core::EventLoop loop;
- if (pledge("stdio shared_buffer unix", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
- if (unveil(nullptr, nullptr) < 0) {
- perror("unveil");
- return 1;
- }
-
- auto engine = ChessEngine::construct(Core::File::standard_input(), Core::File::standard_output());
- return loop.exec();
-}
diff --git a/Services/Clipboard/CMakeLists.txt b/Services/Clipboard/CMakeLists.txt
deleted file mode 100644
index 4f0e5ab65a..0000000000
--- a/Services/Clipboard/CMakeLists.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-compile_ipc(ClipboardServer.ipc ClipboardServerEndpoint.h)
-compile_ipc(ClipboardClient.ipc ClipboardClientEndpoint.h)
-
-set(SOURCES
- ClientConnection.cpp
- ClipboardClientEndpoint.h
- ClipboardServerEndpoint.h
- Storage.cpp
- main.cpp
-)
-
-serenity_bin(Clipboard)
-target_link_libraries(Clipboard LibCore LibIPC)
diff --git a/Services/Clipboard/ClientConnection.cpp b/Services/Clipboard/ClientConnection.cpp
deleted file mode 100644
index 9518a4f0b6..0000000000
--- a/Services/Clipboard/ClientConnection.cpp
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <AK/Badge.h>
-#include <AK/SharedBuffer.h>
-#include <Clipboard/ClientConnection.h>
-#include <Clipboard/ClipboardClientEndpoint.h>
-#include <Clipboard/Storage.h>
-
-namespace Clipboard {
-
-static HashMap<int, RefPtr<ClientConnection>> s_connections;
-
-void ClientConnection::for_each_client(Function<void(ClientConnection&)> callback)
-{
- for (auto& it : s_connections) {
- callback(*it.value);
- }
-}
-
-ClientConnection::ClientConnection(NonnullRefPtr<Core::LocalSocket> socket, int client_id)
- : IPC::ClientConnection<ClipboardClientEndpoint, ClipboardServerEndpoint>(*this, move(socket), client_id)
-{
- s_connections.set(client_id, *this);
-}
-
-ClientConnection::~ClientConnection()
-{
-}
-
-void ClientConnection::die()
-{
- s_connections.remove(client_id());
-}
-
-OwnPtr<Messages::ClipboardServer::GreetResponse> ClientConnection::handle(const Messages::ClipboardServer::Greet&)
-{
- return make<Messages::ClipboardServer::GreetResponse>(client_id());
-}
-
-OwnPtr<Messages::ClipboardServer::SetClipboardDataResponse> ClientConnection::handle(const Messages::ClipboardServer::SetClipboardData& message)
-{
- auto shared_buffer = SharedBuffer::create_from_shbuf_id(message.shbuf_id());
- if (!shared_buffer) {
- did_misbehave("SetClipboardData: Bad shared buffer ID");
- return {};
- }
- Storage::the().set_data(*shared_buffer, message.data_size(), message.mime_type(), message.metadata().entries());
- return make<Messages::ClipboardServer::SetClipboardDataResponse>();
-}
-
-OwnPtr<Messages::ClipboardServer::GetClipboardDataResponse> ClientConnection::handle(const Messages::ClipboardServer::GetClipboardData&)
-{
- auto& storage = Storage::the();
-
- i32 shbuf_id = -1;
- if (storage.data_size()) {
- // FIXME: Optimize case where an app is copy/pasting within itself.
- // We can just reuse the SharedBuffer then, since it will have the same peer PID.
- // It would be even nicer if a SharedBuffer could have an arbitrary number of clients..
- RefPtr<SharedBuffer> shared_buffer = SharedBuffer::create_with_size(storage.data_size());
- ASSERT(shared_buffer);
- memcpy(shared_buffer->data<void>(), storage.data(), storage.data_size());
- shared_buffer->seal();
- shared_buffer->share_with(client_pid());
- shbuf_id = shared_buffer->shbuf_id();
-
- // FIXME: This is a workaround for the fact that SharedBuffers will go away if neither side is retaining them.
- // After we respond to GetClipboardData, we have to wait for the client to ref the buffer on his side.
- m_last_sent_buffer = move(shared_buffer);
- }
- return make<Messages::ClipboardServer::GetClipboardDataResponse>(shbuf_id, storage.data_size(), storage.mime_type(), storage.metadata());
-}
-
-void ClientConnection::notify_about_clipboard_change()
-{
- post_message(Messages::ClipboardClient::ClipboardDataChanged(Storage::the().mime_type()));
-}
-
-}
diff --git a/Services/Clipboard/ClientConnection.h b/Services/Clipboard/ClientConnection.h
deleted file mode 100644
index 48794f4f88..0000000000
--- a/Services/Clipboard/ClientConnection.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <AK/HashMap.h>
-#include <Clipboard/ClipboardClientEndpoint.h>
-#include <Clipboard/ClipboardServerEndpoint.h>
-#include <LibIPC/ClientConnection.h>
-
-namespace Clipboard {
-
-class ClientConnection final
- : public IPC::ClientConnection<ClipboardClientEndpoint, ClipboardServerEndpoint>
- , public ClipboardServerEndpoint {
-
- C_OBJECT(ClientConnection);
-
-public:
- explicit ClientConnection(NonnullRefPtr<Core::LocalSocket>, int client_id);
- virtual ~ClientConnection() override;
-
- virtual void die() override;
-
- static void for_each_client(Function<void(ClientConnection&)>);
-
- void notify_about_clipboard_change();
-
-private:
- virtual OwnPtr<Messages::ClipboardServer::GreetResponse> handle(const Messages::ClipboardServer::Greet&) override;
- virtual OwnPtr<Messages::ClipboardServer::GetClipboardDataResponse> handle(const Messages::ClipboardServer::GetClipboardData&) override;
- virtual OwnPtr<Messages::ClipboardServer::SetClipboardDataResponse> handle(const Messages::ClipboardServer::SetClipboardData&) override;
-
- RefPtr<SharedBuffer> m_last_sent_buffer;
-};
-
-}
diff --git a/Services/Clipboard/ClipboardClient.ipc b/Services/Clipboard/ClipboardClient.ipc
deleted file mode 100644
index 50d695e92a..0000000000
--- a/Services/Clipboard/ClipboardClient.ipc
+++ /dev/null
@@ -1,4 +0,0 @@
-endpoint ClipboardClient = 804
-{
- ClipboardDataChanged([UTF8] String mime_type) =|
-}
diff --git a/Services/Clipboard/ClipboardServer.ipc b/Services/Clipboard/ClipboardServer.ipc
deleted file mode 100644
index c0c1fab8c8..0000000000
--- a/Services/Clipboard/ClipboardServer.ipc
+++ /dev/null
@@ -1,7 +0,0 @@
-endpoint ClipboardServer = 802
-{
- Greet() => (i32 client_id)
-
- GetClipboardData() => (i32 shbuf_id, i32 data_size, [UTF8] String mime_type, IPC::Dictionary metadata)
- SetClipboardData(i32 shbuf_id, i32 data_size, [UTF8] String mime_type, IPC::Dictionary metadata) => ()
-}
diff --git a/Services/Clipboard/Storage.cpp b/Services/Clipboard/Storage.cpp
deleted file mode 100644
index 3b745dea16..0000000000
--- a/Services/Clipboard/Storage.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <Clipboard/Storage.h>
-
-namespace Clipboard {
-
-Storage& Storage::the()
-{
- static Storage* s_the;
- if (!s_the)
- s_the = new Storage;
- return *s_the;
-}
-
-Storage::Storage()
-{
-}
-
-Storage::~Storage()
-{
-}
-
-void Storage::set_data(NonnullRefPtr<SharedBuffer> data, size_t data_size, const String& mime_type, const HashMap<String, String>& metadata)
-{
- dbg() << "Storage::set_data <- [" << mime_type << "] " << data->data<void>() << " (" << data_size << " bytes)";
- for (auto& it : metadata) {
- dbg() << " " << it.key << ": " << it.value;
- }
- m_shared_buffer = move(data);
- m_data_size = data_size;
- m_mime_type = mime_type;
- m_metadata = metadata;
-
- if (on_content_change)
- on_content_change();
-}
-
-}
diff --git a/Services/Clipboard/Storage.h b/Services/Clipboard/Storage.h
deleted file mode 100644
index ce194c15f4..0000000000
--- a/Services/Clipboard/Storage.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <AK/Function.h>
-#include <AK/HashMap.h>
-#include <AK/SharedBuffer.h>
-#include <AK/String.h>
-
-namespace Clipboard {
-
-class Storage {
-public:
- static Storage& the();
- ~Storage();
-
- bool has_data() const { return m_shared_buffer; }
-
- const String& mime_type() const { return m_mime_type; }
- const HashMap<String, String>& metadata() const { return m_metadata; }
-
- const u8* data() const
- {
- if (!has_data())
- return nullptr;
- return m_shared_buffer->data<u8>();
- }
-
- size_t data_size() const
- {
- if (has_data())
- return m_data_size;
- return 0;
- }
-
- void set_data(NonnullRefPtr<SharedBuffer>, size_t data_size, const String& mime_type, const HashMap<String, String>& metadata);
-
- Function<void()> on_content_change;
-
-private:
- Storage();
-
- String m_mime_type;
- RefPtr<SharedBuffer> m_shared_buffer;
- size_t m_data_size { 0 };
- HashMap<String, String> m_metadata;
-};
-
-}
diff --git a/Services/Clipboard/main.cpp b/Services/Clipboard/main.cpp
deleted file mode 100644
index b6cae095ee..0000000000
--- a/Services/Clipboard/main.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <Clipboard/ClientConnection.h>
-#include <Clipboard/Storage.h>
-#include <LibCore/EventLoop.h>
-#include <LibCore/LocalServer.h>
-#include <LibIPC/ClientConnection.h>
-
-int main(int, char**)
-{
- if (pledge("stdio shared_buffer accept unix rpath cpath fattr", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
- Core::EventLoop event_loop;
- if (pledge("stdio shared_buffer unix accept", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
- if (unveil(nullptr, nullptr) < 0) {
- perror("unveil");
- return 1;
- }
-
- auto server = Core::LocalServer::construct();
- bool ok = server->take_over_from_system_server();
- ASSERT(ok);
-
- if (pledge("stdio shared_buffer accept", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- server->on_ready_to_accept = [&] {
- auto client_socket = server->accept();
- if (!client_socket) {
- dbgln("Clipboard: accept failed.");
- return;
- }
- static int s_next_client_id = 0;
- int client_id = ++s_next_client_id;
- IPC::new_client_connection<Clipboard::ClientConnection>(client_socket.release_nonnull(), client_id);
- };
-
- Clipboard::Storage::the().on_content_change = [&] {
- Clipboard::ClientConnection::for_each_client([&](auto& client) {
- client.notify_about_clipboard_change();
- });
- };
-
- return event_loop.exec();
-}
diff --git a/Services/CrashDaemon/CMakeLists.txt b/Services/CrashDaemon/CMakeLists.txt
deleted file mode 100644
index 5dcf13aacb..0000000000
--- a/Services/CrashDaemon/CMakeLists.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-set(SOURCES
- main.cpp
-)
-
-serenity_bin(CrashDaemon)
-target_link_libraries(CrashDaemon LibC LibCore LibCoreDump)
diff --git a/Services/CrashDaemon/main.cpp b/Services/CrashDaemon/main.cpp
deleted file mode 100644
index 2453f73699..0000000000
--- a/Services/CrashDaemon/main.cpp
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (c) 2020, Itamar S. <itamar8910@gmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <AK/LexicalPath.h>
-#include <LibCore/DirectoryWatcher.h>
-#include <LibCoreDump/Backtrace.h>
-#include <LibCoreDump/Reader.h>
-#include <serenity.h>
-#include <spawn.h>
-#include <sys/stat.h>
-#include <time.h>
-#include <unistd.h>
-
-static void wait_until_coredump_is_ready(const String& coredump_path)
-{
- while (true) {
- struct stat statbuf;
- if (stat(coredump_path.characters(), &statbuf) < 0) {
- perror("stat");
- ASSERT_NOT_REACHED();
- }
- if (statbuf.st_mode & 0400) // Check if readable
- break;
-
- usleep(10000); // sleep for 10ms
- }
-}
-
-static void print_backtrace(const String& coredump_path)
-{
- auto coredump = CoreDump::Reader::create(coredump_path);
- if (!coredump) {
- dbgln("Could not open coredump '{}'", coredump_path);
- return;
- }
- for (auto& entry : coredump->backtrace().entries())
- dbgln("{}", entry.to_string(true));
-}
-
-static void launch_crash_reporter(const String& coredump_path)
-{
- pid_t child;
- const char* argv[] = { "CrashReporter", coredump_path.characters(), nullptr, nullptr };
- if ((errno = posix_spawn(&child, "/bin/CrashReporter", nullptr, nullptr, const_cast<char**>(argv), environ))) {
- perror("posix_spawn");
- } else {
- if (disown(child) < 0)
- perror("disown");
- }
-}
-
-int main()
-{
- if (pledge("stdio rpath proc exec", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- Core::DirectoryWatcher watcher { "/tmp/coredump" };
- while (true) {
- auto event = watcher.wait_for_event();
- ASSERT(event.has_value());
- if (event.value().type != Core::DirectoryWatcher::Event::Type::ChildAdded)
- continue;
- auto coredump_path = event.value().child_path;
- dbgln("New coredump file: {}", coredump_path);
- wait_until_coredump_is_ready(coredump_path);
- print_backtrace(coredump_path);
- launch_crash_reporter(coredump_path);
- }
-}
diff --git a/Services/DHCPClient/CMakeLists.txt b/Services/DHCPClient/CMakeLists.txt
deleted file mode 100644
index 6fddd4a21f..0000000000
--- a/Services/DHCPClient/CMakeLists.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-set(SOURCES
- DHCPv4Client.cpp
- DHCPv4.cpp
- main.cpp
-)
-
-serenity_bin(DHCPClient)
-target_link_libraries(DHCPClient LibCore)
diff --git a/Services/DHCPClient/DHCPv4.cpp b/Services/DHCPClient/DHCPv4.cpp
deleted file mode 100644
index 36430f4eec..0000000000
--- a/Services/DHCPClient/DHCPv4.cpp
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (c) 2020, The SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "DHCPv4.h"
-
-//#define DHCPV4_DEBUG
-
-ParsedDHCPv4Options DHCPv4Packet::parse_options() const
-{
- ParsedDHCPv4Options options;
- for (size_t index = 4; index < DHCPV4_OPTION_FIELD_MAX_LENGTH; ++index) {
- auto opt_name = *(const DHCPOption*)&m_options[index];
- switch (opt_name) {
- case DHCPOption::Pad:
- continue;
- case DHCPOption::End:
- goto escape;
- default:
- ++index;
- auto length = m_options[index];
- if ((size_t)length > DHCPV4_OPTION_FIELD_MAX_LENGTH - index) {
- dbg() << "Bogus option length " << length << " assuming forgotten END";
- break;
- }
-#ifdef DHCPV4_DEBUG
- dbg() << "DHCP Option " << (u8)opt_name << " with length " << length;
-#endif
- ++index;
- options.options.set(opt_name, { length, &m_options[index] });
- index += length - 1;
- break;
- }
- }
-escape:;
- return options;
-}
diff --git a/Services/DHCPClient/DHCPv4.h b/Services/DHCPClient/DHCPv4.h
deleted file mode 100644
index a773167683..0000000000
--- a/Services/DHCPClient/DHCPv4.h
+++ /dev/null
@@ -1,299 +0,0 @@
-/*
- * Copyright (c) 2020, The SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <AK/Assertions.h>
-#include <AK/ByteBuffer.h>
-#include <AK/Endian.h>
-#include <AK/HashMap.h>
-#include <AK/IPv4Address.h>
-#include <AK/MACAddress.h>
-#include <AK/StringBuilder.h>
-#include <AK/StringView.h>
-#include <AK/Traits.h>
-#include <AK/Types.h>
-#include <string.h>
-
-enum class DHCPv4Flags : u16 {
- Broadcast = 1,
- /* everything else is reserved and must be zero */
-};
-
-enum class DHCPv4Op : u8 {
- BootRequest = 1,
- BootReply = 2
-};
-
-enum class DHCPOption : u8 {
- // BOOTP
- Pad = 0,
- SubnetMask,
- TimeOffset,
- Router,
- TimeServer,
- NameServer,
- DomainNameServer,
- LogServer,
- CookieServer,
- LPRServer,
- ImpressServer,
- ResourceLocationServer,
- HostName,
- BootFileSize,
- MeritDumpFile,
- DomainName,
- SwapServer,
- RootPath,
- ExtensionsPath,
- IPForwardingEnableDisable,
- NonLocalSourceRoutingEnableDisable,
- PolicyFilter,
- MaximumDatagramReassemblySize,
- DefaultIPTTL,
- PathMTUAgingTimeout,
- PathMTUPlateauTable,
- InterfaceMTU,
- AllSubnetsAreLocal,
- BroadcastAddress,
- PerformMaskDiscovery,
- MaskSupplier,
- PerformRouterDiscovery,
- RouterSolicitationAddress,
- StaticRoute,
- TrailerEncapsulation,
- ARPCacheTimeout,
- EthernetEncapsulation,
- TCPDefaultTTL,
- TCPKeepaliveInterval,
- TCPKeepaliveGarbage,
- NetworkInformationServiceDomain,
- NetworkInformationServers,
- NetworkTimeProtocolServers,
- VendorSpecificInformation,
- NetBIOSOverTCPIPNameServer,
- NetBIOSOverTCPIPDatagramDistributionServer,
- NetBIOSOverTCPIPNodeType,
- NetBIOSOverTCPIPScope,
- XWindowSystemFontServer, // wow
- XWindowSystemDisplayManager,
- // DHCP
- RequestedIPAddress = 50,
- IPAddressLeaseTime,
- OptionOverload,
- DHCPMessageType,
- ServerIdentifier,
- ParameterRequestList,
- Message,
- MaximumDHCPMessageSize,
- RenewalT1Time,
- RenewalT2Time,
- ClassIdentifier,
- ClientIdentifier,
- End = 255
-};
-
-enum class DHCPMessageType : u8 {
- DHCPDiscover = 1,
- DHCPOffer,
- DHCPRequest,
- DHCPDecline,
- DHCPAck,
- DHCPNak,
- DHCPRelease,
-};
-
-template<>
-struct AK::Traits<DHCPOption> : public AK::GenericTraits<DHCPOption> {
- static constexpr bool is_trivial() { return true; }
- static unsigned hash(DHCPOption u) { return int_hash((u8)u); }
-};
-
-struct ParsedDHCPv4Options {
- template<typename T>
- Optional<const T> get(DHCPOption option_name) const
- {
- auto option = options.get(option_name);
- if (!option.has_value()) {
- return {};
- }
- auto& value = option.value();
- if (value.length != sizeof(T))
- return {};
- return *(const T*)value.value;
- }
-
- template<typename T>
- Vector<T> get_many(DHCPOption option_name, size_t max_number) const
- {
- Vector<T> values;
-
- auto option = options.get(option_name);
- if (!option.has_value()) {
- return {};
- }
- auto& value = option.value();
- if (value.length < sizeof(T))
- return {};
-
- for (size_t i = 0; i < max_number; ++i) {
- auto offset = i * sizeof(T);
- if (offset >= value.length)
- break;
- values.append(*(T*)((u8*)const_cast<void*>(value.value) + offset));
- }
-
- return values;
- }
-
- String to_string() const
- {
- StringBuilder builder;
- builder.append("DHCP Options (");
- builder.appendf("%zu", options.size());
- builder.append(" entries)\n");
- for (auto& opt : options) {
- builder.appendf("\toption %d (%d bytes):", (u8)opt.key, (u8)opt.value.length);
- for (auto i = 0; i < opt.value.length; ++i)
- builder.appendf(" %u ", ((const u8*)opt.value.value)[i]);
- builder.append('\n');
- }
- return builder.build();
- }
-
- struct DHCPOptionValue {
- u8 length;
- const void* value;
- };
-
- HashMap<DHCPOption, DHCPOptionValue> options;
-};
-
-constexpr auto DHCPV4_OPTION_FIELD_MAX_LENGTH = 312;
-
-class [[gnu::packed]] DHCPv4Packet {
-public:
- u8 op() const { return m_op; }
- void set_op(DHCPv4Op op) { m_op = (u8)op; }
-
- u8 htype() const { return m_htype; }
- void set_htype(u8 htype) { m_htype = htype; }
-
- u8 hlen() const { return m_hlen; }
- void set_hlen(u8 hlen) { m_hlen = hlen; }
-
- u8 hops() const { return m_hops; }
- void set_hops(u8 hops) { m_hops = hops; }
-
- u32 xid() const { return m_xid; }
- void set_xid(u32 xid) { m_xid = xid; }
-
- u16 secs() const { return m_secs; }
- void set_secs(u16 secs) { m_secs = secs; }
-
- u16 flags() const { return m_flags; }
- void set_flags(DHCPv4Flags flags) { m_flags = (u16)flags; }
-
- const IPv4Address& ciaddr() const { return m_ciaddr; }
- const IPv4Address& yiaddr() const { return m_yiaddr; }
- const IPv4Address& siaddr() const { return m_siaddr; }
- const IPv4Address& giaddr() const { return m_giaddr; }
-
- IPv4Address& ciaddr() { return m_ciaddr; }
- IPv4Address& yiaddr() { return m_yiaddr; }
- IPv4Address& siaddr() { return m_siaddr; }
- IPv4Address& giaddr() { return m_giaddr; }
-
- u8* options() { return m_options; }
- ParsedDHCPv4Options parse_options() const;
-
- const MACAddress& chaddr() const { return *(const MACAddress*)&m_chaddr[0]; }
- void set_chaddr(const MACAddress& mac) { *(MACAddress*)&m_chaddr[0] = mac; }
-
- StringView sname() const { return { (const char*)&m_sname[0] }; }
- StringView file() const { return { (const char*)&m_file[0] }; }
-
-private:
- NetworkOrdered<u8> m_op;
- NetworkOrdered<u8> m_htype;
- NetworkOrdered<u8> m_hlen;
- NetworkOrdered<u8> m_hops;
- NetworkOrdered<u32> m_xid;
- NetworkOrdered<u16> m_secs;
- NetworkOrdered<u16> m_flags;
- IPv4Address m_ciaddr;
- IPv4Address m_yiaddr;
- IPv4Address m_siaddr;
- IPv4Address m_giaddr;
- u8 m_chaddr[16]; // 10 bytes of padding at the end
- u8 m_sname[64] { 0 };
- u8 m_file[128] { 0 };
- u8 m_options[DHCPV4_OPTION_FIELD_MAX_LENGTH] { 0 }; // variable, less than 312 bytes
-};
-
-class DHCPv4PacketBuilder {
-public:
- DHCPv4PacketBuilder()
- : m_buffer(ByteBuffer::create_zeroed(sizeof(DHCPv4Packet)))
- {
- auto* options = peek().options();
- // set the magic DHCP cookie value
- options[0] = 99;
- options[1] = 130;
- options[2] = 83;
- options[3] = 99;
- }
-
- void add_option(DHCPOption option, u8 length, const void* data)
- {
- ASSERT(m_can_add);
- // we need enough space to fit the option value, its length, and its data
- ASSERT(next_option_offset + length + 2 < DHCPV4_OPTION_FIELD_MAX_LENGTH);
-
- auto* options = peek().options();
- options[next_option_offset++] = (u8)option;
- memcpy(options + next_option_offset, &length, 1);
- next_option_offset++;
- memcpy(options + next_option_offset, data, length);
- next_option_offset += length;
- }
-
- void set_message_type(DHCPMessageType type) { add_option(DHCPOption::DHCPMessageType, 1, &type); }
-
- DHCPv4Packet& peek() { return *(DHCPv4Packet*)m_buffer.data(); }
- DHCPv4Packet& build()
- {
- add_option(DHCPOption::End, 0, nullptr);
- m_can_add = false;
- return *(DHCPv4Packet*)m_buffer.data();
- }
- size_t size() const { return m_buffer.size(); }
-
-private:
- ByteBuffer m_buffer;
- size_t next_option_offset { 4 };
- bool m_can_add { true };
-};
diff --git a/Services/DHCPClient/DHCPv4Client.cpp b/Services/DHCPClient/DHCPv4Client.cpp
deleted file mode 100644
index 7a759ed427..0000000000
--- a/Services/DHCPClient/DHCPv4Client.cpp
+++ /dev/null
@@ -1,289 +0,0 @@
-/*
- * Copyright (c) 2020, The SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "DHCPv4Client.h"
-#include <AK/ByteBuffer.h>
-#include <AK/Endian.h>
-#include <AK/Function.h>
-#include <LibCore/SocketAddress.h>
-#include <LibCore/Timer.h>
-#include <stdio.h>
-
-//#define DHCPV4CLIENT_DEBUG
-
-static void send(const InterfaceDescriptor& iface, const DHCPv4Packet& packet, Core::Object*)
-{
- int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
- if (fd < 0) {
- dbg() << "ERROR: socket :: " << strerror(errno);
- return;
- }
-
- if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, iface.m_ifname.characters(), IFNAMSIZ) < 0) {
- dbg() << "ERROR: setsockopt(SO_BINDTODEVICE) :: " << strerror(errno);
- return;
- }
-
- sockaddr_in dst;
- memset(&dst, 0, sizeof(dst));
- dst.sin_family = AF_INET;
- dst.sin_port = htons(67);
- dst.sin_addr.s_addr = IPv4Address { 255, 255, 255, 255 }.to_u32();
- memset(&dst.sin_zero, 0, sizeof(dst.sin_zero));
-
- auto rc = sendto(fd, &packet, sizeof(packet), 0, (sockaddr*)&dst, sizeof(dst));
- if (rc < 0) {
- dbg() << "sendto failed with " << strerror(errno);
- // FIXME: what do we do here?
- }
-}
-
-static void set_params(const InterfaceDescriptor& iface, const IPv4Address& ipv4_addr, const IPv4Address& netmask, const IPv4Address& gateway)
-{
- int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
- if (fd < 0) {
- dbg() << "ERROR: socket :: " << strerror(errno);
- return;
- }
-
- struct ifreq ifr;
- memset(&ifr, 0, sizeof(ifr));
-
- bool fits = iface.m_ifname.copy_characters_to_buffer(ifr.ifr_name, IFNAMSIZ);
- if (!fits) {
- dbgln("Interface name doesn't fit into IFNAMSIZ!");
- return;
- }
-
- // set the IP address
- ifr.ifr_addr.sa_family = AF_INET;
- ((sockaddr_in&)ifr.ifr_addr).sin_addr.s_addr = ipv4_addr.to_in_addr_t();
-
- if (ioctl(fd, SIOCSIFADDR, &ifr) < 0) {
- dbg() << "ERROR: ioctl(SIOCSIFADDR) :: " << strerror(errno);
- }
-
- // set the network mask
- ((sockaddr_in&)ifr.ifr_netmask).sin_addr.s_addr = netmask.to_in_addr_t();
-
- if (ioctl(fd, SIOCSIFNETMASK, &ifr) < 0) {
- dbg() << "ERROR: ioctl(SIOCSIFNETMASK) :: " << strerror(errno);
- }
-
- // set the default gateway
- struct rtentry rt;
- memset(&rt, 0, sizeof(rt));
-
- rt.rt_dev = const_cast<char*>(iface.m_ifname.characters());
- rt.rt_gateway.sa_family = AF_INET;
- ((sockaddr_in&)rt.rt_gateway).sin_addr.s_addr = gateway.to_in_addr_t();
- rt.rt_flags = RTF_UP | RTF_GATEWAY;
-
- if (ioctl(fd, SIOCADDRT, &rt) < 0) {
- dbg() << "Error: ioctl(SIOCADDRT) :: " << strerror(errno);
- }
-}
-
-DHCPv4Client::DHCPv4Client(Vector<InterfaceDescriptor> ifnames)
- : m_ifnames(ifnames)
-{
- m_server = Core::UDPServer::construct(this);
- m_server->on_ready_to_receive = [this] {
- auto buffer = m_server->receive(sizeof(DHCPv4Packet));
- dbg() << "Received " << buffer.size() << " bytes";
- if (buffer.size() != sizeof(DHCPv4Packet)) {
- dbg() << "we expected " << sizeof(DHCPv4Packet) << " bytes, this is a bad packet";
- return;
- }
- auto& packet = *(DHCPv4Packet*)buffer.data();
- process_incoming(packet);
- };
-
- if (!m_server->bind({}, 68)) {
- dbgln("The server we just created somehow came already bound, refusing to continue");
- ASSERT_NOT_REACHED();
- }
-
- for (auto& iface : m_ifnames)
- dhcp_discover(iface);
-}
-
-DHCPv4Client::~DHCPv4Client()
-{
-}
-
-void DHCPv4Client::handle_offer(const DHCPv4Packet& packet, const ParsedDHCPv4Options& options)
-{
- dbg() << "We were offered " << packet.yiaddr().to_string() << " for " << options.get<u32>(DHCPOption::IPAddressLeaseTime).value_or(0);
- auto* transaction = const_cast<DHCPv4Transaction*>(m_ongoing_transactions.get(packet.xid()).value_or(nullptr));
- if (!transaction) {
- dbg() << "we're not looking for " << packet.xid();
- return;
- }
- if (transaction->has_ip)
- return;
- if (transaction->accepted_offer) {
- // we've accepted someone's offer, but they haven't given us an ack
- // TODO: maybe record this offer?
- return;
- }
- // TAKE IT...
- transaction->offered_lease_time = options.get<u32>(DHCPOption::IPAddressLeaseTime).value();
- dhcp_request(*transaction, packet);
-}
-
-void DHCPv4Client::handle_ack(const DHCPv4Packet& packet, const ParsedDHCPv4Options& options)
-{
-#ifdef DHCPV4CLIENT_DEBUG
- dbg() << "The DHCP server handed us " << packet.yiaddr().to_string();
- dbg() << "Here are the options: " << options.to_string();
-#endif
- auto* transaction = const_cast<DHCPv4Transaction*>(m_ongoing_transactions.get(packet.xid()).value_or(nullptr));
- if (!transaction) {
- dbg() << "we're not looking for " << packet.xid();
- return;
- }
- transaction->has_ip = true;
- auto& interface = transaction->interface;
- auto new_ip = packet.yiaddr();
- auto lease_time = AK::convert_between_host_and_network_endian(options.get<u32>(DHCPOption::IPAddressLeaseTime).value_or(transaction->offered_lease_time));
- // set a timer for the duration of the lease, we shall renew if needed
- Core::Timer::create_single_shot(
- lease_time * 1000,
- [this, transaction, interface = InterfaceDescriptor { interface }, new_ip] {
- transaction->accepted_offer = false;
- transaction->has_ip = false;
- dhcp_discover(interface, new_ip);
- },
- this);
- set_params(transaction->interface, new_ip, options.get<IPv4Address>(DHCPOption::SubnetMask).value(), options.get_many<IPv4Address>(DHCPOption::Router, 1).first());
-}
-
-void DHCPv4Client::handle_nak(const DHCPv4Packet& packet, const ParsedDHCPv4Options& options)
-{
- dbg() << "The DHCP server told us to go chase our own tail about " << packet.yiaddr().to_string();
- dbg() << "Here are the options: " << options.to_string();
- // make another request a bit later :shrug:
- auto* transaction = const_cast<DHCPv4Transaction*>(m_ongoing_transactions.get(packet.xid()).value_or(nullptr));
- if (!transaction) {
- dbg() << "we're not looking for " << packet.xid();
- return;
- }
- transaction->accepted_offer = false;
- transaction->has_ip = false;
- auto& iface = transaction->interface;
- Core::Timer::create_single_shot(
- 10000,
- [this, iface = InterfaceDescriptor { iface }] {
- dhcp_discover(iface);
- },
- this);
-}
-
-void DHCPv4Client::process_incoming(const DHCPv4Packet& packet)
-{
- auto options = packet.parse_options();
-#ifdef DHCPV4CLIENT_DEBUG
- dbg() << "Here are the options: " << options.to_string();
-#endif
- auto value = options.get<DHCPMessageType>(DHCPOption::DHCPMessageType).value();
- switch (value) {
- case DHCPMessageType::DHCPOffer:
- handle_offer(packet, options);
- break;
- case DHCPMessageType::DHCPAck:
- handle_ack(packet, options);
- break;
- case DHCPMessageType::DHCPNak:
- handle_nak(packet, options);
- break;
- case DHCPMessageType::DHCPDiscover:
- case DHCPMessageType::DHCPRequest:
- case DHCPMessageType::DHCPRelease:
- // These are not for us
- // we're just getting them because there are other people on our subnet
- // broadcasting stuff
- break;
- case DHCPMessageType::DHCPDecline:
- default:
- dbg() << "I dunno what to do with this " << (u8)value;
- ASSERT_NOT_REACHED();
- break;
- }
-}
-
-void DHCPv4Client::dhcp_discover(const InterfaceDescriptor& iface, IPv4Address previous)
-{
- auto transaction_id = rand();
-#ifdef DHCPV4CLIENT_DEBUG
- dbg() << "Trying to lease an IP for " << iface.m_ifname << " with ID " << transaction_id;
- if (!previous.is_zero())
- dbg() << "going to request the server to hand us " << previous.to_string();
-#endif
- DHCPv4PacketBuilder builder;
-
- DHCPv4Packet& packet = builder.peek();
- packet.set_op(DHCPv4Op::BootRequest);
- packet.set_htype(1); // 10mb ethernet
- packet.set_hlen(sizeof(MACAddress));
- packet.set_xid(transaction_id);
- packet.set_flags(DHCPv4Flags::Broadcast);
- packet.ciaddr() = previous;
- packet.set_chaddr(iface.m_mac_address);
- packet.set_secs(65535); // we lie
-
- // set packet options
- builder.set_message_type(DHCPMessageType::DHCPDiscover);
- auto& dhcp_packet = builder.build();
-
- // broadcast the discover request
- send(iface, dhcp_packet, this);
- m_ongoing_transactions.set(transaction_id, make<DHCPv4Transaction>(iface));
-}
-
-void DHCPv4Client::dhcp_request(DHCPv4Transaction& transaction, const DHCPv4Packet& offer)
-{
- auto& iface = transaction.interface;
- dbg() << "Leasing the IP " << offer.yiaddr().to_string() << " for adapter " << iface.m_ifname;
- DHCPv4PacketBuilder builder;
-
- DHCPv4Packet& packet = builder.peek();
- packet.set_op(DHCPv4Op::BootRequest);
- packet.set_htype(1); // 10mb ethernet
- packet.set_hlen(sizeof(MACAddress));
- packet.set_xid(offer.xid());
- packet.set_flags(DHCPv4Flags::Broadcast);
- packet.set_chaddr(iface.m_mac_address);
- packet.set_secs(65535); // we lie
-
- // set packet options
- builder.set_message_type(DHCPMessageType::DHCPRequest);
- auto& dhcp_packet = builder.build();
-
- // broadcast the "request" request
- send(iface, dhcp_packet, this);
- transaction.accepted_offer = true;
-}
diff --git a/Services/DHCPClient/DHCPv4Client.h b/Services/DHCPClient/DHCPv4Client.h
deleted file mode 100644
index 60f76a55ef..0000000000
--- a/Services/DHCPClient/DHCPv4Client.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (c) 2020, The SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include "DHCPv4.h"
-#include <AK/HashMap.h>
-#include <AK/OwnPtr.h>
-#include <AK/String.h>
-#include <AK/Vector.h>
-#include <LibCore/UDPServer.h>
-#include <net/if.h>
-#include <net/route.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-
-struct InterfaceDescriptor {
- String m_ifname;
- MACAddress m_mac_address;
-};
-
-struct DHCPv4Transaction {
- DHCPv4Transaction(InterfaceDescriptor ifname)
- : interface(ifname)
- {
- }
-
- InterfaceDescriptor interface;
- bool accepted_offer { false };
- bool has_ip { false };
- u32 offered_lease_time { 0 };
-};
-
-class DHCPv4Client final : public Core::Object {
- C_OBJECT(DHCPv4Client)
-
-public:
- explicit DHCPv4Client(Vector<InterfaceDescriptor> ifnames);
- virtual ~DHCPv4Client() override;
-
- void dhcp_discover(const InterfaceDescriptor& ifname, IPv4Address previous = IPv4Address { 0, 0, 0, 0 });
- void dhcp_request(DHCPv4Transaction& transaction, const DHCPv4Packet& packet);
-
- void process_incoming(const DHCPv4Packet& packet);
-
- bool id_is_registered(u32 id) { return m_ongoing_transactions.contains(id); }
-
-private:
- HashMap<u32, OwnPtr<DHCPv4Transaction>> m_ongoing_transactions;
- Vector<InterfaceDescriptor> m_ifnames;
- RefPtr<Core::UDPServer> m_server;
-
- void handle_offer(const DHCPv4Packet&, const ParsedDHCPv4Options&);
- void handle_ack(const DHCPv4Packet&, const ParsedDHCPv4Options&);
- void handle_nak(const DHCPv4Packet&, const ParsedDHCPv4Options&);
-};
diff --git a/Services/DHCPClient/main.cpp b/Services/DHCPClient/main.cpp
deleted file mode 100644
index d81750b299..0000000000
--- a/Services/DHCPClient/main.cpp
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (c) 2020, The SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "DHCPv4Client.h"
-#include <AK/JsonArray.h>
-#include <AK/JsonObject.h>
-#include <AK/String.h>
-#include <AK/Types.h>
-#include <LibCore/EventLoop.h>
-#include <LibCore/File.h>
-#include <LibCore/LocalServer.h>
-#include <stdio.h>
-#include <string.h>
-
-static u8 mac_part(const Vector<String>& parts, size_t index)
-{
- auto chars = parts.at(index).characters();
- return (chars[0] - '0') * 16 + (chars[1] - '0');
-}
-
-static MACAddress mac_from_string(const String& str)
-{
- auto chunks = str.split(':');
- ASSERT(chunks.size() == 6); // should we...worry about this?
- return {
- mac_part(chunks, 0), mac_part(chunks, 1), mac_part(chunks, 2),
- mac_part(chunks, 3), mac_part(chunks, 4), mac_part(chunks, 5)
- };
-}
-
-int main([[maybe_unused]] int argc, [[maybe_unused]] char** argv)
-{
- if (pledge("stdio unix inet cpath rpath fattr", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- Core::EventLoop event_loop;
-
- if (unveil("/proc/net/", "r") < 0) {
- perror("unveil");
- return 1;
- }
-
- unveil(nullptr, nullptr);
-
- auto file = Core::File::construct("/proc/net/adapters");
- if (!file->open(Core::IODevice::ReadOnly)) {
- fprintf(stderr, "Error: %s\n", file->error_string());
- return 1;
- }
-
- auto file_contents = file->read_all();
- auto json = JsonValue::from_string(file_contents);
- ASSERT(json.has_value());
- Vector<InterfaceDescriptor> ifnames;
- json.value().as_array().for_each([&ifnames](auto& value) {
- auto if_object = value.as_object();
-
- if (if_object.get("class_name").to_string() == "LoopbackAdapter")
- return;
-
- auto name = if_object.get("name").to_string();
- auto mac = if_object.get("mac_address").to_string();
- ifnames.append({ name, mac_from_string(mac) });
- });
-
- auto client = DHCPv4Client::construct(move(ifnames));
-
- if (pledge("stdio inet", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- return event_loop.exec();
-}
diff --git a/Services/EchoServer/CMakeLists.txt b/Services/EchoServer/CMakeLists.txt
deleted file mode 100644
index e7d67fe14e..0000000000
--- a/Services/EchoServer/CMakeLists.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-set(SOURCES
- Client.cpp
- main.cpp
-)
-
-serenity_bin(EchoServer)
-target_link_libraries(EchoServer LibCore)
diff --git a/Services/EchoServer/Client.cpp b/Services/EchoServer/Client.cpp
deleted file mode 100644
index 874553915b..0000000000
--- a/Services/EchoServer/Client.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "Client.h"
-
-Client::Client(int id, RefPtr<Core::TCPSocket> socket)
- : m_id(id)
- , m_socket(move(socket))
-{
- m_socket->on_ready_to_read = [this] { drain_socket(); };
-}
-
-void Client::drain_socket()
-{
- NonnullRefPtr<Client> protect(*this);
- while (m_socket->can_read()) {
- auto buf = m_socket->read(1024);
-
- dbg() << "Read " << buf.size() << " bytes: " << buf;
-
- if (m_socket->eof()) {
- quit();
- break;
- }
-
- m_socket->write(buf);
- }
-}
-
-void Client::quit()
-{
- m_socket->close();
- if (on_exit)
- on_exit();
-}
diff --git a/Services/EchoServer/Client.h b/Services/EchoServer/Client.h
deleted file mode 100644
index 23359fa79b..0000000000
--- a/Services/EchoServer/Client.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <LibCore/TCPSocket.h>
-
-class Client : public RefCounted<Client> {
-public:
- static NonnullRefPtr<Client> create(int id, RefPtr<Core::TCPSocket> socket)
- {
- return adopt(*new Client(id, move(socket)));
- }
-
- Function<void()> on_exit;
-
-protected:
- Client(int id, RefPtr<Core::TCPSocket> socket);
-
- void drain_socket();
- void quit();
-
-private:
- int m_id { 0 };
- RefPtr<Core::TCPSocket> m_socket;
-};
diff --git a/Services/EchoServer/main.cpp b/Services/EchoServer/main.cpp
deleted file mode 100644
index a4136c3df6..0000000000
--- a/Services/EchoServer/main.cpp
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "Client.h"
-#include <AK/HashMap.h>
-#include <AK/IPv4Address.h>
-#include <LibCore/ArgsParser.h>
-#include <LibCore/EventLoop.h>
-#include <LibCore/TCPServer.h>
-#include <LibCore/TCPSocket.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-int main(int argc, char** argv)
-{
- if (pledge("stdio cpath unix fattr inet id accept", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- if (unveil("/tmp/rpc", "rwc") < 0) {
- perror("unveil");
- return 1;
- }
-
- if (unveil(nullptr, nullptr) < 0) {
- perror("unveil");
- return 1;
- }
-
- int port = 7;
-
- Core::ArgsParser args_parser;
- args_parser.add_option(port, "Port to listen on", "port", 'p', "port");
- args_parser.parse(argc, argv);
-
- if ((u16)port != port) {
- warnln("Invalid port number: {}", port);
- exit(1);
- }
-
- Core::EventLoop event_loop;
-
- auto server = Core::TCPServer::construct();
-
- if (!server->listen({}, port)) {
- warnln("Listening on 0.0.0.0:{} failed", port);
- exit(1);
- }
-
- HashMap<int, NonnullRefPtr<Client>> clients;
- int next_id = 0;
-
- server->on_ready_to_accept = [&next_id, &clients, &server] {
- int id = next_id++;
-
- auto client_socket = server->accept();
- if (!client_socket) {
- perror("accept");
- return;
- }
-
- outln("Client {} connected", id);
-
- auto client = Client::create(id, move(client_socket));
- client->on_exit = [&clients, id] {
- clients.remove(id);
- outln("Client {} disconnected", id);
- };
- clients.set(id, client);
- };
-
- outln("Listening on 0.0.0.0:{}", port);
-
- return event_loop.exec();
-}
diff --git a/Services/ImageDecoder/CMakeLists.txt b/Services/ImageDecoder/CMakeLists.txt
deleted file mode 100644
index 56482fe31d..0000000000
--- a/Services/ImageDecoder/CMakeLists.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-compile_ipc(ImageDecoderServer.ipc ImageDecoderServerEndpoint.h)
-compile_ipc(ImageDecoderClient.ipc ImageDecoderClientEndpoint.h)
-
-set(SOURCES
- ClientConnection.cpp
- main.cpp
- ImageDecoderServerEndpoint.h
- ImageDecoderClientEndpoint.h
-)
-
-serenity_bin(ImageDecoder)
-target_link_libraries(ImageDecoder LibGfx LibIPC)
diff --git a/Services/ImageDecoder/ClientConnection.cpp b/Services/ImageDecoder/ClientConnection.cpp
deleted file mode 100644
index 1e516ccdb9..0000000000
--- a/Services/ImageDecoder/ClientConnection.cpp
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <AK/Badge.h>
-#include <AK/SharedBuffer.h>
-#include <ImageDecoder/ClientConnection.h>
-#include <ImageDecoder/ImageDecoderClientEndpoint.h>
-#include <LibGfx/Bitmap.h>
-#include <LibGfx/ImageDecoder.h>
-#include <LibGfx/SystemTheme.h>
-
-namespace ImageDecoder {
-
-static HashMap<int, RefPtr<ClientConnection>> s_connections;
-
-ClientConnection::ClientConnection(NonnullRefPtr<Core::LocalSocket> socket, int client_id)
- : IPC::ClientConnection<ImageDecoderClientEndpoint, ImageDecoderServerEndpoint>(*this, move(socket), client_id)
-{
- s_connections.set(client_id, *this);
-}
-
-ClientConnection::~ClientConnection()
-{
-}
-
-void ClientConnection::die()
-{
- s_connections.remove(client_id());
- exit(0);
-}
-
-OwnPtr<Messages::ImageDecoderServer::GreetResponse> ClientConnection::handle(const Messages::ImageDecoderServer::Greet& message)
-{
- set_client_pid(message.client_pid());
- return make<Messages::ImageDecoderServer::GreetResponse>(client_id(), getpid());
-}
-
-OwnPtr<Messages::ImageDecoderServer::DecodeImageResponse> ClientConnection::handle(const Messages::ImageDecoderServer::DecodeImage& message)
-{
- auto encoded_buffer = SharedBuffer::create_from_shbuf_id(message.encoded_shbuf_id());
- if (!encoded_buffer) {
-#ifdef IMAGE_DECODER_DEBUG
- dbgln("Could not map encoded data buffer");
-#endif
- return {};
- }
-
- if (message.encoded_size() > (size_t)encoded_buffer->size()) {
-#ifdef IMAGE_DECODER_DEBUG
- dbgln("Encoded buffer is smaller than encoded size");
-#endif
- return {};
- }
-
-#ifdef IMAGE_DECODER_DEBUG
- dbg() << "Trying to decode " << message.encoded_size() << " bytes of image(?) data in shbuf_id=" << message.encoded_shbuf_id() << " (shbuf size: " << encoded_buffer->size() << ")";
-#endif
-
- auto decoder = Gfx::ImageDecoder::create(encoded_buffer->data<u8>(), message.encoded_size());
- auto bitmap = decoder->bitmap();
-
- if (!bitmap) {
-#ifdef IMAGE_DECODER_DEBUG
- dbgln("Could not decode image from encoded data");
-#endif
- return make<Messages::ImageDecoderServer::DecodeImageResponse>(-1, Gfx::IntSize(), (i32)Gfx::BitmapFormat::Invalid, Vector<u32>());
- }
-
- // FIXME: We should fix ShareableBitmap so you can send it in responses as well as requests..
- m_shareable_bitmap = bitmap->to_bitmap_backed_by_shared_buffer();
- m_shareable_bitmap->shared_buffer()->share_with(client_pid());
- Vector<u32> palette;
- if (m_shareable_bitmap->is_indexed()) {
- palette = m_shareable_bitmap->palette_to_vector();
- }
- return make<Messages::ImageDecoderServer::DecodeImageResponse>(m_shareable_bitmap->shbuf_id(), m_shareable_bitmap->size(), (i32)m_shareable_bitmap->format(), palette);
-}
-
-}
diff --git a/Services/ImageDecoder/ClientConnection.h b/Services/ImageDecoder/ClientConnection.h
deleted file mode 100644
index 1447c3b063..0000000000
--- a/Services/ImageDecoder/ClientConnection.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <AK/HashMap.h>
-#include <ImageDecoder/Forward.h>
-#include <ImageDecoder/ImageDecoderClientEndpoint.h>
-#include <ImageDecoder/ImageDecoderServerEndpoint.h>
-#include <LibIPC/ClientConnection.h>
-#include <LibWeb/Forward.h>
-
-namespace ImageDecoder {
-
-class ClientConnection final
- : public IPC::ClientConnection<ImageDecoderClientEndpoint, ImageDecoderServerEndpoint>
- , public ImageDecoderServerEndpoint {
- C_OBJECT(ClientConnection);
-
-public:
- explicit ClientConnection(NonnullRefPtr<Core::LocalSocket>, int client_id);
- ~ClientConnection() override;
-
- virtual void die() override;
-
-private:
- virtual OwnPtr<Messages::ImageDecoderServer::GreetResponse> handle(const Messages::ImageDecoderServer::Greet&) override;
- virtual OwnPtr<Messages::ImageDecoderServer::DecodeImageResponse> handle(const Messages::ImageDecoderServer::DecodeImage&) override;
-
- RefPtr<Gfx::Bitmap> m_shareable_bitmap;
-};
-
-}
diff --git a/Services/ImageDecoder/Forward.h b/Services/ImageDecoder/Forward.h
deleted file mode 100644
index e43ca83960..0000000000
--- a/Services/ImageDecoder/Forward.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-namespace WebContent {
-
-class ClientConnection;
-class PageHost;
-
-}
diff --git a/Services/ImageDecoder/ImageDecoderClient.ipc b/Services/ImageDecoder/ImageDecoderClient.ipc
deleted file mode 100644
index 49dc3862c2..0000000000
--- a/Services/ImageDecoder/ImageDecoderClient.ipc
+++ /dev/null
@@ -1,4 +0,0 @@
-endpoint ImageDecoderClient = 7002
-{
- Dummy() =|
-}
diff --git a/Services/ImageDecoder/ImageDecoderServer.ipc b/Services/ImageDecoder/ImageDecoderServer.ipc
deleted file mode 100644
index 295454282f..0000000000
--- a/Services/ImageDecoder/ImageDecoderServer.ipc
+++ /dev/null
@@ -1,7 +0,0 @@
-endpoint ImageDecoderServer = 7001
-{
- Greet(i32 client_pid) => (i32 client_id, i32 server_pid)
-
- DecodeImage(i32 encoded_shbuf_id, u32 encoded_size) => (i32 decoded_shbuf_id, Gfx::IntSize size, i32 bitmap_format, Vector<u32> palette)
-
-}
diff --git a/Services/ImageDecoder/main.cpp b/Services/ImageDecoder/main.cpp
deleted file mode 100644
index d370f0d00b..0000000000
--- a/Services/ImageDecoder/main.cpp
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <ImageDecoder/ClientConnection.h>
-#include <LibCore/EventLoop.h>
-#include <LibCore/LocalServer.h>
-#include <LibIPC/ClientConnection.h>
-
-int main(int, char**)
-{
- Core::EventLoop event_loop;
- if (pledge("stdio shared_buffer unix", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
- if (unveil(nullptr, nullptr) < 0) {
- perror("unveil");
- return 1;
- }
-
- auto socket = Core::LocalSocket::take_over_accepted_socket_from_system_server();
- IPC::new_client_connection<ImageDecoder::ClientConnection>(socket.release_nonnull(), 1);
- if (pledge("stdio shared_buffer", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
- return event_loop.exec();
-}
diff --git a/Services/LaunchServer/CMakeLists.txt b/Services/LaunchServer/CMakeLists.txt
deleted file mode 100644
index 29308ce7f1..0000000000
--- a/Services/LaunchServer/CMakeLists.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-compile_ipc(LaunchServer.ipc LaunchServerEndpoint.h)
-compile_ipc(LaunchClient.ipc LaunchClientEndpoint.h)
-
-set(SOURCES
- ClientConnection.cpp
- Launcher.cpp
- main.cpp
- LaunchClientEndpoint.h
- LaunchServerEndpoint.h
-)
-
-serenity_bin(LaunchServer)
-target_link_libraries(LaunchServer LibCore LibIPC LibDesktop)
diff --git a/Services/LaunchServer/ClientConnection.cpp b/Services/LaunchServer/ClientConnection.cpp
deleted file mode 100644
index 7ac167c1ae..0000000000
--- a/Services/LaunchServer/ClientConnection.cpp
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright (c) 2020, Nicholas Hollett <niax@niax.co.uk>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "ClientConnection.h"
-#include "Launcher.h"
-#include <AK/HashMap.h>
-#include <AK/URL.h>
-#include <LaunchServer/LaunchClientEndpoint.h>
-
-namespace LaunchServer {
-
-static HashMap<int, RefPtr<ClientConnection>> s_connections;
-ClientConnection::ClientConnection(NonnullRefPtr<Core::LocalSocket> client_socket, int client_id)
- : IPC::ClientConnection<LaunchClientEndpoint, LaunchServerEndpoint>(*this, move(client_socket), client_id)
-{
- s_connections.set(client_id, *this);
-}
-
-ClientConnection::~ClientConnection()
-{
-}
-
-void ClientConnection::die()
-{
- s_connections.remove(client_id());
-}
-
-OwnPtr<Messages::LaunchServer::GreetResponse> ClientConnection::handle(const Messages::LaunchServer::Greet&)
-{
- return make<Messages::LaunchServer::GreetResponse>(client_id());
-}
-
-OwnPtr<Messages::LaunchServer::OpenURLResponse> ClientConnection::handle(const Messages::LaunchServer::OpenURL& request)
-{
- if (!m_allowlist.is_empty()) {
- bool allowed = false;
- for (auto& allowed_handler : m_allowlist) {
- if (allowed_handler.handler_name == request.handler_name()
- && (allowed_handler.any_url || allowed_handler.urls.contains_slow(request.url()))) {
- allowed = true;
- break;
- }
- }
- if (!allowed) {
- // You are not on the list, go home!
- did_misbehave(String::formatted("Client requested a combination of handler/URL that was not on the list: '{}' with '{}'", request.handler_name(), request.url()).characters());
- return {};
- }
- }
-
- URL url(request.url());
- auto result = Launcher::the().open_url(url, request.handler_name());
- return make<Messages::LaunchServer::OpenURLResponse>(result);
-}
-
-OwnPtr<Messages::LaunchServer::GetHandlersForURLResponse> ClientConnection::handle(const Messages::LaunchServer::GetHandlersForURL& request)
-{
- URL url(request.url());
- auto result = Launcher::the().handlers_for_url(url);
- return make<Messages::LaunchServer::GetHandlersForURLResponse>(result);
-}
-
-OwnPtr<Messages::LaunchServer::GetHandlersWithDetailsForURLResponse> ClientConnection::handle(const Messages::LaunchServer::GetHandlersWithDetailsForURL& request)
-{
- URL url(request.url());
- auto result = Launcher::the().handlers_with_details_for_url(url);
- return make<Messages::LaunchServer::GetHandlersWithDetailsForURLResponse>(result);
-}
-
-OwnPtr<Messages::LaunchServer::AddAllowedURLResponse> ClientConnection::handle(const Messages::LaunchServer::AddAllowedURL& request)
-{
- if (m_allowlist_is_sealed) {
- did_misbehave("Got request to add more allowed handlers after list was sealed");
- return {};
- }
-
- if (!request.url().is_valid()) {
- did_misbehave("Got request to allow invalid URL");
- return {};
- }
-
- m_allowlist.empend(String(), false, Vector<URL> { request.url() });
-
- return make<Messages::LaunchServer::AddAllowedURLResponse>();
-}
-
-OwnPtr<Messages::LaunchServer::AddAllowedHandlerWithAnyURLResponse> ClientConnection::handle(const Messages::LaunchServer::AddAllowedHandlerWithAnyURL& request)
-{
- if (m_allowlist_is_sealed) {
- did_misbehave("Got request to add more allowed handlers after list was sealed");
- return {};
- }
-
- if (request.handler_name().is_empty()) {
- did_misbehave("Got request to allow empty handler name");
- return {};
- }
-
- m_allowlist.empend(request.handler_name(), true, Vector<URL>());
-
- return make<Messages::LaunchServer::AddAllowedHandlerWithAnyURLResponse>();
-}
-
-OwnPtr<Messages::LaunchServer::AddAllowedHandlerWithOnlySpecificURLsResponse> ClientConnection::handle(const Messages::LaunchServer::AddAllowedHandlerWithOnlySpecificURLs& request)
-{
- if (m_allowlist_is_sealed) {
- did_misbehave("Got request to add more allowed handlers after list was sealed");
- return {};
- }
-
- if (request.handler_name().is_empty()) {
- did_misbehave("Got request to allow empty handler name");
- return {};
- }
-
- if (request.urls().is_empty()) {
- did_misbehave("Got request to allow empty URL list");
- return {};
- }
-
- m_allowlist.empend(request.handler_name(), false, request.urls());
-
- return make<Messages::LaunchServer::AddAllowedHandlerWithOnlySpecificURLsResponse>();
-}
-
-OwnPtr<Messages::LaunchServer::SealAllowlistResponse> ClientConnection::handle(const Messages::LaunchServer::SealAllowlist&)
-{
- if (m_allowlist_is_sealed) {
- did_misbehave("Got more than one request to seal the allowed handlers list");
- return {};
- }
-
- return make<Messages::LaunchServer::SealAllowlistResponse>();
-}
-
-}
diff --git a/Services/LaunchServer/ClientConnection.h b/Services/LaunchServer/ClientConnection.h
deleted file mode 100644
index 77eef53374..0000000000
--- a/Services/LaunchServer/ClientConnection.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (c) 2020, Nicholas Hollett <niax@niax.co.uk>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <LaunchServer/LaunchClientEndpoint.h>
-#include <LaunchServer/LaunchServerEndpoint.h>
-#include <LibIPC/ClientConnection.h>
-
-namespace LaunchServer {
-
-class ClientConnection final : public IPC::ClientConnection<LaunchClientEndpoint, LaunchServerEndpoint>
- , public LaunchServerEndpoint {
- C_OBJECT(ClientConnection)
-public:
- ~ClientConnection() override;
-
- virtual void die() override;
-
-private:
- explicit ClientConnection(NonnullRefPtr<Core::LocalSocket>, int client_id);
-
- virtual OwnPtr<Messages::LaunchServer::GreetResponse> handle(const Messages::LaunchServer::Greet&) override;
- virtual OwnPtr<Messages::LaunchServer::OpenURLResponse> handle(const Messages::LaunchServer::OpenURL&) override;
- virtual OwnPtr<Messages::LaunchServer::GetHandlersForURLResponse> handle(const Messages::LaunchServer::GetHandlersForURL&) override;
- virtual OwnPtr<Messages::LaunchServer::GetHandlersWithDetailsForURLResponse> handle(const Messages::LaunchServer::GetHandlersWithDetailsForURL&) override;
- virtual OwnPtr<Messages::LaunchServer::AddAllowedURLResponse> handle(const Messages::LaunchServer::AddAllowedURL&) override;
- virtual OwnPtr<Messages::LaunchServer::AddAllowedHandlerWithAnyURLResponse> handle(const Messages::LaunchServer::AddAllowedHandlerWithAnyURL&) override;
- virtual OwnPtr<Messages::LaunchServer::AddAllowedHandlerWithOnlySpecificURLsResponse> handle(const Messages::LaunchServer::AddAllowedHandlerWithOnlySpecificURLs&) override;
- virtual OwnPtr<Messages::LaunchServer::SealAllowlistResponse> handle(const Messages::LaunchServer::SealAllowlist&) override;
-
- struct AllowlistEntry {
- String handler_name;
- bool any_url { false };
- Vector<URL> urls;
- };
-
- Vector<AllowlistEntry> m_allowlist;
- bool m_allowlist_is_sealed { false };
-};
-}
diff --git a/Services/LaunchServer/LaunchClient.ipc b/Services/LaunchServer/LaunchClient.ipc
deleted file mode 100644
index abd4e9ba3d..0000000000
--- a/Services/LaunchServer/LaunchClient.ipc
+++ /dev/null
@@ -1,4 +0,0 @@
-endpoint LaunchClient = 102
-{
- Dummy() =|
-}
diff --git a/Services/LaunchServer/LaunchServer.ipc b/Services/LaunchServer/LaunchServer.ipc
deleted file mode 100644
index 4f50221f4b..0000000000
--- a/Services/LaunchServer/LaunchServer.ipc
+++ /dev/null
@@ -1,12 +0,0 @@
-endpoint LaunchServer = 101
-{
- Greet() => (i32 client_id)
- OpenURL(URL url, String handler_name) => (bool response)
- GetHandlersForURL(URL url) => (Vector<String> handlers)
- GetHandlersWithDetailsForURL(URL url) => (Vector<String> handlers_details)
-
- AddAllowedURL(URL url) => ()
- AddAllowedHandlerWithAnyURL(String handler_name) => ()
- AddAllowedHandlerWithOnlySpecificURLs(String handler_name, Vector<URL> urls) => ()
- SealAllowlist() => ()
-}
diff --git a/Services/LaunchServer/Launcher.cpp b/Services/LaunchServer/Launcher.cpp
deleted file mode 100644
index ad6d025035..0000000000
--- a/Services/LaunchServer/Launcher.cpp
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
- * Copyright (c) 2020, Nicholas Hollett <niax@niax.co.uk>, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "Launcher.h"
-#include <AK/Function.h>
-#include <AK/JsonObject.h>
-#include <AK/JsonObjectSerializer.h>
-#include <AK/JsonValue.h>
-#include <AK/LexicalPath.h>
-#include <AK/StringBuilder.h>
-#include <LibCore/ConfigFile.h>
-#include <LibDesktop/AppFile.h>
-#include <serenity.h>
-#include <spawn.h>
-#include <stdio.h>
-#include <sys/stat.h>
-
-namespace LaunchServer {
-
-static Launcher* s_the;
-static bool spawn(String executable, String argument);
-
-String Handler::name_from_executable(const StringView& executable)
-{
- auto separator = executable.find_last_of('/');
- if (separator.has_value()) {
- auto start = separator.value() + 1;
- return executable.substring_view(start, executable.length() - start);
- }
- return executable;
-}
-
-void Handler::from_executable(Type handler_type, const String& executable)
-{
- this->handler_type = handler_type;
- this->name = name_from_executable(executable);
- this->executable = executable;
-}
-
-String Handler::to_details_str() const
-{
- StringBuilder builder;
- JsonObjectSerializer obj { builder };
- obj.add("executable", executable);
- obj.add("name", name);
- switch (handler_type) {
- case Type::Application:
- obj.add("type", "app");
- break;
- case Type::UserDefault:
- obj.add("type", "userdefault");
- break;
- case Type::UserPreferred:
- obj.add("type", "userpreferred");
- break;
- default:
- break;
- }
- obj.finish();
- return builder.build();
-}
-
-Launcher::Launcher()
-{
- ASSERT(s_the == nullptr);
- s_the = this;
-}
-
-Launcher& Launcher::the()
-{
- ASSERT(s_the);
- return *s_the;
-}
-
-void Launcher::load_handlers(const String& af_dir)
-{
- Desktop::AppFile::for_each([&](auto af) {
- auto app_name = af->name();
- auto app_executable = af->executable();
- HashTable<String> file_types;
- for (auto& file_type : af->launcher_file_types())
- file_types.set(file_type);
- HashTable<String> protocols;
- for (auto& protocol : af->launcher_protocols())
- protocols.set(protocol);
- m_handlers.set(app_executable, { Handler::Type::Default, app_name, app_executable, file_types, protocols });
- },
- af_dir);
-}
-
-void Launcher::load_config(const Core::ConfigFile& cfg)
-{
- for (auto key : cfg.keys("FileType")) {
- auto handler = cfg.read_entry("FileType", key).trim_whitespace();
- if (handler.is_empty())
- continue;
- m_file_handlers.set(key.to_lowercase(), handler);
- }
-
- for (auto key : cfg.keys("Protocol")) {
- auto handler = cfg.read_entry("Protocol", key).trim_whitespace();
- if (handler.is_empty())
- continue;
- m_protocol_handlers.set(key.to_lowercase(), handler);
- }
-}
-
-Vector<String> Launcher::handlers_for_url(const URL& url)
-{
- Vector<String> handlers;
- if (url.protocol() == "file") {
- for_each_handler_for_path(url.path(), [&](auto& handler) -> bool {
- handlers.append(handler.executable);
- return true;
- });
- } else {
- for_each_handler(url.protocol(), m_protocol_handlers, [&](const auto& handler) -> bool {
- if (handler.handler_type != Handler::Type::Default || handler.protocols.contains(url.protocol())) {
- handlers.append(handler.executable);
- return true;
- }
- return false;
- });
- }
- return handlers;
-}
-
-Vector<String> Launcher::handlers_with_details_for_url(const URL& url)
-{
- Vector<String> handlers;
- if (url.protocol() == "file") {
- for_each_handler_for_path(url.path(), [&](auto& handler) -> bool {
- handlers.append(handler.to_details_str());
- return true;
- });
- } else {
- for_each_handler(url.protocol(), m_protocol_handlers, [&](const auto& handler) -> bool {
- if (handler.handler_type != Handler::Type::Default || handler.protocols.contains(url.protocol())) {
- handlers.append(handler.to_details_str());
- return true;
- }
- return false;
- });
- }
- return handlers;
-}
-
-bool Launcher::open_url(const URL& url, const String& handler_name)
-{
- if (!handler_name.is_null())
- return open_with_handler_name(url, handler_name);
-
- if (url.protocol() == "file")
- return open_file_url(url);
-
- return open_with_user_preferences(m_protocol_handlers, url.protocol(), url.to_string());
-}
-
-bool Launcher::open_with_handler_name(const URL& url, const String& handler_name)
-{
- auto handler_optional = m_handlers.get(handler_name);
- if (!handler_optional.has_value())
- return false;
-
- auto& handler = handler_optional.value();
- String argument;
- if (url.protocol() == "file")
- argument = url.path();
- else
- argument = url.to_string();
- return spawn(handler.executable, argument);
-}
-
-bool spawn(String executable, String argument)
-{
- pid_t child_pid;
- const char* argv[] = { executable.characters(), argument.characters(), nullptr };
- if ((errno = posix_spawn(&child_pid, executable.characters(), nullptr, nullptr, const_cast<char**>(argv), environ))) {
- perror("posix_spawn");
- return false;
- } else {
- if (disown(child_pid) < 0)
- perror("disown");
- }
- return true;
-}
-
-Handler Launcher::get_handler_for_executable(Handler::Type handler_type, const String& executable) const
-{
- Handler handler;
- auto existing_handler = m_handlers.get(executable);
- if (existing_handler.has_value()) {
- handler = existing_handler.value();
- handler.handler_type = handler_type;
- } else {
- handler.from_executable(handler_type, executable);
- }
- return handler;
-}
-
-bool Launcher::open_with_user_preferences(const HashMap<String, String>& user_preferences, const String key, const String argument, const String default_program)
-{
- auto program_path = user_preferences.get(key);
- if (program_path.has_value())
- return spawn(program_path.value(), argument);
-
- // There wasn't a handler for this, so try the fallback instead
- program_path = user_preferences.get("*");
- if (program_path.has_value())
- return spawn(program_path.value(), argument);
-
- // Absolute worst case, try the provided default program, if any
- if (!default_program.is_empty())
- return spawn(default_program, argument);
-
- return false;
-}
-
-void Launcher::for_each_handler(const String& key, HashMap<String, String>& user_preference, Function<bool(const Handler&)> f)
-{
- auto user_preferred = user_preference.get(key);
- if (user_preferred.has_value())
- f(get_handler_for_executable(Handler::Type::UserPreferred, user_preferred.value()));
-
- size_t counted = 0;
- for (auto& handler : m_handlers) {
- // Skip over the existing item in the list
- if (user_preferred.has_value() && user_preferred.value() == handler.value.executable)
- continue;
- if (f(handler.value))
- counted++;
- }
-
- auto user_default = user_preference.get("*");
- if (counted == 0 && user_default.has_value())
- f(get_handler_for_executable(Handler::Type::UserDefault, user_default.value()));
-}
-
-void Launcher::for_each_handler_for_path(const String& path, Function<bool(const Handler&)> f)
-{
- struct stat st;
- if (stat(path.characters(), &st) < 0) {
- perror("stat");
- return;
- }
-
- // TODO: Make directory opening configurable
- if (S_ISDIR(st.st_mode)) {
- f(get_handler_for_executable(Handler::Type::Default, "/bin/FileManager"));
- return;
- }
-
- if ((st.st_mode & S_IFMT) == S_IFREG && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)))
- f(get_handler_for_executable(Handler::Type::Application, path));
-
- auto extension = LexicalPath(path).extension().to_lowercase();
-
- for_each_handler(extension, m_file_handlers, [&](const auto& handler) -> bool {
- if (handler.handler_type != Handler::Type::Default || handler.file_types.contains(extension))
- return f(handler);
- return false;
- });
-}
-
-bool Launcher::open_file_url(const URL& url)
-{
- struct stat st;
- if (stat(url.path().characters(), &st) < 0) {
- perror("stat");
- return false;
- }
-
- // TODO: Make directory opening configurable
- if (S_ISDIR(st.st_mode))
- return spawn("/bin/FileManager", url.path());
-
- if ((st.st_mode & S_IFMT) == S_IFREG && st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))
- return spawn(url.path(), {});
-
- auto extension_parts = url.path().to_lowercase().split('.');
- String extension = {};
- if (extension_parts.size() > 1)
- extension = extension_parts.last();
- return open_with_user_preferences(m_file_handlers, extension, url.path(), "/bin/TextEditor");
-}
-}
diff --git a/Services/LaunchServer/Launcher.h b/Services/LaunchServer/Launcher.h
deleted file mode 100644
index 8708cdc258..0000000000
--- a/Services/LaunchServer/Launcher.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (c) 2020, Nicholas Hollett <niax@niax.co.uk>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <AK/HashMap.h>
-#include <AK/HashTable.h>
-#include <AK/URL.h>
-#include <LibCore/ConfigFile.h>
-#include <LibDesktop/AppFile.h>
-
-namespace LaunchServer {
-
-struct Handler {
- enum class Type {
- Default = 0,
- Application,
- UserPreferred,
- UserDefault
- };
- Type handler_type;
- String name;
- String executable;
- HashTable<String> file_types {};
- HashTable<String> protocols {};
-
- static String name_from_executable(const StringView&);
- void from_executable(Type, const String&);
- String to_details_str() const;
-};
-
-class Launcher {
-public:
- Launcher();
- static Launcher& the();
-
- void load_handlers(const String& af_dir = Desktop::AppFile::APP_FILES_DIRECTORY);
- void load_config(const Core::ConfigFile&);
- bool open_url(const URL&, const String& handler_name);
- Vector<String> handlers_for_url(const URL&);
- Vector<String> handlers_with_details_for_url(const URL&);
-
-private:
- HashMap<String, Handler> m_handlers;
- HashMap<String, String> m_protocol_handlers;
- HashMap<String, String> m_file_handlers;
-
- Handler get_handler_for_executable(Handler::Type, const String&) const;
- void for_each_handler(const String& key, HashMap<String, String>& user_preferences, Function<bool(const Handler&)> f);
- void for_each_handler_for_path(const String&, Function<bool(const Handler&)> f);
- bool open_file_url(const URL&);
- bool open_with_user_preferences(const HashMap<String, String>& user_preferences, const String key, const String argument, const String default_program = {});
- bool open_with_handler_name(const URL&, const String& handler_name);
-};
-}
diff --git a/Services/LaunchServer/main.cpp b/Services/LaunchServer/main.cpp
deleted file mode 100644
index 2535d1e8bb..0000000000
--- a/Services/LaunchServer/main.cpp
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (c) 2020, Nicholas Hollett <niax@niax.co.uk>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "ClientConnection.h"
-#include "Launcher.h"
-#include <LibCore/ConfigFile.h>
-#include <LibCore/EventLoop.h>
-#include <LibCore/LocalServer.h>
-#include <stdio.h>
-#include <unistd.h>
-
-int main([[maybe_unused]] int argc, [[maybe_unused]] char** argv)
-{
- Core::EventLoop event_loop;
- auto server = Core::LocalServer::construct();
-
- auto launcher = LaunchServer::Launcher();
-
- launcher.load_handlers();
- launcher.load_config(Core::ConfigFile::get_for_app("LaunchServer"));
-
- if (pledge("stdio accept rpath proc exec", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- bool ok = server->take_over_from_system_server();
- ASSERT(ok);
- server->on_ready_to_accept = [&] {
- auto client_socket = server->accept();
- if (!client_socket) {
- dbgln("LaunchServer: accept failed.");
- return;
- }
- static int s_next_client_id = 0;
- int client_id = ++s_next_client_id;
- dbgln("Received connection");
- IPC::new_client_connection<LaunchServer::ClientConnection>(client_socket.release_nonnull(), client_id);
- };
-
- return event_loop.exec();
-}
diff --git a/Services/LookupServer/CMakeLists.txt b/Services/LookupServer/CMakeLists.txt
deleted file mode 100644
index 89769d4abc..0000000000
--- a/Services/LookupServer/CMakeLists.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-set(SOURCES
- DNSAnswer.cpp
- DNSRequest.cpp
- DNSResponse.cpp
- LookupServer.cpp
- main.cpp
-)
-
-serenity_bin(LookupServer)
-target_link_libraries(LookupServer LibCore)
diff --git a/Services/LookupServer/DNSAnswer.cpp b/Services/LookupServer/DNSAnswer.cpp
deleted file mode 100644
index 775c23784e..0000000000
--- a/Services/LookupServer/DNSAnswer.cpp
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "DNSAnswer.h"
-#include <time.h>
-
-DNSAnswer::DNSAnswer(const String& name, u16 type, u16 class_code, u32 ttl, const String& record_data)
- : m_name(name)
- , m_type(type)
- , m_class_code(class_code)
- , m_ttl(ttl)
- , m_record_data(record_data)
-{
- auto now = time(nullptr);
- m_expiration_time = now + m_ttl;
- if (m_expiration_time < now)
- m_expiration_time = 0;
-}
-
-bool DNSAnswer::has_expired() const
-{
- return time(nullptr) >= m_expiration_time;
-}
diff --git a/Services/LookupServer/DNSAnswer.h b/Services/LookupServer/DNSAnswer.h
deleted file mode 100644
index 794603dd30..0000000000
--- a/Services/LookupServer/DNSAnswer.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <AK/String.h>
-#include <AK/Types.h>
-
-class DNSAnswer {
-public:
- DNSAnswer(const String& name, u16 type, u16 class_code, u32 ttl, const String& record_data);
-
- const String& name() const { return m_name; }
- u16 type() const { return m_type; }
- u16 class_code() const { return m_class_code; }
- u32 ttl() const { return m_ttl; }
- const String& record_data() const { return m_record_data; }
-
- bool has_expired() const;
-
-private:
- String m_name;
- u16 m_type { 0 };
- u16 m_class_code { 0 };
- u32 m_ttl { 0 };
- time_t m_expiration_time { 0 };
- String m_record_data;
-};
diff --git a/Services/LookupServer/DNSPacket.h b/Services/LookupServer/DNSPacket.h
deleted file mode 100644
index 1cddc372c7..0000000000
--- a/Services/LookupServer/DNSPacket.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <AK/Endian.h>
-#include <AK/Types.h>
-
-class [[gnu::packed]] DNSPacket {
-public:
- DNSPacket()
- : m_recursion_desired(false)
- , m_truncated(false)
- , m_authoritative_answer(false)
- , m_opcode(0)
- , m_query_or_response(false)
- , m_response_code(0)
- , m_checking_disabled(false)
- , m_authenticated_data(false)
- , m_zero(false)
- , m_recursion_available(false)
- {
- }
-
- u16 id() const { return m_id; }
- void set_id(u16 w) { m_id = w; }
-
- bool recursion_desired() const { return m_recursion_desired; }
- void set_recursion_desired(bool b) { m_recursion_desired = b; }
-
- bool is_truncated() const { return m_truncated; }
- void set_truncated(bool b) { m_truncated = b; }
-
- bool is_authoritative_answer() const { return m_authoritative_answer; }
- void set_authoritative_answer(bool b) { m_authoritative_answer = b; }
-
- u8 opcode() const { return m_opcode; }
- void set_opcode(u8 b) { m_opcode = b; }
-
- bool is_query() const { return !m_query_or_response; }
- bool is_response() const { return m_query_or_response; }
- void set_is_query() { m_query_or_response = false; }
- void set_is_response() { m_query_or_response = true; }
-
- u8 response_code() const { return m_response_code; }
- void set_response_code(u8 b) { m_response_code = b; }
-
- bool checking_disabled() const { return m_checking_disabled; }
- void set_checking_disabled(bool b) { m_checking_disabled = b; }
-
- bool is_authenticated_data() const { return m_authenticated_data; }
- void set_authenticated_data(bool b) { m_authenticated_data = b; }
-
- bool is_recursion_available() const { return m_recursion_available; }
- void set_recursion_available(bool b) { m_recursion_available = b; }
-
- u16 question_count() const { return m_question_count; }
- void set_question_count(u16 w) { m_question_count = w; }
-
- u16 answer_count() const { return m_answer_count; }
- void set_answer_count(u16 w) { m_answer_count = w; }
-
- u16 authority_count() const { return m_authority_count; }
- void set_authority_count(u16 w) { m_authority_count = w; }
-
- u16 additional_count() const { return m_additional_count; }
- void set_additional_count(u16 w) { m_additional_count = w; }
-
- void* payload() { return this + 1; }
- const void* payload() const { return this + 1; }
-
-private:
- NetworkOrdered<u16> m_id;
-
- bool m_recursion_desired : 1;
- bool m_truncated : 1;
- bool m_authoritative_answer : 1;
- u8 m_opcode : 4;
- bool m_query_or_response : 1;
- u8 m_response_code : 4;
- bool m_checking_disabled : 1;
- bool m_authenticated_data : 1;
- bool m_zero : 1;
- bool m_recursion_available : 1;
-
- NetworkOrdered<u16> m_question_count;
- NetworkOrdered<u16> m_answer_count;
- NetworkOrdered<u16> m_authority_count;
- NetworkOrdered<u16> m_additional_count;
-};
-
-static_assert(sizeof(DNSPacket) == 12);
diff --git a/Services/LookupServer/DNSQuestion.h b/Services/LookupServer/DNSQuestion.h
deleted file mode 100644
index ec696905e6..0000000000
--- a/Services/LookupServer/DNSQuestion.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <AK/String.h>
-#include <AK/Types.h>
-
-class DNSQuestion {
-public:
- DNSQuestion(const String& name, u16 record_type, u16 class_code)
- : m_name(name)
- , m_record_type(record_type)
- , m_class_code(class_code)
- {
- }
-
- u16 record_type() const { return m_record_type; }
- u16 class_code() const { return m_class_code; }
- const String& name() const { return m_name; }
-
- bool operator==(const DNSQuestion& other) const
- {
- return m_name == other.m_name && m_record_type == other.m_record_type && m_class_code == other.m_class_code;
- }
-
- bool operator!=(const DNSQuestion& other) const
- {
- return !(*this == other);
- }
-
-private:
- String m_name;
- u16 m_record_type { 0 };
- u16 m_class_code { 0 };
-};
diff --git a/Services/LookupServer/DNSRequest.cpp b/Services/LookupServer/DNSRequest.cpp
deleted file mode 100644
index 561e988ac9..0000000000
--- a/Services/LookupServer/DNSRequest.cpp
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "DNSRequest.h"
-#include "DNSPacket.h"
-#include <AK/MemoryStream.h>
-#include <AK/StringBuilder.h>
-#include <arpa/inet.h>
-#include <ctype.h>
-#include <stdlib.h>
-
-const u16 C_IN = 1;
-
-DNSRequest::DNSRequest()
- : m_id(arc4random_uniform(UINT16_MAX))
-{
-}
-
-void DNSRequest::add_question(const String& name, u16 record_type, ShouldRandomizeCase should_randomize_case)
-{
- ASSERT(m_questions.size() <= UINT16_MAX);
-
- if (name.is_empty())
- return;
-
- StringBuilder builder;
- for (size_t i = 0; i < name.length(); ++i) {
- u8 ch = name[i];
- if (should_randomize_case == ShouldRandomizeCase::Yes) {
- // Randomize the 0x20 bit in every ASCII character.
- if (isalpha(ch)) {
- if (arc4random_uniform(2))
- ch |= 0x20;
- else
- ch &= ~0x20;
- }
- }
- builder.append(ch);
- }
-
- if (name[name.length() - 1] != '.')
- builder.append('.');
-
- m_questions.empend(builder.to_string(), record_type, C_IN);
-}
-
-ByteBuffer DNSRequest::to_byte_buffer() const
-{
- DNSPacket request_header;
- request_header.set_id(m_id);
- request_header.set_is_query();
- request_header.set_opcode(0);
- request_header.set_truncated(false);
- request_header.set_recursion_desired(true);
- request_header.set_question_count(m_questions.size());
-
- DuplexMemoryStream stream;
-
- stream << ReadonlyBytes { &request_header, sizeof(request_header) };
-
- for (auto& question : m_questions) {
- auto parts = question.name().split('.');
- for (auto& part : parts) {
- stream << (u8)part.length();
- stream << part.bytes();
- }
- stream << '\0';
- stream << htons(question.record_type());
- stream << htons(question.class_code());
- }
-
- return stream.copy_into_contiguous_buffer();
-}
diff --git a/Services/LookupServer/DNSRequest.h b/Services/LookupServer/DNSRequest.h
deleted file mode 100644
index 2b55dd75fb..0000000000
--- a/Services/LookupServer/DNSRequest.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include "DNSQuestion.h"
-#include <AK/Types.h>
-#include <AK/Vector.h>
-
-#define T_A 1
-#define T_NS 2
-#define T_CNAME 5
-#define T_SOA 6
-#define T_PTR 12
-#define T_MX 15
-
-enum class ShouldRandomizeCase {
- No = 0,
- Yes
-};
-
-class DNSRequest {
-public:
- DNSRequest();
-
- void add_question(const String& name, u16 record_type, ShouldRandomizeCase);
-
- const Vector<DNSQuestion>& questions() const { return m_questions; }
-
- u16 question_count() const
- {
- ASSERT(m_questions.size() < UINT16_MAX);
- return m_questions.size();
- }
-
- u16 id() const { return m_id; }
- ByteBuffer to_byte_buffer() const;
-
-private:
- u16 m_id { 0 };
- Vector<DNSQuestion> m_questions;
-};
diff --git a/Services/LookupServer/DNSResponse.cpp b/Services/LookupServer/DNSResponse.cpp
deleted file mode 100644
index 54f4a985e8..0000000000
--- a/Services/LookupServer/DNSResponse.cpp
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "DNSResponse.h"
-#include "DNSPacket.h"
-#include "DNSRequest.h"
-#include <AK/IPv4Address.h>
-#include <AK/StringBuilder.h>
-
-static String parse_dns_name(const u8* data, size_t& offset, size_t max_offset, size_t recursion_level = 0);
-
-class [[gnu::packed]] DNSRecordWithoutName {
-public:
- DNSRecordWithoutName() { }
-
- u16 type() const { return m_type; }
- u16 record_class() const { return m_class; }
- u32 ttl() const { return m_ttl; }
- u16 data_length() const { return m_data_length; }
-
- void* data() { return this + 1; }
- const void* data() const { return this + 1; }
-
-private:
- NetworkOrdered<u16> m_type;
- NetworkOrdered<u16> m_class;
- NetworkOrdered<u32> m_ttl;
- NetworkOrdered<u16> m_data_length;
-};
-
-static_assert(sizeof(DNSRecordWithoutName) == 10);
-
-Optional<DNSResponse> DNSResponse::from_raw_response(const u8* raw_data, size_t raw_size)
-{
- if (raw_size < sizeof(DNSPacket)) {
- dbgln("DNS response not large enough ({} out of {}) to be a DNS packet.", raw_size, sizeof(DNSPacket));
- return {};
- }
-
- auto& response_header = *(const DNSPacket*)(raw_data);
-#ifdef LOOKUPSERVER_DEBUG
- dbgln("Got response (ID: {})", response_header.id());
- dbgln(" Question count: {}", response_header.question_count());
- dbgln(" Answer count: {}", response_header.answer_count());
- dbgln(" Authority count: {}", response_header.authority_count());
- dbgln("Additional count: {}", response_header.additional_count());
-#endif
-
- DNSResponse response;
- response.m_id = response_header.id();
- response.m_code = response_header.response_code();
-
- if (response.code() != DNSResponse::Code::NOERROR)
- return response;
-
- size_t offset = sizeof(DNSPacket);
-
- for (u16 i = 0; i < response_header.question_count(); ++i) {
- auto name = parse_dns_name(raw_data, offset, raw_size);
- struct RawDNSAnswerQuestion {
- NetworkOrdered<u16> record_type;
- NetworkOrdered<u16> class_code;
- };
- auto& record_and_class = *(const RawDNSAnswerQuestion*)&raw_data[offset];
- response.m_questions.empend(name, record_and_class.record_type, record_and_class.class_code);
- offset += 4;
-#ifdef LOOKUPSERVER_DEBUG
- auto& question = response.m_questions.last();
- dbgln("Question #{}: name=_{}_, type={}, class={}", i, question.name(), question.record_type(), question.class_code());
-#endif
- }
-
- for (u16 i = 0; i < response_header.answer_count(); ++i) {
- auto name = parse_dns_name(raw_data, offset, raw_size);
-
- auto& record = *(const DNSRecordWithoutName*)(&raw_data[offset]);
-
- String data;
-
- offset += sizeof(DNSRecordWithoutName);
- if (record.type() == T_PTR) {
- size_t dummy_offset = offset;
- data = parse_dns_name(raw_data, dummy_offset, raw_size);
- } else if (record.type() == T_A) {
- auto ipv4_address = IPv4Address((const u8*)record.data());
- data = ipv4_address.to_string();
- } else {
- // FIXME: Parse some other record types perhaps?
- dbgln("data=(unimplemented record type {})", record.type());
- }
-#ifdef LOOKUPSERVER_DEBUG
- dbgln("Answer #{}: name=_{}_, type={}, ttl={}, length={}, data=_{}_", i, name, record.type(), record.ttl(), record.data_length(), data);
-#endif
- response.m_answers.empend(name, record.type(), record.record_class(), record.ttl(), data);
- offset += record.data_length();
- }
-
- return response;
-}
-
-String parse_dns_name(const u8* data, size_t& offset, size_t max_offset, size_t recursion_level)
-{
- if (recursion_level > 4)
- return {};
- Vector<char, 128> buf;
- while (offset < max_offset) {
- u8 ch = data[offset];
- if (ch == '\0') {
- ++offset;
- break;
- }
- if ((ch & 0xc0) == 0xc0) {
- if ((offset + 1) >= max_offset)
- return {};
- size_t dummy = (ch & 0x3f) << 8 | data[offset + 1];
- offset += 2;
- StringBuilder builder;
- builder.append(buf.data(), buf.size());
- auto okay = parse_dns_name(data, dummy, max_offset, recursion_level + 1);
- builder.append(okay);
- return builder.to_string();
- }
- for (size_t i = 0; i < ch; ++i)
- buf.append(data[offset + i + 1]);
- buf.append('.');
- offset += ch + 1;
- }
- return String::copy(buf);
-}
diff --git a/Services/LookupServer/DNSResponse.h b/Services/LookupServer/DNSResponse.h
deleted file mode 100644
index 2bfe17fecd..0000000000
--- a/Services/LookupServer/DNSResponse.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include "DNSAnswer.h"
-#include "DNSQuestion.h"
-#include <AK/Optional.h>
-#include <AK/Types.h>
-#include <AK/Vector.h>
-
-class DNSResponse {
-public:
- static Optional<DNSResponse> from_raw_response(const u8*, size_t);
-
- u16 id() const { return m_id; }
- const Vector<DNSQuestion>& questions() const { return m_questions; }
- const Vector<DNSAnswer>& answers() const { return m_answers; }
-
- u16 question_count() const
- {
- ASSERT(m_questions.size() <= UINT16_MAX);
- return m_questions.size();
- }
-
- u16 answer_count() const
- {
- ASSERT(m_answers.size() <= UINT16_MAX);
- return m_answers.size();
- }
-
- enum class Code : u8 {
- NOERROR = 0,
- FORMERR = 1,
- SERVFAIL = 2,
- NXDOMAIN = 3,
- NOTIMP = 4,
- REFUSED = 5,
- YXDOMAIN = 6,
- XRRSET = 7,
- NOTAUTH = 8,
- NOTZONE = 9,
- };
-
- Code code() const { return (Code)m_code; }
-
-private:
- DNSResponse() { }
-
- u16 m_id { 0 };
- u8 m_code { 0 };
- Vector<DNSQuestion> m_questions;
- Vector<DNSAnswer> m_answers;
-};
diff --git a/Services/LookupServer/LookupServer.cpp b/Services/LookupServer/LookupServer.cpp
deleted file mode 100644
index 16761ec7e4..0000000000
--- a/Services/LookupServer/LookupServer.cpp
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "LookupServer.h"
-#include "DNSRequest.h"
-#include "DNSResponse.h"
-#include <AK/ByteBuffer.h>
-#include <AK/HashMap.h>
-#include <AK/String.h>
-#include <AK/StringBuilder.h>
-#include <LibCore/ConfigFile.h>
-#include <LibCore/File.h>
-#include <LibCore/LocalServer.h>
-#include <LibCore/LocalSocket.h>
-#include <LibCore/UDPSocket.h>
-#include <stdio.h>
-#include <sys/time.h>
-#include <unistd.h>
-
-//#define LOOKUPSERVER_DEBUG
-
-LookupServer::LookupServer()
-{
- auto config = Core::ConfigFile::get_for_system("LookupServer");
- dbgln("Using network config file at {}", config->file_name());
- m_nameservers = config->read_entry("DNS", "Nameservers", "1.1.1.1,1.0.0.1").split(',');
-
- load_etc_hosts();
-
- m_local_server = Core::LocalServer::construct(this);
- m_local_server->on_ready_to_accept = [this]() {
- auto socket = m_local_server->accept();
- socket->on_ready_to_read = [this, socket]() {
- service_client(socket);
- RefPtr<Core::LocalSocket> keeper = socket;
- const_cast<Core::LocalSocket&>(*socket).on_ready_to_read = [] {};
- };
- };
- bool ok = m_local_server->take_over_from_system_server();
- ASSERT(ok);
-}
-
-void LookupServer::load_etc_hosts()
-{
- auto file = Core::File::construct("/etc/hosts");
- if (!file->open(Core::IODevice::ReadOnly))
- return;
- while (!file->eof()) {
- auto line = file->read_line(1024);
- if (line.is_empty())
- break;
- auto fields = line.split('\t');
-
- auto sections = fields[0].split('.');
- IPv4Address addr {
- (u8)atoi(sections[0].characters()),
- (u8)atoi(sections[1].characters()),
- (u8)atoi(sections[2].characters()),
- (u8)atoi(sections[3].characters()),
- };
-
- auto name = fields[1];
- m_etc_hosts.set(name, addr.to_string());
-
- IPv4Address reverse_addr {
- (u8)atoi(sections[3].characters()),
- (u8)atoi(sections[2].characters()),
- (u8)atoi(sections[1].characters()),
- (u8)atoi(sections[0].characters()),
- };
- StringBuilder builder;
- builder.append(reverse_addr.to_string());
- builder.append(".in-addr.arpa");
- m_etc_hosts.set(builder.to_string(), name);
- }
-}
-
-void LookupServer::service_client(RefPtr<Core::LocalSocket> socket)
-{
- u8 client_buffer[1024];
- int nrecv = socket->read(client_buffer, sizeof(client_buffer) - 1);
- if (nrecv < 0) {
- perror("read");
- return;
- }
-
- client_buffer[nrecv] = '\0';
-
- char lookup_type = client_buffer[0];
- if (lookup_type != 'L' && lookup_type != 'R') {
- dbgln("Invalid lookup_type '{}'", lookup_type);
- return;
- }
- auto hostname = String((const char*)client_buffer + 1, nrecv - 1, Chomp);
-#ifdef LOOKUPSERVER_DEBUG
- dbgln("Got request for '{}'", hostname);
-#endif
-
- Vector<String> responses;
-
- if (auto known_host = m_etc_hosts.get(hostname); known_host.has_value()) {
- responses.append(known_host.value());
- } else if (!hostname.is_empty()) {
- for (auto& nameserver : m_nameservers) {
-#ifdef LOOKUPSERVER_DEBUG
- dbgln("Doing lookup using nameserver '{}'", nameserver);
-#endif
- bool did_get_response = false;
- int retries = 3;
- do {
- if (lookup_type == 'L')
- responses = lookup(hostname, nameserver, did_get_response, T_A);
- else if (lookup_type == 'R')
- responses = lookup(hostname, nameserver, did_get_response, T_PTR);
- if (did_get_response)
- break;
- } while (--retries);
- if (!responses.is_empty()) {
- break;
- } else {
- if (!did_get_response)
- dbgln("Never got a response from '{}', trying next nameserver", nameserver);
- else
- dbgln("Received response from '{}' but no result(s), trying next nameserver", nameserver);
- }
- }
- if (responses.is_empty()) {
- fprintf(stderr, "LookupServer: Tried all nameservers but never got a response :(\n");
- return;
- }
- }
-
- if (responses.is_empty()) {
- int nsent = socket->write("Not found.\n");
- if (nsent < 0)
- perror("write");
- return;
- }
- for (auto& response : responses) {
- auto line = String::format("%s\n", response.characters());
- int nsent = socket->write(line);
- if (nsent < 0) {
- perror("write");
- break;
- }
- }
-}
-
-Vector<String> LookupServer::lookup(const String& hostname, const String& nameserver, bool& did_get_response, unsigned short record_type, ShouldRandomizeCase should_randomize_case)
-{
- if (auto it = m_lookup_cache.find(hostname); it != m_lookup_cache.end()) {
- auto& cached_lookup = it->value;
- if (cached_lookup.question.record_type() == record_type) {
- Vector<String> responses;
- for (auto& cached_answer : cached_lookup.answers) {
-#ifdef LOOKUPSERVER_DEBUG
- dbgln("Cache hit: {} -> {}, expired: {}", hostname, cached_answer.record_data(), cached_answer.has_expired());
-#endif
- if (!cached_answer.has_expired())
- responses.append(cached_answer.record_data());
- }
- if (!responses.is_empty())
- return responses;
- }
- m_lookup_cache.remove(it);
- }
-
- DNSRequest request;
- request.add_question(hostname, record_type, should_randomize_case);
-
- auto buffer = request.to_byte_buffer();
-
- auto udp_socket = Core::UDPSocket::construct();
- udp_socket->set_blocking(true);
-
- struct timeval timeout {
- 1, 0
- };
-
- int rc = setsockopt(udp_socket->fd(), SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
- if (rc < 0) {
- perror("setsockopt(SOL_SOCKET, SO_RCVTIMEO)");
- return {};
- }
-
- if (!udp_socket->connect(nameserver, 53))
- return {};
-
- if (!udp_socket->write(buffer))
- return {};
-
- u8 response_buffer[4096];
- int nrecv = udp_socket->read(response_buffer, sizeof(response_buffer));
- if (nrecv == 0)
- return {};
-
- did_get_response = true;
-
- auto o_response = DNSResponse::from_raw_response(response_buffer, nrecv);
- if (!o_response.has_value())
- return {};
-
- auto& response = o_response.value();
-
- if (response.id() != request.id()) {
- dbgln("LookupServer: ID mismatch ({} vs {}) :(", response.id(), request.id());
- return {};
- }
-
- if (response.code() == DNSResponse::Code::REFUSED) {
- if (should_randomize_case == ShouldRandomizeCase::Yes) {
- // Retry with 0x20 case randomization turned off.
- return lookup(hostname, nameserver, did_get_response, record_type, ShouldRandomizeCase::No);
- }
- return {};
- }
-
- if (response.question_count() != request.question_count()) {
- dbgln("LookupServer: Question count ({} vs {}) :(", response.question_count(), request.question_count());
- return {};
- }
-
- for (size_t i = 0; i < request.question_count(); ++i) {
- auto& request_question = request.questions()[i];
- auto& response_question = response.questions()[i];
- if (request_question != response_question) {
- dbgln("Request and response questions do not match");
- dbgln(" Request: name=_{}_, type={}, class={}", request_question.name(), response_question.record_type(), response_question.class_code());
- dbgln(" Response: name=_{}_, type={}, class={}", response_question.name(), response_question.record_type(), response_question.class_code());
- return {};
- }
- }
-
- if (response.answer_count() < 1) {
- dbgln("LookupServer: Not enough answers ({}) :(", response.answer_count());
- return {};
- }
-
- Vector<String, 8> responses;
- Vector<DNSAnswer, 8> cacheable_answers;
- for (auto& answer : response.answers()) {
- if (answer.type() != T_A)
- continue;
- responses.append(answer.record_data());
- if (!answer.has_expired())
- cacheable_answers.append(answer);
- }
-
- if (!cacheable_answers.is_empty()) {
- if (m_lookup_cache.size() >= 256)
- m_lookup_cache.remove(m_lookup_cache.begin());
- m_lookup_cache.set(hostname, { request.questions()[0], move(cacheable_answers) });
- }
- return responses;
-}
diff --git a/Services/LookupServer/LookupServer.h b/Services/LookupServer/LookupServer.h
deleted file mode 100644
index 7b5a08140a..0000000000
--- a/Services/LookupServer/LookupServer.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include "DNSRequest.h"
-#include "DNSResponse.h"
-#include <AK/HashMap.h>
-#include <LibCore/Object.h>
-
-class DNSAnswer;
-
-class LookupServer final : public Core::Object {
- C_OBJECT(LookupServer)
-
-public:
- LookupServer();
-
-private:
- void load_etc_hosts();
- void service_client(RefPtr<Core::LocalSocket>);
- Vector<String> lookup(const String& hostname, const String& nameserver, bool& did_get_response, unsigned short record_type, ShouldRandomizeCase = ShouldRandomizeCase::Yes);
-
- struct CachedLookup {
- DNSQuestion question;
- Vector<DNSAnswer> answers;
- };
-
- RefPtr<Core::LocalServer> m_local_server;
- Vector<String> m_nameservers;
- HashMap<String, String> m_etc_hosts;
- HashMap<String, CachedLookup> m_lookup_cache;
-};
diff --git a/Services/LookupServer/main.cpp b/Services/LookupServer/main.cpp
deleted file mode 100644
index 23d5933bac..0000000000
--- a/Services/LookupServer/main.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "LookupServer.h"
-#include <LibCore/EventLoop.h>
-#include <LibCore/LocalServer.h>
-#include <stdio.h>
-
-int main([[maybe_unused]] int argc, [[maybe_unused]] char** argv)
-{
- if (pledge("stdio accept unix inet cpath rpath fattr", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- Core::EventLoop event_loop;
- LookupServer server;
-
- if (pledge("stdio accept inet", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- unveil(nullptr, nullptr);
-
- return event_loop.exec();
-}
diff --git a/Services/NotificationServer/CMakeLists.txt b/Services/NotificationServer/CMakeLists.txt
deleted file mode 100644
index a28d9f16a5..0000000000
--- a/Services/NotificationServer/CMakeLists.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-compile_ipc(NotificationServer.ipc NotificationServerEndpoint.h)
-compile_ipc(NotificationClient.ipc NotificationClientEndpoint.h)
-
-set(SOURCES
- ClientConnection.cpp
- main.cpp
- NotificationWindow.cpp
- NotificationServerEndpoint.h
- NotificationClientEndpoint.h
-)
-
-serenity_bin(NotificationServer)
-target_link_libraries(NotificationServer LibGUI LibIPC)
diff --git a/Services/NotificationServer/ClientConnection.cpp b/Services/NotificationServer/ClientConnection.cpp
deleted file mode 100644
index 9c6cc8051a..0000000000
--- a/Services/NotificationServer/ClientConnection.cpp
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "ClientConnection.h"
-#include "NotificationWindow.h"
-#include <AK/HashMap.h>
-#include <NotificationServer/NotificationClientEndpoint.h>
-
-namespace NotificationServer {
-
-static HashMap<int, RefPtr<ClientConnection>> s_connections;
-
-ClientConnection::ClientConnection(NonnullRefPtr<Core::LocalSocket> client_socket, int client_id)
- : IPC::ClientConnection<NotificationClientEndpoint, NotificationServerEndpoint>(*this, move(client_socket), client_id)
-{
- s_connections.set(client_id, *this);
-}
-
-ClientConnection::~ClientConnection()
-{
-}
-
-void ClientConnection::die()
-{
- s_connections.remove(client_id());
-}
-
-OwnPtr<Messages::NotificationServer::GreetResponse> ClientConnection::handle(const Messages::NotificationServer::Greet&)
-{
- return make<Messages::NotificationServer::GreetResponse>(client_id());
-}
-
-OwnPtr<Messages::NotificationServer::ShowNotificationResponse> ClientConnection::handle(const Messages::NotificationServer::ShowNotification& message)
-{
- auto window = NotificationWindow::construct(message.text(), message.title(), message.icon());
- window->show();
- return make<Messages::NotificationServer::ShowNotificationResponse>();
-}
-
-}
diff --git a/Services/NotificationServer/ClientConnection.h b/Services/NotificationServer/ClientConnection.h
deleted file mode 100644
index af4e36d0aa..0000000000
--- a/Services/NotificationServer/ClientConnection.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <LibIPC/ClientConnection.h>
-#include <NotificationServer/NotificationClientEndpoint.h>
-#include <NotificationServer/NotificationServerEndpoint.h>
-
-namespace NotificationServer {
-
-class ClientConnection final : public IPC::ClientConnection<NotificationClientEndpoint, NotificationServerEndpoint>
- , public NotificationServerEndpoint {
- C_OBJECT(ClientConnection)
-public:
- ~ClientConnection() override;
-
- virtual void die() override;
-
-private:
- explicit ClientConnection(NonnullRefPtr<Core::LocalSocket>, int client_id);
-
- virtual OwnPtr<Messages::NotificationServer::GreetResponse> handle(const Messages::NotificationServer::Greet&) override;
- virtual OwnPtr<Messages::NotificationServer::ShowNotificationResponse> handle(const Messages::NotificationServer::ShowNotification&) override;
-};
-
-}
diff --git a/Services/NotificationServer/NotificationClient.ipc b/Services/NotificationServer/NotificationClient.ipc
deleted file mode 100644
index fc85168f76..0000000000
--- a/Services/NotificationServer/NotificationClient.ipc
+++ /dev/null
@@ -1,4 +0,0 @@
-endpoint NotificationClient = 92
-{
- Dummy() =|
-}
diff --git a/Services/NotificationServer/NotificationServer.ipc b/Services/NotificationServer/NotificationServer.ipc
deleted file mode 100644
index e342ebf2d3..0000000000
--- a/Services/NotificationServer/NotificationServer.ipc
+++ /dev/null
@@ -1,7 +0,0 @@
-endpoint NotificationServer = 95
-{
- // Basic protocol
- Greet() => (i32 client_id)
-
- ShowNotification([UTF8] String text, [UTF8] String title, Gfx::ShareableBitmap icon) => ()
-}
diff --git a/Services/NotificationServer/NotificationWindow.cpp b/Services/NotificationServer/NotificationWindow.cpp
deleted file mode 100644
index e5739b1c3b..0000000000
--- a/Services/NotificationServer/NotificationWindow.cpp
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "NotificationWindow.h"
-#include <AK/Vector.h>
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/Button.h>
-#include <LibGUI/Desktop.h>
-#include <LibGUI/ImageWidget.h>
-#include <LibGUI/Label.h>
-#include <LibGUI/Widget.h>
-#include <LibGfx/Bitmap.h>
-#include <LibGfx/Font.h>
-#include <LibGfx/FontDatabase.h>
-#include <LibGfx/ShareableBitmap.h>
-
-namespace NotificationServer {
-
-static Vector<RefPtr<NotificationWindow>> s_windows;
-
-void update_notification_window_locations()
-{
- Gfx::IntRect last_window_rect;
- for (auto& window : s_windows) {
- Gfx::IntPoint new_window_location;
- if (last_window_rect.is_null())
- new_window_location = GUI::Desktop::the().rect().top_right().translated(-window->rect().width() - 24, 26);
- else
- new_window_location = last_window_rect.bottom_left().translated(0, 10);
- if (window->rect().location() != new_window_location) {
- window->move_to(new_window_location);
- window->set_original_rect(window->rect());
- }
- last_window_rect = window->rect();
- }
-}
-
-NotificationWindow::NotificationWindow(const String& text, const String& title, const Gfx::ShareableBitmap& icon)
-{
- s_windows.append(this);
-
- set_window_type(GUI::WindowType::Notification);
- set_resizable(false);
- set_minimizable(false);
-
- Gfx::IntRect lowest_notification_rect_on_screen;
- for (auto& window : s_windows) {
- if (window->m_original_rect.y() > lowest_notification_rect_on_screen.y())
- lowest_notification_rect_on_screen = window->m_original_rect;
- }
-
- Gfx::IntRect rect;
- rect.set_width(220);
- rect.set_height(40);
- rect.set_location(GUI::Desktop::the().rect().top_right().translated(-rect.width() - 24, 26));
-
- if (!lowest_notification_rect_on_screen.is_null())
- rect.set_location(lowest_notification_rect_on_screen.bottom_left().translated(0, 10));
-
- set_rect(rect);
-
- m_original_rect = rect;
-
- auto& widget = set_main_widget<GUI::Widget>();
- widget.set_fill_with_background_color(true);
-
- widget.set_layout<GUI::HorizontalBoxLayout>();
- widget.layout()->set_margins({ 8, 8, 8, 8 });
- widget.layout()->set_spacing(6);
-
- if (icon.is_valid()) {
- auto& image = widget.add<GUI::ImageWidget>();
- image.set_bitmap(icon.bitmap());
- }
-
- auto& left_container = widget.add<GUI::Widget>();
- left_container.set_layout<GUI::VerticalBoxLayout>();
-
- auto& title_label = left_container.add<GUI::Label>(title);
- title_label.set_font(Gfx::FontDatabase::default_bold_font());
- title_label.set_text_alignment(Gfx::TextAlignment::CenterLeft);
- auto& text_label = left_container.add<GUI::Label>(text);
- text_label.set_text_alignment(Gfx::TextAlignment::CenterLeft);
-
- auto& right_container = widget.add<GUI::Widget>();
- right_container.set_fixed_width(36);
- right_container.set_layout<GUI::HorizontalBoxLayout>();
-
- on_close_request = [this] {
- s_windows.remove_first_matching([this](auto& entry) { return entry == this; });
- update_notification_window_locations();
- return CloseRequestDecision::Close;
- };
-}
-
-NotificationWindow::~NotificationWindow()
-{
-}
-
-}
diff --git a/Services/NotificationServer/NotificationWindow.h b/Services/NotificationServer/NotificationWindow.h
deleted file mode 100644
index 607365fe6e..0000000000
--- a/Services/NotificationServer/NotificationWindow.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <LibGUI/Window.h>
-
-namespace NotificationServer {
-
-void update_notification_window_locations();
-
-class NotificationWindow final : public GUI::Window {
- C_OBJECT(NotificationWindow);
-
-public:
- virtual ~NotificationWindow() override;
- void set_original_rect(Gfx::IntRect original_rect) { m_original_rect = original_rect; };
-
-private:
- NotificationWindow(const String& text, const String& title, const Gfx::ShareableBitmap&);
-
- Gfx::IntRect m_original_rect;
-};
-
-}
diff --git a/Services/NotificationServer/main.cpp b/Services/NotificationServer/main.cpp
deleted file mode 100644
index 91cd06e0d7..0000000000
--- a/Services/NotificationServer/main.cpp
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "ClientConnection.h"
-#include "NotificationWindow.h"
-#include <LibCore/LocalServer.h>
-#include <LibGUI/Application.h>
-#include <LibGUI/Desktop.h>
-#include <LibGUI/WindowServerConnection.h>
-#include <stdio.h>
-#include <unistd.h>
-
-int main(int argc, char** argv)
-{
- if (pledge("stdio shared_buffer accept rpath wpath cpath unix fattr", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- auto app = GUI::Application::construct(argc, argv);
- auto server = Core::LocalServer::construct();
-
- bool ok = server->take_over_from_system_server();
- ASSERT(ok);
- server->on_ready_to_accept = [&] {
- auto client_socket = server->accept();
- if (!client_socket) {
- dbgln("NotificationServer: accept failed.");
- return;
- }
- static int s_next_client_id = 0;
- int client_id = ++s_next_client_id;
- IPC::new_client_connection<NotificationServer::ClientConnection>(client_socket.release_nonnull(), client_id);
- };
-
- if (unveil("/res", "r") < 0) {
- perror("unveil");
- return 1;
- }
-
- unveil(nullptr, nullptr);
-
- if (pledge("stdio shared_buffer accept rpath", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- GUI::Desktop::the().on_rect_change = [](auto&) { NotificationServer::update_notification_window_locations(); };
-
- return app->exec();
-}
diff --git a/Services/ProtocolServer/CMakeLists.txt b/Services/ProtocolServer/CMakeLists.txt
deleted file mode 100644
index 4fb0757759..0000000000
--- a/Services/ProtocolServer/CMakeLists.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-compile_ipc(ProtocolServer.ipc ProtocolServerEndpoint.h)
-compile_ipc(ProtocolClient.ipc ProtocolClientEndpoint.h)
-
-set(SOURCES
- ClientConnection.cpp
- Download.cpp
- GeminiDownload.cpp
- GeminiProtocol.cpp
- HttpDownload.cpp
- HttpProtocol.cpp
- HttpsDownload.cpp
- HttpsProtocol.cpp
- main.cpp
- Protocol.cpp
- ProtocolServerEndpoint.h
- ProtocolClientEndpoint.h
-)
-
-serenity_bin(ProtocolServer)
-target_link_libraries(ProtocolServer LibCore LibIPC LibGemini LibHTTP)
diff --git a/Services/ProtocolServer/ClientConnection.cpp b/Services/ProtocolServer/ClientConnection.cpp
deleted file mode 100644
index e966d2f2f4..0000000000
--- a/Services/ProtocolServer/ClientConnection.cpp
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <AK/Badge.h>
-#include <AK/SharedBuffer.h>
-#include <ProtocolServer/ClientConnection.h>
-#include <ProtocolServer/Download.h>
-#include <ProtocolServer/Protocol.h>
-#include <ProtocolServer/ProtocolClientEndpoint.h>
-
-namespace ProtocolServer {
-
-static HashMap<int, RefPtr<ClientConnection>> s_connections;
-
-ClientConnection::ClientConnection(NonnullRefPtr<Core::LocalSocket> socket, int client_id)
- : IPC::ClientConnection<ProtocolClientEndpoint, ProtocolServerEndpoint>(*this, move(socket), client_id)
-{
- s_connections.set(client_id, *this);
-}
-
-ClientConnection::~ClientConnection()
-{
-}
-
-void ClientConnection::die()
-{
- s_connections.remove(client_id());
- if (s_connections.is_empty())
- Core::EventLoop::current().quit(0);
-}
-
-OwnPtr<Messages::ProtocolServer::IsSupportedProtocolResponse> ClientConnection::handle(const Messages::ProtocolServer::IsSupportedProtocol& message)
-{
- bool supported = Protocol::find_by_name(message.protocol().to_lowercase());
- return make<Messages::ProtocolServer::IsSupportedProtocolResponse>(supported);
-}
-
-OwnPtr<Messages::ProtocolServer::StartDownloadResponse> ClientConnection::handle(const Messages::ProtocolServer::StartDownload& message)
-{
- const auto& url = message.url();
- if (!url.is_valid()) {
- dbgln("StartDownload: Invalid URL requested: '{}'", url);
- return make<Messages::ProtocolServer::StartDownloadResponse>(-1, Optional<IPC::File> {});
- }
- auto* protocol = Protocol::find_by_name(url.protocol());
- if (!protocol) {
- dbgln("StartDownload: No protocol handler for URL: '{}'", url);
- return make<Messages::ProtocolServer::StartDownloadResponse>(-1, Optional<IPC::File> {});
- }
- auto download = protocol->start_download(*this, message.method(), url, message.request_headers().entries(), message.request_body());
- if (!download) {
- dbgln("StartDownload: Protocol handler failed to start download: '{}'", url);
- return make<Messages::ProtocolServer::StartDownloadResponse>(-1, Optional<IPC::File> {});
- }
- auto id = download->id();
- auto fd = download->download_fd();
- m_downloads.set(id, move(download));
- auto response = make<Messages::ProtocolServer::StartDownloadResponse>(id, fd);
- response->on_destruction = [fd] { close(fd); };
- return response;
-}
-
-OwnPtr<Messages::ProtocolServer::StopDownloadResponse> ClientConnection::handle(const Messages::ProtocolServer::StopDownload& message)
-{
- auto* download = const_cast<Download*>(m_downloads.get(message.download_id()).value_or(nullptr));
- bool success = false;
- if (download) {
- download->stop();
- m_downloads.remove(message.download_id());
- success = true;
- }
- return make<Messages::ProtocolServer::StopDownloadResponse>(success);
-}
-
-void ClientConnection::did_receive_headers(Badge<Download>, Download& download)
-{
- IPC::Dictionary response_headers;
- for (auto& it : download.response_headers())
- response_headers.add(it.key, it.value);
-
- post_message(Messages::ProtocolClient::HeadersBecameAvailable(download.id(), move(response_headers), download.status_code()));
-}
-
-void ClientConnection::did_finish_download(Badge<Download>, Download& download, bool success)
-{
- ASSERT(download.total_size().has_value());
-
- post_message(Messages::ProtocolClient::DownloadFinished(download.id(), success, download.total_size().value()));
-
- m_downloads.remove(download.id());
-}
-
-void ClientConnection::did_progress_download(Badge<Download>, Download& download)
-{
- post_message(Messages::ProtocolClient::DownloadProgress(download.id(), download.total_size(), download.downloaded_size()));
-}
-
-void ClientConnection::did_request_certificates(Badge<Download>, Download& download)
-{
- post_message(Messages::ProtocolClient::CertificateRequested(download.id()));
-}
-
-OwnPtr<Messages::ProtocolServer::GreetResponse> ClientConnection::handle(const Messages::ProtocolServer::Greet&)
-{
- return make<Messages::ProtocolServer::GreetResponse>(client_id());
-}
-
-OwnPtr<Messages::ProtocolServer::SetCertificateResponse> ClientConnection::handle(const Messages::ProtocolServer::SetCertificate& message)
-{
- auto* download = const_cast<Download*>(m_downloads.get(message.download_id()).value_or(nullptr));
- bool success = false;
- if (download) {
- download->set_certificate(message.certificate(), message.key());
- success = true;
- }
- return make<Messages::ProtocolServer::SetCertificateResponse>(success);
-}
-
-}
diff --git a/Services/ProtocolServer/ClientConnection.h b/Services/ProtocolServer/ClientConnection.h
deleted file mode 100644
index 778f3eff81..0000000000
--- a/Services/ProtocolServer/ClientConnection.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <AK/HashMap.h>
-#include <LibIPC/ClientConnection.h>
-#include <ProtocolServer/Forward.h>
-#include <ProtocolServer/ProtocolClientEndpoint.h>
-#include <ProtocolServer/ProtocolServerEndpoint.h>
-
-namespace ProtocolServer {
-
-class ClientConnection final
- : public IPC::ClientConnection<ProtocolClientEndpoint, ProtocolServerEndpoint>
- , public ProtocolServerEndpoint {
- C_OBJECT(ClientConnection);
-
-public:
- explicit ClientConnection(NonnullRefPtr<Core::LocalSocket>, int client_id);
- ~ClientConnection() override;
-
- virtual void die() override;
-
- void did_receive_headers(Badge<Download>, Download&);
- void did_finish_download(Badge<Download>, Download&, bool success);
- void did_progress_download(Badge<Download>, Download&);
- void did_request_certificates(Badge<Download>, Download&);
-
-private:
- virtual OwnPtr<Messages::ProtocolServer::GreetResponse> handle(const Messages::ProtocolServer::Greet&) override;
- virtual OwnPtr<Messages::ProtocolServer::IsSupportedProtocolResponse> handle(const Messages::ProtocolServer::IsSupportedProtocol&) override;
- virtual OwnPtr<Messages::ProtocolServer::StartDownloadResponse> handle(const Messages::ProtocolServer::StartDownload&) override;
- virtual OwnPtr<Messages::ProtocolServer::StopDownloadResponse> handle(const Messages::ProtocolServer::StopDownload&) override;
- virtual OwnPtr<Messages::ProtocolServer::SetCertificateResponse> handle(const Messages::ProtocolServer::SetCertificate&) override;
-
- HashMap<i32, OwnPtr<Download>> m_downloads;
-};
-
-}
diff --git a/Services/ProtocolServer/Download.cpp b/Services/ProtocolServer/Download.cpp
deleted file mode 100644
index 11a7d28933..0000000000
--- a/Services/ProtocolServer/Download.cpp
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <AK/Badge.h>
-#include <ProtocolServer/ClientConnection.h>
-#include <ProtocolServer/Download.h>
-
-namespace ProtocolServer {
-
-// FIXME: What about rollover?
-static i32 s_next_id = 1;
-
-Download::Download(ClientConnection& client, NonnullOwnPtr<OutputFileStream>&& output_stream)
- : m_client(client)
- , m_id(s_next_id++)
- , m_output_stream(move(output_stream))
-{
-}
-
-Download::~Download()
-{
-}
-
-void Download::stop()
-{
- m_client.did_finish_download({}, *this, false);
-}
-
-void Download::set_response_headers(const HashMap<String, String, CaseInsensitiveStringTraits>& response_headers)
-{
- m_response_headers = response_headers;
- m_client.did_receive_headers({}, *this);
-}
-
-void Download::set_certificate(String, String)
-{
-}
-
-void Download::did_finish(bool success)
-{
- m_client.did_finish_download({}, *this, success);
-}
-
-void Download::did_progress(Optional<u32> total_size, u32 downloaded_size)
-{
- m_total_size = total_size;
- m_downloaded_size = downloaded_size;
- m_client.did_progress_download({}, *this);
-}
-
-void Download::did_request_certificates()
-{
- m_client.did_request_certificates({}, *this);
-}
-
-}
diff --git a/Services/ProtocolServer/Download.h b/Services/ProtocolServer/Download.h
deleted file mode 100644
index 35c60269f4..0000000000
--- a/Services/ProtocolServer/Download.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <AK/FileStream.h>
-#include <AK/HashMap.h>
-#include <AK/NonnullOwnPtr.h>
-#include <AK/Optional.h>
-#include <AK/RefCounted.h>
-#include <AK/URL.h>
-#include <ProtocolServer/Forward.h>
-
-namespace ProtocolServer {
-
-class Download {
-public:
- virtual ~Download();
-
- i32 id() const { return m_id; }
- URL url() const { return m_url; }
-
- Optional<u32> status_code() const { return m_status_code; }
- Optional<u32> total_size() const { return m_total_size; }
- size_t downloaded_size() const { return m_downloaded_size; }
- const HashMap<String, String, CaseInsensitiveStringTraits>& response_headers() const { return m_response_headers; }
-
- void stop();
- virtual void set_certificate(String, String);
-
- // FIXME: Want Badge<Protocol>, but can't make one from HttpProtocol, etc.
- void set_download_fd(int fd) { m_download_fd = fd; }
- int download_fd() const { return m_download_fd; }
-
-protected:
- explicit Download(ClientConnection&, NonnullOwnPtr<OutputFileStream>&&);
-
- void did_finish(bool success);
- void did_progress(Optional<u32> total_size, u32 downloaded_size);
- void set_status_code(u32 status_code) { m_status_code = status_code; }
- void did_request_certificates();
- void set_response_headers(const HashMap<String, String, CaseInsensitiveStringTraits>&);
- void set_downloaded_size(size_t size) { m_downloaded_size = size; }
- const OutputFileStream& output_stream() const { return *m_output_stream; }
-
-private:
- ClientConnection& m_client;
- i32 m_id { 0 };
- int m_download_fd { -1 }; // Passed to client.
- URL m_url;
- Optional<u32> m_status_code;
- Optional<u32> m_total_size {};
- size_t m_downloaded_size { 0 };
- NonnullOwnPtr<OutputFileStream> m_output_stream;
- HashMap<String, String, CaseInsensitiveStringTraits> m_response_headers;
-};
-
-}
diff --git a/Services/ProtocolServer/Forward.h b/Services/ProtocolServer/Forward.h
deleted file mode 100644
index 06eec6c7ab..0000000000
--- a/Services/ProtocolServer/Forward.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-namespace ProtocolServer {
-
-class ClientConnection;
-class Download;
-class GeminiProtocol;
-class HttpDownload;
-class HttpProtocol;
-class HttpsDownload;
-class HttpsProtocol;
-class Protocol;
-
-}
diff --git a/Services/ProtocolServer/GeminiDownload.cpp b/Services/ProtocolServer/GeminiDownload.cpp
deleted file mode 100644
index 0bba75519d..0000000000
--- a/Services/ProtocolServer/GeminiDownload.cpp
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (c) 2020, The SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <LibGemini/GeminiJob.h>
-#include <LibGemini/GeminiResponse.h>
-#include <ProtocolServer/GeminiDownload.h>
-
-namespace ProtocolServer {
-
-GeminiDownload::GeminiDownload(ClientConnection& client, NonnullRefPtr<Gemini::GeminiJob> job, NonnullOwnPtr<OutputFileStream>&& output_stream)
- : Download(client, move(output_stream))
- , m_job(job)
-{
- m_job->on_finish = [this](bool success) {
- if (auto* response = m_job->response()) {
- set_downloaded_size(this->output_stream().size());
- if (!response->meta().is_empty()) {
- HashMap<String, String, CaseInsensitiveStringTraits> headers;
- headers.set("meta", response->meta());
- // Note: We're setting content-type to meta only on status==SUCCESS
- // we should perhaps have a better mechanism for this, since we
- // are already shoehorning the concept of "headers" here
- if (response->status() >= 20 && response->status() < 30) {
- headers.set("content-type", response->meta());
- }
- set_response_headers(headers);
- }
- }
-
- // signal 100% download progress so any listeners can react
- // appropriately
- did_progress(downloaded_size(), downloaded_size());
-
- did_finish(success);
- };
- m_job->on_progress = [this](Optional<u32> total, u32 current) {
- did_progress(total, current);
- };
- m_job->on_certificate_requested = [this](auto&) {
- did_request_certificates();
- };
-}
-
-void GeminiDownload::set_certificate(String certificate, String key)
-{
- m_job->set_certificate(move(certificate), move(key));
-}
-
-GeminiDownload::~GeminiDownload()
-{
- m_job->on_finish = nullptr;
- m_job->on_progress = nullptr;
- m_job->shutdown();
-}
-
-NonnullOwnPtr<GeminiDownload> GeminiDownload::create_with_job(Badge<GeminiProtocol>, ClientConnection& client, NonnullRefPtr<Gemini::GeminiJob> job, NonnullOwnPtr<OutputFileStream>&& output_stream)
-{
- return adopt_own(*new GeminiDownload(client, move(job), move(output_stream)));
-}
-
-}
diff --git a/Services/ProtocolServer/GeminiDownload.h b/Services/ProtocolServer/GeminiDownload.h
deleted file mode 100644
index fcd81c121f..0000000000
--- a/Services/ProtocolServer/GeminiDownload.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2020, The SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <AK/Badge.h>
-#include <LibCore/Forward.h>
-#include <LibGemini/Forward.h>
-#include <ProtocolServer/Download.h>
-
-namespace ProtocolServer {
-
-class GeminiDownload final : public Download {
-public:
- virtual ~GeminiDownload() override;
- static NonnullOwnPtr<GeminiDownload> create_with_job(Badge<GeminiProtocol>, ClientConnection&, NonnullRefPtr<Gemini::GeminiJob>, NonnullOwnPtr<OutputFileStream>&&);
-
-private:
- explicit GeminiDownload(ClientConnection&, NonnullRefPtr<Gemini::GeminiJob>, NonnullOwnPtr<OutputFileStream>&&);
-
- virtual void set_certificate(String certificate, String key) override;
-
- NonnullRefPtr<Gemini::GeminiJob> m_job;
-};
-
-}
diff --git a/Services/ProtocolServer/GeminiProtocol.cpp b/Services/ProtocolServer/GeminiProtocol.cpp
deleted file mode 100644
index c09b53ca42..0000000000
--- a/Services/ProtocolServer/GeminiProtocol.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (c) 2020, The SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <LibGemini/GeminiJob.h>
-#include <LibGemini/GeminiRequest.h>
-#include <ProtocolServer/GeminiDownload.h>
-#include <ProtocolServer/GeminiProtocol.h>
-#include <fcntl.h>
-
-namespace ProtocolServer {
-
-GeminiProtocol::GeminiProtocol()
- : Protocol("gemini")
-{
-}
-
-GeminiProtocol::~GeminiProtocol()
-{
-}
-
-OwnPtr<Download> GeminiProtocol::start_download(ClientConnection& client, const String&, const URL& url, const HashMap<String, String>&, ReadonlyBytes)
-{
- Gemini::GeminiRequest request;
- request.set_url(url);
-
- auto pipe_result = get_pipe_for_download();
- if (pipe_result.is_error())
- return {};
-
- auto output_stream = make<OutputFileStream>(pipe_result.value().write_fd);
- output_stream->make_unbuffered();
- auto job = Gemini::GeminiJob::construct(request, *output_stream);
- auto download = GeminiDownload::create_with_job({}, client, (Gemini::GeminiJob&)*job, move(output_stream));
- download->set_download_fd(pipe_result.value().read_fd);
- job->start();
- return download;
-}
-
-}
diff --git a/Services/ProtocolServer/GeminiProtocol.h b/Services/ProtocolServer/GeminiProtocol.h
deleted file mode 100644
index 23a4d7c717..0000000000
--- a/Services/ProtocolServer/GeminiProtocol.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2020, The SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <ProtocolServer/Protocol.h>
-
-namespace ProtocolServer {
-
-class GeminiProtocol final : public Protocol {
-public:
- GeminiProtocol();
- virtual ~GeminiProtocol() override;
-
- virtual OwnPtr<Download> start_download(ClientConnection&, const String& method, const URL&, const HashMap<String, String>&, ReadonlyBytes body) override;
-};
-
-}
diff --git a/Services/ProtocolServer/HttpDownload.cpp b/Services/ProtocolServer/HttpDownload.cpp
deleted file mode 100644
index 8ba945d335..0000000000
--- a/Services/ProtocolServer/HttpDownload.cpp
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <LibHTTP/HttpJob.h>
-#include <LibHTTP/HttpResponse.h>
-#include <ProtocolServer/HttpDownload.h>
-
-namespace ProtocolServer {
-
-HttpDownload::HttpDownload(ClientConnection& client, NonnullRefPtr<HTTP::HttpJob> job, NonnullOwnPtr<OutputFileStream>&& output_stream)
- : Download(client, move(output_stream))
- , m_job(job)
-{
- m_job->on_headers_received = [this](auto& headers, auto response_code) {
- if (response_code.has_value())
- set_status_code(response_code.value());
- set_response_headers(headers);
- };
-
- m_job->on_finish = [this](bool success) {
- if (auto* response = m_job->response()) {
- set_status_code(response->code());
- set_response_headers(response->headers());
- set_downloaded_size(this->output_stream().size());
- }
-
- // if we didn't know the total size, pretend that the download finished successfully
- // and set the total size to the downloaded size
- if (!total_size().has_value())
- did_progress(downloaded_size(), downloaded_size());
-
- did_finish(success);
- };
- m_job->on_progress = [this](Optional<u32> total, u32 current) {
- did_progress(total, current);
- };
-}
-
-HttpDownload::~HttpDownload()
-{
- m_job->on_finish = nullptr;
- m_job->on_progress = nullptr;
- m_job->shutdown();
-}
-
-NonnullOwnPtr<HttpDownload> HttpDownload::create_with_job(Badge<HttpProtocol>, ClientConnection& client, NonnullRefPtr<HTTP::HttpJob> job, NonnullOwnPtr<OutputFileStream>&& output_stream)
-{
- return adopt_own(*new HttpDownload(client, move(job), move(output_stream)));
-}
-
-}
diff --git a/Services/ProtocolServer/HttpDownload.h b/Services/ProtocolServer/HttpDownload.h
deleted file mode 100644
index 50095bd0e5..0000000000
--- a/Services/ProtocolServer/HttpDownload.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <AK/Badge.h>
-#include <LibCore/Forward.h>
-#include <LibHTTP/Forward.h>
-#include <ProtocolServer/Download.h>
-
-namespace ProtocolServer {
-
-class HttpDownload final : public Download {
-public:
- virtual ~HttpDownload() override;
- static NonnullOwnPtr<HttpDownload> create_with_job(Badge<HttpProtocol>, ClientConnection&, NonnullRefPtr<HTTP::HttpJob>, NonnullOwnPtr<OutputFileStream>&&);
-
-private:
- explicit HttpDownload(ClientConnection&, NonnullRefPtr<HTTP::HttpJob>, NonnullOwnPtr<OutputFileStream>&&);
-
- NonnullRefPtr<HTTP::HttpJob> m_job;
-};
-
-}
diff --git a/Services/ProtocolServer/HttpProtocol.cpp b/Services/ProtocolServer/HttpProtocol.cpp
deleted file mode 100644
index acc10a88ec..0000000000
--- a/Services/ProtocolServer/HttpProtocol.cpp
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <LibHTTP/HttpJob.h>
-#include <LibHTTP/HttpRequest.h>
-#include <ProtocolServer/HttpDownload.h>
-#include <ProtocolServer/HttpProtocol.h>
-
-namespace ProtocolServer {
-
-HttpProtocol::HttpProtocol()
- : Protocol("http")
-{
-}
-
-HttpProtocol::~HttpProtocol()
-{
-}
-
-OwnPtr<Download> HttpProtocol::start_download(ClientConnection& client, const String& method, const URL& url, const HashMap<String, String>& headers, ReadonlyBytes body)
-{
- HTTP::HttpRequest request;
- if (method.equals_ignoring_case("post"))
- request.set_method(HTTP::HttpRequest::Method::POST);
- else
- request.set_method(HTTP::HttpRequest::Method::GET);
- request.set_url(url);
- request.set_headers(headers);
- request.set_body(body);
-
- auto pipe_result = get_pipe_for_download();
- if (pipe_result.is_error())
- return {};
-
- auto output_stream = make<OutputFileStream>(pipe_result.value().write_fd);
- output_stream->make_unbuffered();
- auto job = HTTP::HttpJob::construct(request, *output_stream);
- auto download = HttpDownload::create_with_job({}, client, (HTTP::HttpJob&)*job, move(output_stream));
- download->set_download_fd(pipe_result.value().read_fd);
- job->start();
- return download;
-}
-
-}
diff --git a/Services/ProtocolServer/HttpProtocol.h b/Services/ProtocolServer/HttpProtocol.h
deleted file mode 100644
index 8c4a564f37..0000000000
--- a/Services/ProtocolServer/HttpProtocol.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <ProtocolServer/Protocol.h>
-
-namespace ProtocolServer {
-
-class HttpProtocol final : public Protocol {
-public:
- HttpProtocol();
- virtual ~HttpProtocol() override;
-
- virtual OwnPtr<Download> start_download(ClientConnection&, const String& method, const URL&, const HashMap<String, String>& headers, ReadonlyBytes body) override;
-};
-
-}
diff --git a/Services/ProtocolServer/HttpsDownload.cpp b/Services/ProtocolServer/HttpsDownload.cpp
deleted file mode 100644
index 991dd730d8..0000000000
--- a/Services/ProtocolServer/HttpsDownload.cpp
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (c) 2020, The SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <LibHTTP/HttpResponse.h>
-#include <LibHTTP/HttpsJob.h>
-#include <ProtocolServer/HttpsDownload.h>
-
-namespace ProtocolServer {
-
-HttpsDownload::HttpsDownload(ClientConnection& client, NonnullRefPtr<HTTP::HttpsJob> job, NonnullOwnPtr<OutputFileStream>&& output_stream)
- : Download(client, move(output_stream))
- , m_job(job)
-{
- m_job->on_headers_received = [this](auto& headers, auto response_code) {
- if (response_code.has_value())
- set_status_code(response_code.value());
- set_response_headers(headers);
- };
-
- m_job->on_finish = [this](bool success) {
- if (auto* response = m_job->response()) {
- set_status_code(response->code());
- set_response_headers(response->headers());
- set_downloaded_size(this->output_stream().size());
- }
-
- // if we didn't know the total size, pretend that the download finished successfully
- // and set the total size to the downloaded size
- if (!total_size().has_value())
- did_progress(downloaded_size(), downloaded_size());
-
- did_finish(success);
- };
- m_job->on_progress = [this](Optional<u32> total, u32 current) {
- did_progress(total, current);
- };
- m_job->on_certificate_requested = [this](auto&) {
- did_request_certificates();
- };
-}
-
-void HttpsDownload::set_certificate(String certificate, String key)
-{
- m_job->set_certificate(move(certificate), move(key));
-}
-
-HttpsDownload::~HttpsDownload()
-{
- m_job->on_finish = nullptr;
- m_job->on_progress = nullptr;
- m_job->shutdown();
-}
-
-NonnullOwnPtr<HttpsDownload> HttpsDownload::create_with_job(Badge<HttpsProtocol>, ClientConnection& client, NonnullRefPtr<HTTP::HttpsJob> job, NonnullOwnPtr<OutputFileStream>&& output_stream)
-{
- return adopt_own(*new HttpsDownload(client, move(job), move(output_stream)));
-}
-
-}
diff --git a/Services/ProtocolServer/HttpsDownload.h b/Services/ProtocolServer/HttpsDownload.h
deleted file mode 100644
index 254172b3f7..0000000000
--- a/Services/ProtocolServer/HttpsDownload.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2020, The SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <AK/Badge.h>
-#include <LibCore/Forward.h>
-#include <LibHTTP/HttpsJob.h>
-#include <ProtocolServer/Download.h>
-
-namespace ProtocolServer {
-
-class HttpsDownload final : public Download {
-public:
- virtual ~HttpsDownload() override;
- static NonnullOwnPtr<HttpsDownload> create_with_job(Badge<HttpsProtocol>, ClientConnection&, NonnullRefPtr<HTTP::HttpsJob>, NonnullOwnPtr<OutputFileStream>&&);
-
-private:
- explicit HttpsDownload(ClientConnection&, NonnullRefPtr<HTTP::HttpsJob>, NonnullOwnPtr<OutputFileStream>&&);
-
- virtual void set_certificate(String certificate, String key) override;
-
- NonnullRefPtr<HTTP::HttpsJob> m_job;
-};
-
-}
diff --git a/Services/ProtocolServer/HttpsProtocol.cpp b/Services/ProtocolServer/HttpsProtocol.cpp
deleted file mode 100644
index ef8e63fd0d..0000000000
--- a/Services/ProtocolServer/HttpsProtocol.cpp
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (c) 2018-2020, The SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <LibHTTP/HttpRequest.h>
-#include <LibHTTP/HttpsJob.h>
-#include <ProtocolServer/HttpsDownload.h>
-#include <ProtocolServer/HttpsProtocol.h>
-
-namespace ProtocolServer {
-
-HttpsProtocol::HttpsProtocol()
- : Protocol("https")
-{
-}
-
-HttpsProtocol::~HttpsProtocol()
-{
-}
-
-OwnPtr<Download> HttpsProtocol::start_download(ClientConnection& client, const String& method, const URL& url, const HashMap<String, String>& headers, ReadonlyBytes body)
-{
- HTTP::HttpRequest request;
- if (method.equals_ignoring_case("post"))
- request.set_method(HTTP::HttpRequest::Method::POST);
- else
- request.set_method(HTTP::HttpRequest::Method::GET);
- request.set_url(url);
- request.set_headers(headers);
- request.set_body(body);
-
- auto pipe_result = get_pipe_for_download();
- if (pipe_result.is_error())
- return {};
-
- auto output_stream = make<OutputFileStream>(pipe_result.value().write_fd);
- output_stream->make_unbuffered();
- auto job = HTTP::HttpsJob::construct(request, *output_stream);
- auto download = HttpsDownload::create_with_job({}, client, (HTTP::HttpsJob&)*job, move(output_stream));
- download->set_download_fd(pipe_result.value().read_fd);
- job->start();
- return download;
-}
-
-}
diff --git a/Services/ProtocolServer/HttpsProtocol.h b/Services/ProtocolServer/HttpsProtocol.h
deleted file mode 100644
index 40e59aa271..0000000000
--- a/Services/ProtocolServer/HttpsProtocol.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2018-2020, The SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <ProtocolServer/Protocol.h>
-
-namespace ProtocolServer {
-
-class HttpsProtocol final : public Protocol {
-public:
- HttpsProtocol();
- virtual ~HttpsProtocol() override;
-
- virtual OwnPtr<Download> start_download(ClientConnection&, const String& method, const URL&, const HashMap<String, String>& headers, ReadonlyBytes body) override;
-};
-
-}
diff --git a/Services/ProtocolServer/Protocol.cpp b/Services/ProtocolServer/Protocol.cpp
deleted file mode 100644
index ee8248dfef..0000000000
--- a/Services/ProtocolServer/Protocol.cpp
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <AK/HashMap.h>
-#include <ProtocolServer/Protocol.h>
-#include <fcntl.h>
-#include <string.h>
-
-namespace ProtocolServer {
-
-static HashMap<String, Protocol*>& all_protocols()
-{
- static HashMap<String, Protocol*> map;
- return map;
-}
-
-Protocol* Protocol::find_by_name(const String& name)
-{
- return all_protocols().get(name).value_or(nullptr);
-}
-
-Protocol::Protocol(const String& name)
-{
- all_protocols().set(name, this);
-}
-
-Protocol::~Protocol()
-{
- ASSERT_NOT_REACHED();
-}
-
-Result<Protocol::Pipe, String> Protocol::get_pipe_for_download()
-{
- int fd_pair[2] { 0 };
- if (pipe(fd_pair) != 0) {
- auto saved_errno = errno;
- dbgln("Protocol: pipe() failed: {}", strerror(saved_errno));
- return String { strerror(saved_errno) };
- }
- fcntl(fd_pair[1], F_SETFL, fcntl(fd_pair[1], F_GETFL) | O_NONBLOCK);
- return Pipe { fd_pair[0], fd_pair[1] };
-}
-
-}
diff --git a/Services/ProtocolServer/Protocol.h b/Services/ProtocolServer/Protocol.h
deleted file mode 100644
index 89db931afb..0000000000
--- a/Services/ProtocolServer/Protocol.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <AK/RefPtr.h>
-#include <AK/Result.h>
-#include <AK/URL.h>
-#include <ProtocolServer/Forward.h>
-
-namespace ProtocolServer {
-
-class Protocol {
-public:
- virtual ~Protocol();
-
- const String& name() const { return m_name; }
- virtual OwnPtr<Download> start_download(ClientConnection&, const String& method, const URL&, const HashMap<String, String>& headers, ReadonlyBytes body) = 0;
-
- static Protocol* find_by_name(const String&);
-
-protected:
- explicit Protocol(const String& name);
- struct Pipe {
- int read_fd { -1 };
- int write_fd { -1 };
- };
- static Result<Pipe, String> get_pipe_for_download();
-
-private:
- String m_name;
-};
-
-}
diff --git a/Services/ProtocolServer/ProtocolClient.ipc b/Services/ProtocolServer/ProtocolClient.ipc
deleted file mode 100644
index 88f4cfc96d..0000000000
--- a/Services/ProtocolServer/ProtocolClient.ipc
+++ /dev/null
@@ -1,10 +0,0 @@
-endpoint ProtocolClient = 13
-{
- // Download notifications
- DownloadProgress(i32 download_id, Optional<u32> total_size, u32 downloaded_size) =|
- DownloadFinished(i32 download_id, bool success, u32 total_size) =|
- HeadersBecameAvailable(i32 download_id, IPC::Dictionary response_headers, Optional<u32> status_code) =|
-
- // Certificate requests
- CertificateRequested(i32 download_id) => ()
-}
diff --git a/Services/ProtocolServer/ProtocolServer.ipc b/Services/ProtocolServer/ProtocolServer.ipc
deleted file mode 100644
index a89eab506b..0000000000
--- a/Services/ProtocolServer/ProtocolServer.ipc
+++ /dev/null
@@ -1,13 +0,0 @@
-endpoint ProtocolServer = 9
-{
- // Basic protocol
- Greet() => (i32 client_id)
-
- // Test if a specific protocol is supported, e.g "http"
- IsSupportedProtocol(String protocol) => (bool supported)
-
- // Download API
- StartDownload(String method, URL url, IPC::Dictionary request_headers, ByteBuffer request_body) => (i32 download_id, Optional<IPC::File> response_fd)
- StopDownload(i32 download_id) => (bool success)
- SetCertificate(i32 download_id, String certificate, String key) => (bool success)
-}
diff --git a/Services/ProtocolServer/main.cpp b/Services/ProtocolServer/main.cpp
deleted file mode 100644
index 62fc908dd1..0000000000
--- a/Services/ProtocolServer/main.cpp
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <LibCore/EventLoop.h>
-#include <LibCore/LocalServer.h>
-#include <LibIPC/ClientConnection.h>
-#include <LibTLS/Certificate.h>
-#include <ProtocolServer/ClientConnection.h>
-#include <ProtocolServer/GeminiProtocol.h>
-#include <ProtocolServer/HttpProtocol.h>
-#include <ProtocolServer/HttpsProtocol.h>
-
-int main(int, char**)
-{
- if (pledge("stdio inet shared_buffer accept unix rpath cpath fattr sendfd recvfd", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- // Ensure the certificates are read out here.
- [[maybe_unused]] auto& certs = DefaultRootCACertificates::the();
-
- Core::EventLoop event_loop;
- // FIXME: Establish a connection to LookupServer and then drop "unix"?
- if (pledge("stdio inet shared_buffer accept unix sendfd recvfd", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
- if (unveil("/tmp/portal/lookup", "rw") < 0) {
- perror("unveil");
- return 1;
- }
- if (unveil(nullptr, nullptr) < 0) {
- perror("unveil");
- return 1;
- }
-
- [[maybe_unused]] auto gemini = new ProtocolServer::GeminiProtocol;
- [[maybe_unused]] auto http = new ProtocolServer::HttpProtocol;
- [[maybe_unused]] auto https = new ProtocolServer::HttpsProtocol;
-
- auto socket = Core::LocalSocket::take_over_accepted_socket_from_system_server();
- ASSERT(socket);
- IPC::new_client_connection<ProtocolServer::ClientConnection>(socket.release_nonnull(), 1);
- return event_loop.exec();
-}
diff --git a/Services/SystemMenu/CMakeLists.txt b/Services/SystemMenu/CMakeLists.txt
deleted file mode 100644
index 8d6a6adee8..0000000000
--- a/Services/SystemMenu/CMakeLists.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-set(SOURCES
- main.cpp
- ShutdownDialog.cpp
-)
-
-serenity_bin(SystemMenu)
-target_link_libraries(SystemMenu LibGUI LibDesktop)
diff --git a/Services/SystemMenu/ShutdownDialog.cpp b/Services/SystemMenu/ShutdownDialog.cpp
deleted file mode 100644
index 5f01b7308e..0000000000
--- a/Services/SystemMenu/ShutdownDialog.cpp
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "ShutdownDialog.h"
-#include <AK/String.h>
-#include <AK/Vector.h>
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/Button.h>
-#include <LibGUI/Label.h>
-#include <LibGUI/RadioButton.h>
-#include <LibGUI/Widget.h>
-#include <LibGfx/Font.h>
-#include <LibGfx/FontDatabase.h>
-
-struct Option {
- String title;
- Vector<char const*> cmd;
- bool enabled;
- bool default_action;
-};
-
-static const Vector<Option> options = {
- { "Shut down", { "/bin/shutdown", "--now", nullptr }, true, true },
- { "Restart", { "/bin/reboot", nullptr }, true, false },
- { "Log out", {}, false, false },
- { "Sleep", {}, false, false },
-};
-
-Vector<char const*> ShutdownDialog::show()
-{
- auto dialog = ShutdownDialog::construct();
- auto rc = dialog->exec();
- if (rc == ExecResult::ExecOK && dialog->m_selected_option != -1)
- return options[dialog->m_selected_option].cmd;
-
- return {};
-}
-
-ShutdownDialog::ShutdownDialog()
- : Dialog(nullptr)
-{
- resize(180, 180 + ((static_cast<int>(options.size()) - 3) * 16));
- center_on_screen();
- set_resizable(false);
- set_title("SerenityOS");
- set_icon(Gfx::Bitmap::load_from_file("/res/icons/16x16/power.png"));
-
- auto& main = set_main_widget<GUI::Widget>();
- main.set_layout<GUI::VerticalBoxLayout>();
- main.layout()->set_margins({ 8, 8, 8, 8 });
- main.layout()->set_spacing(8);
- main.set_fill_with_background_color(true);
-
- auto& header = main.add<GUI::Label>();
- header.set_text("What would you like to do?");
- header.set_fixed_height(16);
- header.set_font(Gfx::FontDatabase::default_bold_font());
-
- for (size_t i = 0; i < options.size(); i++) {
- auto action = options[i];
- auto& radio = main.add<GUI::RadioButton>();
- radio.set_enabled(action.enabled);
- radio.set_text(action.title);
-
- radio.on_checked = [this, i](auto) {
- m_selected_option = i;
- };
-
- if (action.default_action) {
- radio.set_checked(true);
- m_selected_option = i;
- }
- }
-
- auto& button_box = main.add<GUI::Widget>();
- button_box.set_layout<GUI::HorizontalBoxLayout>();
- button_box.layout()->set_spacing(8);
-
- auto& ok_button = button_box.add<GUI::Button>();
- ok_button.on_click = [this](auto) {
- done(ExecResult::ExecOK);
- };
- ok_button.set_text("OK");
-
- auto& cancel_button = button_box.add<GUI::Button>();
- cancel_button.on_click = [this](auto) {
- done(ExecResult::ExecCancel);
- };
- cancel_button.set_text("Cancel");
-}
-
-ShutdownDialog::~ShutdownDialog()
-{
-}
diff --git a/Services/SystemMenu/ShutdownDialog.h b/Services/SystemMenu/ShutdownDialog.h
deleted file mode 100644
index 73f581916c..0000000000
--- a/Services/SystemMenu/ShutdownDialog.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <AK/Vector.h>
-#include <LibGUI/Dialog.h>
-
-class ShutdownDialog : public GUI::Dialog {
- C_OBJECT(ShutdownDialog);
-
-public:
- static Vector<char const*> show();
-
-private:
- ShutdownDialog();
- virtual ~ShutdownDialog() override;
-
- int m_selected_option { -1 };
-};
diff --git a/Services/SystemMenu/main.cpp b/Services/SystemMenu/main.cpp
deleted file mode 100644
index af532ee4cf..0000000000
--- a/Services/SystemMenu/main.cpp
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "ShutdownDialog.h"
-#include <AK/LexicalPath.h>
-#include <AK/QuickSort.h>
-#include <LibCore/ConfigFile.h>
-#include <LibCore/DirIterator.h>
-#include <LibCore/StandardPaths.h>
-#include <LibDesktop/AppFile.h>
-#include <LibGUI/Action.h>
-#include <LibGUI/ActionGroup.h>
-#include <LibGUI/Application.h>
-#include <LibGUI/FileIconProvider.h>
-#include <LibGUI/Icon.h>
-#include <LibGUI/Menu.h>
-#include <LibGUI/WindowServerConnection.h>
-#include <LibGfx/Bitmap.h>
-#include <serenity.h>
-#include <spawn.h>
-
-//#define SYSTEM_MENU_DEBUG
-
-struct AppMetadata {
- String executable;
- String name;
- String category;
-};
-Vector<AppMetadata> g_apps;
-
-struct ThemeMetadata {
- String name;
- String path;
-};
-
-Color g_menu_selection_color;
-
-Vector<ThemeMetadata> g_themes;
-RefPtr<GUI::Menu> g_themes_menu;
-GUI::ActionGroup g_themes_group;
-
-static Vector<String> discover_apps_and_categories();
-static NonnullRefPtr<GUI::Menu> build_system_menu();
-
-int main(int argc, char** argv)
-{
- auto app = GUI::Application::construct(argc, argv);
- app->set_quit_when_last_window_deleted(false);
-
- auto menu = build_system_menu();
- menu->realize_menu_if_needed();
-
- GUI::WindowServerConnection::the().send_sync<Messages::WindowServer::SetSystemMenu>(menu->menu_id());
-
- if (pledge("stdio shared_buffer accept rpath proc exec", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- if (chdir(Core::StandardPaths::home_directory().characters()) < 0) {
- perror("chdir");
- return 1;
- }
-
- if (unveil("/bin", "x")) {
- perror("unveil");
- return 1;
- }
-
- if (unveil("/res", "r")) {
- perror("unveil");
- return 1;
- }
-
- unveil(nullptr, nullptr);
-
- return app->exec();
-}
-
-Vector<String> discover_apps_and_categories()
-{
- HashTable<String> seen_app_categories;
- Desktop::AppFile::for_each([&](auto af) {
- g_apps.append({ af->executable(), af->name(), af->category() });
- seen_app_categories.set(af->category());
- });
- quick_sort(g_apps, [](auto& a, auto& b) { return a.name < b.name; });
-
- Vector<String> sorted_app_categories;
- for (auto& category : seen_app_categories) {
- sorted_app_categories.append(category);
- }
- quick_sort(sorted_app_categories);
-
- return sorted_app_categories;
-}
-
-NonnullRefPtr<GUI::Menu> build_system_menu()
-{
- const Vector<String> sorted_app_categories = discover_apps_and_categories();
- auto system_menu = GUI::Menu::construct("\xE2\x9A\xA1"); // HIGH VOLTAGE SIGN
-
- // First we construct all the necessary app category submenus.
- HashMap<String, NonnullRefPtr<GUI::Menu>> app_category_menus;
- auto category_icons = Core::ConfigFile::open("/res/icons/SystemMenu.ini");
- for (const auto& category : sorted_app_categories) {
- if (app_category_menus.contains(category))
- continue;
- auto& category_menu = system_menu->add_submenu(category);
- auto category_icon_path = category_icons->read_entry("16x16", category);
- if (!category_icon_path.is_empty()) {
- auto icon = Gfx::Bitmap::load_from_file(category_icon_path);
- category_menu.set_icon(icon);
- }
- app_category_menus.set(category, category_menu);
- }
-
- // Then we create and insert all the app menu items into the right place.
- int app_identifier = 0;
- for (const auto& app : g_apps) {
- auto icon = GUI::FileIconProvider::icon_for_executable(app.executable).bitmap_for_size(16);
-
-#ifdef SYSTEM_MENU_DEBUG
- if (icon)
- dbg() << "App " << app.name << " has icon with size " << icon->size();
-#endif
-
- auto parent_menu = app_category_menus.get(app.category).value_or(*system_menu);
- parent_menu->add_action(GUI::Action::create(app.name, icon, [app_identifier](auto&) {
- dbg() << "Activated app with ID " << app_identifier;
- const auto& bin = g_apps[app_identifier].executable;
- pid_t child_pid;
- const char* argv[] = { bin.characters(), nullptr };
- if ((errno = posix_spawn(&child_pid, bin.characters(), nullptr, nullptr, const_cast<char**>(argv), environ))) {
- perror("posix_spawn");
- } else {
- if (disown(child_pid) < 0)
- perror("disown");
- }
- }));
- ++app_identifier;
- }
-
- system_menu->add_separator();
-
- g_themes_group.set_exclusive(true);
- g_themes_group.set_unchecking_allowed(false);
-
- g_themes_menu = &system_menu->add_submenu("Themes");
- g_themes_menu->set_icon(Gfx::Bitmap::load_from_file("/res/icons/16x16/themes.png"));
-
- {
- Core::DirIterator dt("/res/themes", Core::DirIterator::SkipDots);
- while (dt.has_next()) {
- auto theme_name = dt.next_path();
- auto theme_path = String::format("/res/themes/%s", theme_name.characters());
- g_themes.append({ LexicalPath(theme_name).title(), theme_path });
- }
- quick_sort(g_themes, [](auto& a, auto& b) { return a.name < b.name; });
- }
-
- auto current_theme_name = GUI::WindowServerConnection::the().send_sync<Messages::WindowServer::GetSystemTheme>()->theme_name();
-
- {
- int theme_identifier = 0;
- for (auto& theme : g_themes) {
- auto action = GUI::Action::create_checkable(theme.name, [theme_identifier](auto&) {
- auto& theme = g_themes[theme_identifier];
- dbg() << "Theme switched to " << theme.name << " at path " << theme.path;
- auto response = GUI::WindowServerConnection::the().send_sync<Messages::WindowServer::SetSystemTheme>(theme.path, theme.name);
- ASSERT(response->success());
- });
- if (theme.name == current_theme_name)
- action->set_checked(true);
- g_themes_group.add_action(action);
- g_themes_menu->add_action(action);
- ++theme_identifier;
- }
- }
-
- system_menu->add_separator();
- system_menu->add_action(GUI::Action::create("About SerenityOS", Gfx::Bitmap::load_from_file("/res/icons/16x16/ladybug.png"), [](auto&) {
- pid_t child_pid;
- const char* argv[] = { "/bin/About", nullptr };
- if ((errno = posix_spawn(&child_pid, "/bin/About", nullptr, nullptr, const_cast<char**>(argv), environ))) {
- perror("posix_spawn");
- } else {
- if (disown(child_pid) < 0)
- perror("disown");
- }
- }));
- system_menu->add_separator();
- system_menu->add_action(GUI::Action::create("Exit...", Gfx::Bitmap::load_from_file("/res/icons/16x16/power.png"), [](auto&) {
- auto command = ShutdownDialog::show();
-
- if (command.size() == 0)
- return;
-
- pid_t child_pid;
- if ((errno = posix_spawn(&child_pid, command[0], nullptr, nullptr, const_cast<char**>(command.data()), environ))) {
- perror("posix_spawn");
- } else {
- if (disown(child_pid) < 0)
- perror("disown");
- }
- }));
-
- return system_menu;
-}
diff --git a/Services/SystemServer/CMakeLists.txt b/Services/SystemServer/CMakeLists.txt
deleted file mode 100644
index fda6eb1bcc..0000000000
--- a/Services/SystemServer/CMakeLists.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-set(SOURCES
- main.cpp
- Service.cpp
-)
-
-serenity_bin(SystemServer)
-target_link_libraries(SystemServer LibCore)
diff --git a/Services/SystemServer/Service.cpp b/Services/SystemServer/Service.cpp
deleted file mode 100644
index 99b01b5ab6..0000000000
--- a/Services/SystemServer/Service.cpp
+++ /dev/null
@@ -1,376 +0,0 @@
-/*
- * Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "Service.h"
-#include <AK/HashMap.h>
-#include <AK/JsonArray.h>
-#include <AK/JsonObject.h>
-#include <LibCore/ConfigFile.h>
-#include <LibCore/File.h>
-#include <LibCore/Socket.h>
-#include <grp.h>
-#include <libgen.h>
-#include <pwd.h>
-#include <sched.h>
-#include <stdio.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-static HashMap<pid_t, Service*> s_service_map;
-
-Service* Service::find_by_pid(pid_t pid)
-{
- auto it = s_service_map.find(pid);
- if (it == s_service_map.end())
- return nullptr;
- return (*it).value;
-}
-
-void Service::setup_socket()
-{
- ASSERT(!m_socket_path.is_null());
- ASSERT(m_socket_fd == -1);
-
- auto ok = Core::File::ensure_parent_directories(m_socket_path);
- ASSERT(ok);
-
- // Note: we use SOCK_CLOEXEC here to make sure we don't leak every socket to
- // all the clients. We'll make the one we do need to pass down !CLOEXEC later
- // after forking off the process.
- m_socket_fd = socket(AF_LOCAL, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
- if (m_socket_fd < 0) {
- perror("socket");
- ASSERT_NOT_REACHED();
- }
-
- if (m_account.has_value()) {
- auto& account = m_account.value();
- if (fchown(m_socket_fd, account.uid(), account.gid()) < 0) {
- perror("fchown");
- ASSERT_NOT_REACHED();
- }
- }
-
- if (fchmod(m_socket_fd, m_socket_permissions) < 0) {
- perror("fchmod");
- ASSERT_NOT_REACHED();
- }
-
- auto socket_address = Core::SocketAddress::local(m_socket_path);
- auto un_optional = socket_address.to_sockaddr_un();
- if (!un_optional.has_value()) {
- dbg() << "Socket name " << m_socket_path << " is too long. BUG! This should have failed earlier!";
- ASSERT_NOT_REACHED();
- }
- auto un = un_optional.value();
- int rc = bind(m_socket_fd, (const sockaddr*)&un, sizeof(un));
- if (rc < 0) {
- perror("bind");
- ASSERT_NOT_REACHED();
- }
-
- rc = listen(m_socket_fd, 16);
- if (rc < 0) {
- perror("listen");
- ASSERT_NOT_REACHED();
- }
-}
-
-void Service::setup_notifier()
-{
- ASSERT(m_lazy);
- ASSERT(m_socket_fd >= 0);
- ASSERT(!m_socket_notifier);
-
- m_socket_notifier = Core::Notifier::construct(m_socket_fd, Core::Notifier::Event::Read, this);
- m_socket_notifier->on_ready_to_read = [this] {
- handle_socket_connection();
- };
-}
-
-void Service::handle_socket_connection()
-{
-#ifdef SERVICE_DEBUG
- dbg() << "Ready to read on behalf of " << name();
-#endif
- if (m_accept_socket_connections) {
- int accepted_fd = accept(m_socket_fd, nullptr, nullptr);
- if (accepted_fd < 0) {
- perror("accept");
- return;
- }
- spawn(accepted_fd);
- close(accepted_fd);
- } else {
- remove_child(*m_socket_notifier);
- m_socket_notifier = nullptr;
- spawn(m_socket_fd);
- }
-}
-
-void Service::activate()
-{
- ASSERT(m_pid < 0);
-
- if (m_lazy)
- setup_notifier();
- else
- spawn(m_socket_fd);
-}
-
-void Service::spawn(int socket_fd)
-{
-#ifdef SERVICE_DEBUG
- dbg() << "Spawning " << name();
-#endif
-
- m_run_timer.start();
- pid_t pid = fork();
-
- if (pid < 0) {
- perror("fork");
- dbg() << "Failed to spawn " << name() << ". Sucks, dude :(";
- } else if (pid == 0) {
- // We are the child.
-
- if (!m_working_directory.is_null()) {
- if (chdir(m_working_directory.characters()) < 0) {
- perror("chdir");
- ASSERT_NOT_REACHED();
- }
- }
-
- struct sched_param p;
- p.sched_priority = m_priority;
- int rc = sched_setparam(0, &p);
- if (rc < 0) {
- perror("sched_setparam");
- ASSERT_NOT_REACHED();
- }
-
- if (!m_stdio_file_path.is_null()) {
- close(STDIN_FILENO);
- int fd = open_with_path_length(m_stdio_file_path.characters(), m_stdio_file_path.length(), O_RDWR, 0);
- ASSERT(fd <= 0);
- if (fd < 0) {
- perror("open");
- ASSERT_NOT_REACHED();
- }
- dup2(STDIN_FILENO, STDOUT_FILENO);
- dup2(STDIN_FILENO, STDERR_FILENO);
-
- if (isatty(STDIN_FILENO)) {
- ioctl(STDIN_FILENO, TIOCSCTTY);
- }
- } else {
- if (isatty(STDIN_FILENO)) {
- ioctl(STDIN_FILENO, TIOCNOTTY);
- }
- close(STDIN_FILENO);
- close(STDOUT_FILENO);
- close(STDERR_FILENO);
-
- int fd = open("/dev/null", O_RDWR);
- ASSERT(fd == STDIN_FILENO);
- dup2(STDIN_FILENO, STDOUT_FILENO);
- dup2(STDIN_FILENO, STDERR_FILENO);
- }
-
- if (socket_fd >= 0) {
- ASSERT(!m_socket_path.is_null());
- ASSERT(socket_fd > 3);
- dup2(socket_fd, 3);
- // The new descriptor is !CLOEXEC here.
- setenv("SOCKET_TAKEOVER", "1", true);
- }
-
- if (m_account.has_value()) {
- auto& account = m_account.value();
- if (setgid(account.gid()) < 0 || setgroups(account.extra_gids().size(), account.extra_gids().data()) < 0 || setuid(account.uid()) < 0) {
- dbgln("Failed to drop privileges (GID={}, UID={})\n", account.gid(), account.uid());
- exit(1);
- }
- setenv("HOME", account.home_directory().characters(), true);
- }
-
- for (String& env : m_environment)
- putenv(const_cast<char*>(env.characters()));
-
- char* argv[m_extra_arguments.size() + 2];
- argv[0] = const_cast<char*>(m_executable_path.characters());
- for (size_t i = 0; i < m_extra_arguments.size(); i++)
- argv[i + 1] = const_cast<char*>(m_extra_arguments[i].characters());
- argv[m_extra_arguments.size() + 1] = nullptr;
-
- rc = execv(argv[0], argv);
- perror("exec");
- ASSERT_NOT_REACHED();
- } else if (!m_multi_instance) {
- // We are the parent.
- m_pid = pid;
- s_service_map.set(pid, this);
- }
-}
-
-void Service::did_exit(int exit_code)
-{
- ASSERT(m_pid > 0);
- ASSERT(!m_multi_instance);
-
- dbg() << "Service " << name() << " has exited with exit code " << exit_code;
-
- s_service_map.remove(m_pid);
- m_pid = -1;
-
- if (!m_keep_alive)
- return;
-
- int run_time_in_msec = m_run_timer.elapsed();
- bool exited_successfully = exit_code == 0;
-
- if (!exited_successfully && run_time_in_msec < 1000) {
- switch (m_restart_attempts) {
- case 0:
- dbgln("Trying again");
- break;
- case 1:
- dbgln("Third time's a charm?");
- break;
- default:
- dbg() << "Giving up on " << name() << ". Good luck!";
- return;
- }
- m_restart_attempts++;
- }
-
- activate();
-}
-
-Service::Service(const Core::ConfigFile& config, const StringView& name)
- : Core::Object(nullptr)
-{
- ASSERT(config.has_group(name));
-
- set_name(name);
- m_executable_path = config.read_entry(name, "Executable", String::format("/bin/%s", this->name().characters()));
- m_extra_arguments = config.read_entry(name, "Arguments", "").split(' ');
- m_stdio_file_path = config.read_entry(name, "StdIO");
-
- String prio = config.read_entry(name, "Priority");
- if (prio == "low")
- m_priority = 10;
- else if (prio == "normal" || prio.is_null())
- m_priority = 30;
- else if (prio == "high")
- m_priority = 50;
- else
- ASSERT_NOT_REACHED();
-
- m_keep_alive = config.read_bool_entry(name, "KeepAlive");
- m_lazy = config.read_bool_entry(name, "Lazy");
-
- m_user = config.read_entry(name, "User");
- if (!m_user.is_null()) {
- auto result = Core::Account::from_name(m_user.characters());
- if (result.is_error())
- warnln("Failed to resolve user {}: {}", m_user, result.error());
- else
- m_account = result.value();
- }
-
- m_working_directory = config.read_entry(name, "WorkingDirectory");
- m_environment = config.read_entry(name, "Environment").split(' ');
- m_boot_modes = config.read_entry(name, "BootModes", "graphical").split(',');
- m_multi_instance = config.read_bool_entry(name, "MultiInstance");
- m_accept_socket_connections = config.read_bool_entry(name, "AcceptSocketConnections");
-
- m_socket_path = config.read_entry(name, "Socket");
-
- // Lazy requires Socket.
- ASSERT(!m_lazy || !m_socket_path.is_null());
- // AcceptSocketConnections always requires Socket, Lazy, and MultiInstance.
- ASSERT(!m_accept_socket_connections || (!m_socket_path.is_null() && m_lazy && m_multi_instance));
- // MultiInstance doesn't work with KeepAlive.
- ASSERT(!m_multi_instance || !m_keep_alive);
- // Socket path (plus NUL) must fit into the structs sent to the Kernel.
- ASSERT(m_socket_path.length() < UNIX_PATH_MAX);
-
- if (!m_socket_path.is_null() && is_enabled()) {
- auto socket_permissions_string = config.read_entry(name, "SocketPermissions", "0600");
- m_socket_permissions = strtol(socket_permissions_string.characters(), nullptr, 8) & 04777;
- setup_socket();
- }
-}
-
-void Service::save_to(JsonObject& json)
-{
- Core::Object::save_to(json);
-
- json.set("executable_path", m_executable_path);
-
- // FIXME: This crashes Inspector.
- /*
- JsonArray extra_args;
- for (String& arg : m_extra_arguments)
- extra_args.append(arg);
- json.set("extra_arguments", move(extra_args));
-
- JsonArray boot_modes;
- for (String& mode : m_boot_modes)
- boot_modes.append(mode);
- json.set("boot_modes", boot_modes);
-
- JsonArray environment;
- for (String& env : m_environment)
- boot_modes.append(env);
- json.set("environment", environment);
- */
-
- json.set("stdio_file_path", m_stdio_file_path);
- json.set("priority", m_priority);
- json.set("keep_alive", m_keep_alive);
- json.set("socket_path", m_socket_path);
- json.set("socket_permissions", m_socket_permissions);
- json.set("lazy", m_lazy);
- json.set("user", m_user);
- json.set("multi_instance", m_multi_instance);
- json.set("accept_socket_connections", m_accept_socket_connections);
-
- if (m_pid > 0)
- json.set("pid", m_pid);
- else
- json.set("pid", nullptr);
-
- json.set("restart_attempts", m_restart_attempts);
- json.set("working_directory", m_working_directory);
-}
-
-bool Service::is_enabled() const
-{
- extern String g_boot_mode;
- return m_boot_modes.contains_slow(g_boot_mode);
-}
diff --git a/Services/SystemServer/Service.h b/Services/SystemServer/Service.h
deleted file mode 100644
index 23014825cf..0000000000
--- a/Services/SystemServer/Service.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <AK/RefPtr.h>
-#include <AK/String.h>
-#include <LibCore/Account.h>
-#include <LibCore/ElapsedTimer.h>
-#include <LibCore/Notifier.h>
-#include <LibCore/Object.h>
-
-class Service final : public Core::Object {
- C_OBJECT(Service)
-
-public:
- bool is_enabled() const;
- void activate();
- void did_exit(int exit_code);
-
- static Service* find_by_pid(pid_t);
-
- // FIXME: Port to Core::Property
- void save_to(AK::JsonObject&);
-
-private:
- Service(const Core::ConfigFile&, const StringView& name);
-
- void spawn(int socket_fd = -1);
-
- // Path to the executable. By default this is /bin/{m_name}.
- String m_executable_path;
- // Extra arguments, starting from argv[1], to pass when exec'ing.
- Vector<String> m_extra_arguments;
- // File path to open as stdio fds.
- String m_stdio_file_path;
- int m_priority { 1 };
- // Whether we should re-launch it if it exits.
- bool m_keep_alive { false };
- // Path to the socket to create and listen on on behalf of this service.
- String m_socket_path;
- // File system permissions for the socket.
- mode_t m_socket_permissions { 0 };
- // Whether we should accept connections on the socket and pass the accepted
- // (and not listening) socket to the service. This requires a multi-instance
- // service.
- bool m_accept_socket_connections { false };
- // Whether we should only spawn this service once somebody connects to the socket.
- bool m_lazy;
- // The name of the user we should run this service as.
- String m_user;
- // The working directory in which to spawn the service.
- String m_working_directory;
- // Boot modes to run this service in. By default, this is the graphical mode.
- Vector<String> m_boot_modes;
- // Whether several instances of this service can run at once.
- bool m_multi_instance { false };
- // Environment variables to pass to the service.
- Vector<String> m_environment;
-
- // The resolved user account to run this service as.
- Optional<Core::Account> m_account;
-
- // For single-instance services, PID of the running instance of this service.
- pid_t m_pid { -1 };
- // An open fd to the socket.
- int m_socket_fd { -1 };
- RefPtr<Core::Notifier> m_socket_notifier;
-
- // Timer since we last spawned the service.
- Core::ElapsedTimer m_run_timer;
- // How many times we have tried to restart this service, only counting those
- // times where it has exited unsuccessfully and too quickly.
- int m_restart_attempts { 0 };
-
- void setup_socket();
- void setup_notifier();
- void handle_socket_connection();
-};
diff --git a/Services/SystemServer/main.cpp b/Services/SystemServer/main.cpp
deleted file mode 100644
index 6409b0eda6..0000000000
--- a/Services/SystemServer/main.cpp
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "Service.h"
-#include <AK/Assertions.h>
-#include <AK/ByteBuffer.h>
-#include <LibCore/ConfigFile.h>
-#include <LibCore/Event.h>
-#include <LibCore/EventLoop.h>
-#include <LibCore/File.h>
-#include <errno.h>
-#include <signal.h>
-#include <stdio.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-String g_boot_mode = "graphical";
-
-static void sigchld_handler(int)
-{
- for (;;) {
- int status = 0;
- pid_t pid = waitpid(-1, &status, WNOHANG);
- if (pid < 0) {
- perror("waitpid");
- break;
- }
- if (pid == 0)
- break;
-
-#ifdef SYSTEMSERVER_DEBUG
- dbg() << "Reaped child with pid " << pid << ", exit status " << status;
-#endif
-
- Service* service = Service::find_by_pid(pid);
- if (service == nullptr) {
- // This can happen for multi-instance services.
- continue;
- }
-
- service->did_exit(status);
- }
-}
-
-static void parse_boot_mode()
-{
- auto f = Core::File::construct("/proc/cmdline");
- if (!f->open(Core::IODevice::ReadOnly)) {
- dbg() << "Failed to read command line: " << f->error_string();
- return;
- }
- const String cmdline = String::copy(f->read_all(), Chomp);
- dbg() << "Read command line: " << cmdline;
-
- for (auto& part : cmdline.split_view(' ')) {
- auto pair = part.split_view('=', 2);
- if (pair.size() == 2 && pair[0] == "boot_mode")
- g_boot_mode = pair[1];
- }
- dbg() << "Booting in " << g_boot_mode << " mode";
-}
-
-static void prepare_devfs()
-{
- // FIXME: Find a better way to all of this stuff, without hardcoding all of this!
-
- int rc = mount(-1, "/dev", "dev", 0);
- if (rc != 0) {
- ASSERT_NOT_REACHED();
- }
-
- rc = mkdir("/dev/pts", 0755);
- if (rc != 0) {
- ASSERT_NOT_REACHED();
- }
-
- rc = mount(-1, "/dev/pts", "devpts", 0);
- if (rc != 0) {
- ASSERT_NOT_REACHED();
- }
-
- rc = symlink("/dev/random", "/dev/urandom");
- if (rc < 0) {
- ASSERT_NOT_REACHED();
- }
-
- // FIXME: Find a better way to chown without hardcoding the gid!
- // This will fail with ENOENT in text mode.
- rc = chown("/dev/fb0", 0, 3);
- if (rc < 0 && errno != ENOENT) {
- ASSERT_NOT_REACHED();
- }
-
- // FIXME: Find a better way to chown without hardcoding the gid!
- rc = chown("/dev/keyboard", 0, 3);
- if (rc < 0) {
- ASSERT_NOT_REACHED();
- }
-
- // FIXME: Find a better way to chown without hardcoding the gid!
- rc = chown("/dev/mouse", 0, 3);
- if (rc < 0) {
- ASSERT_NOT_REACHED();
- }
-
- for (size_t index = 0; index < 4; index++) {
- // FIXME: Find a better way to chown without hardcoding the gid!
- rc = chown(String::formatted("/dev/tty{}", index).characters(), 0, 2);
- if (rc < 0) {
- ASSERT_NOT_REACHED();
- }
- }
-
- for (size_t index = 0; index < 4; index++) {
- // FIXME: Find a better way to chown without hardcoding the gid!
- rc = chown(String::formatted("/dev/ttyS{}", index).characters(), 0, 2);
- if (rc < 0) {
- ASSERT_NOT_REACHED();
- }
- }
-
- // FIXME: Find a better way to chown without hardcoding the gid!
- rc = chown("/dev/audio", 0, 4);
- if (rc < 0) {
- ASSERT_NOT_REACHED();
- }
-
- rc = symlink("/proc/self/fd/0", "/dev/stdin");
- if (rc < 0) {
- ASSERT_NOT_REACHED();
- }
- rc = symlink("/proc/self/fd/1", "/dev/stdout");
- if (rc < 0) {
- ASSERT_NOT_REACHED();
- }
- rc = symlink("/proc/self/fd/2", "/dev/stderr");
- if (rc < 0) {
- ASSERT_NOT_REACHED();
- }
-}
-
-static void mount_all_filesystems()
-{
- dbgln("Spawning mount -a to mount all filesystems.");
- pid_t pid = fork();
-
- if (pid < 0) {
- perror("fork");
- ASSERT_NOT_REACHED();
- } else if (pid == 0) {
- execl("/bin/mount", "mount", "-a", nullptr);
- perror("exec");
- ASSERT_NOT_REACHED();
- } else {
- wait(nullptr);
- }
-}
-
-static void create_tmp_rpc_directory()
-{
- dbgln("Creating /tmp/rpc directory");
- auto old_umask = umask(0);
- auto rc = mkdir("/tmp/rpc", 01777);
- if (rc < 0) {
- perror("mkdir(/tmp/rpc)");
- ASSERT_NOT_REACHED();
- }
- umask(old_umask);
-}
-
-static void create_tmp_coredump_directory()
-{
- dbgln("Creating /tmp/coredump directory");
- auto old_umask = umask(0);
- auto rc = mkdir("/tmp/coredump", 0755);
- if (rc < 0) {
- perror("mkdir(/tmp/coredump)");
- ASSERT_NOT_REACHED();
- }
- umask(old_umask);
-}
-
-int main(int, char**)
-{
- prepare_devfs();
-
- if (pledge("stdio proc exec tty accept unix rpath wpath cpath chown fattr id sigaction", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- mount_all_filesystems();
- create_tmp_rpc_directory();
- create_tmp_coredump_directory();
- parse_boot_mode();
-
- Core::EventLoop event_loop;
-
- event_loop.register_signal(SIGCHLD, sigchld_handler);
-
- // Read our config and instantiate services.
- // This takes care of setting up sockets.
- NonnullRefPtrVector<Service> services;
- auto config = Core::ConfigFile::get_for_system("SystemServer");
- for (auto name : config->groups()) {
- auto service = Service::construct(*config, name);
- if (service->is_enabled())
- services.append(service);
- }
-
- // After we've set them all up, activate them!
- dbg() << "Activating " << services.size() << " services...";
- for (auto& service : services)
- service.activate();
-
- return event_loop.exec();
-}
diff --git a/Services/Taskbar/CMakeLists.txt b/Services/Taskbar/CMakeLists.txt
deleted file mode 100644
index 83de9ee9c8..0000000000
--- a/Services/Taskbar/CMakeLists.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-set(SOURCES
- main.cpp
- TaskbarButton.cpp
- TaskbarWindow.cpp
- WindowList.cpp
-)
-
-serenity_bin(Taskbar)
-target_link_libraries(Taskbar LibGUI LibDesktop)
diff --git a/Services/Taskbar/TaskbarButton.cpp b/Services/Taskbar/TaskbarButton.cpp
deleted file mode 100644
index 69103ca5e0..0000000000
--- a/Services/Taskbar/TaskbarButton.cpp
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "TaskbarButton.h"
-#include "WindowList.h"
-#include <LibGUI/Action.h>
-#include <LibGUI/Painter.h>
-#include <LibGUI/WindowServerConnection.h>
-#include <LibGfx/Font.h>
-#include <LibGfx/FontDatabase.h>
-#include <LibGfx/Palette.h>
-#include <LibGfx/StylePainter.h>
-
-TaskbarButton::TaskbarButton(const WindowIdentifier& identifier)
- : m_identifier(identifier)
-{
-}
-
-TaskbarButton::~TaskbarButton()
-{
-}
-
-void TaskbarButton::context_menu_event(GUI::ContextMenuEvent&)
-{
- GUI::WindowServerConnection::the().post_message(Messages::WindowServer::WM_PopupWindowMenu(m_identifier.client_id(), m_identifier.window_id(), screen_relative_rect().location()));
-}
-
-void TaskbarButton::update_taskbar_rect()
-{
- GUI::WindowServerConnection::the().post_message(
- Messages::WindowServer::WM_SetWindowTaskbarRect(
- m_identifier.client_id(),
- m_identifier.window_id(),
- screen_relative_rect()));
-}
-
-void TaskbarButton::clear_taskbar_rect()
-{
- GUI::WindowServerConnection::the().post_message(
- Messages::WindowServer::WM_SetWindowTaskbarRect(
- m_identifier.client_id(),
- m_identifier.window_id(),
- {}));
-}
-
-void TaskbarButton::resize_event(GUI::ResizeEvent& event)
-{
- update_taskbar_rect();
- return GUI::Button::resize_event(event);
-}
-
-static void paint_custom_progress_bar(GUI::Painter& painter, const Gfx::IntRect& rect, const Gfx::IntRect& text_rect, const Palette& palette, int min, int max, int value, const StringView& text, const Gfx::Font& font, Gfx::TextAlignment text_alignment)
-{
- float range_size = max - min;
- float progress = (value - min) / range_size;
- float progress_width = progress * rect.width();
-
- Gfx::IntRect progress_rect { rect.x(), rect.y(), (int)progress_width, rect.height() };
-
- {
- Gfx::PainterStateSaver saver(painter);
- painter.add_clip_rect(progress_rect);
-
- Color start_color = palette.active_window_border1();
- Color end_color = palette.active_window_border2();
- painter.fill_rect_with_gradient(rect, start_color, end_color);
-
- if (!text.is_null()) {
- painter.draw_text(text_rect.translated(1, 1), text, font, text_alignment, palette.base_text(), Gfx::TextElision::Right);
- painter.draw_text(text_rect, text, font, text_alignment, palette.base_text().inverted(), Gfx::TextElision::Right);
- }
- }
-
- Gfx::IntRect hole_rect { (int)progress_width, 0, (int)(rect.width() - progress_width), rect.height() };
- hole_rect.move_by(rect.location());
- hole_rect.set_right_without_resize(rect.right());
- Gfx::PainterStateSaver saver(painter);
- painter.add_clip_rect(hole_rect);
- if (!text.is_null())
- painter.draw_text(text_rect, text, font, text_alignment, palette.base_text(), Gfx::TextElision::Right);
-}
-
-void TaskbarButton::paint_event(GUI::PaintEvent& event)
-{
- ASSERT(icon());
- auto& icon = *this->icon();
- auto& font = is_checked() ? Gfx::FontDatabase::default_bold_font() : this->font();
- auto& window = WindowList::the().ensure_window(m_identifier);
-
- GUI::Painter painter(*this);
- painter.add_clip_rect(event.rect());
-
- Gfx::StylePainter::paint_button(painter, rect(), palette(), button_style(), is_being_pressed(), is_hovered(), is_checked(), is_enabled());
-
- if (text().is_empty())
- return;
-
- bool has_progress = window.progress() >= 0 && window.progress() <= 100;
-
- auto content_rect = rect().shrunken(8, 2);
- auto icon_location = content_rect.center().translated(-(icon.width() / 2), -(icon.height() / 2));
- if (!text().is_empty())
- icon_location.set_x(content_rect.x());
-
- if (!text().is_empty()) {
- content_rect.move_by(icon.width() + 4, 0);
- content_rect.set_width(content_rect.width() - icon.width() - 4);
- }
-
- Gfx::IntRect text_rect { 0, 0, font.width(text()), font.glyph_height() };
- if (text_rect.width() > content_rect.width())
- text_rect.set_width(content_rect.width());
- text_rect.align_within(content_rect, text_alignment());
-
- if (is_being_pressed() || is_checked()) {
- text_rect.move_by(1, 1);
- icon_location.move_by(1, 1);
- }
-
- if (has_progress) {
- auto adjusted_rect = rect().shrunken(4, 4);
- if (is_being_pressed() || is_checked()) {
- adjusted_rect.set_height(adjusted_rect.height() + 1);
- }
- paint_custom_progress_bar(painter, adjusted_rect, text_rect, palette(), 0, 100, window.progress(), text(), font, text_alignment());
- }
-
- if (is_enabled()) {
- if (is_hovered())
- painter.blit_brightened(icon_location, icon, icon.rect());
- else
- painter.blit(icon_location, icon, icon.rect());
- } else {
- painter.blit_disabled(icon_location, icon, icon.rect(), palette());
- }
-
- if (!has_progress)
- paint_text(painter, text_rect, font, text_alignment());
-}
diff --git a/Services/Taskbar/TaskbarButton.h b/Services/Taskbar/TaskbarButton.h
deleted file mode 100644
index b990c04d03..0000000000
--- a/Services/Taskbar/TaskbarButton.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include "WindowIdentifier.h"
-#include <LibGUI/Button.h>
-
-class TaskbarButton final : public GUI::Button {
- C_OBJECT(TaskbarButton)
-public:
- virtual ~TaskbarButton() override;
-
- void update_taskbar_rect();
- void clear_taskbar_rect();
-
-private:
- explicit TaskbarButton(const WindowIdentifier&);
-
- virtual void context_menu_event(GUI::ContextMenuEvent&) override;
- virtual void resize_event(GUI::ResizeEvent&) override;
- virtual void paint_event(GUI::PaintEvent&) override;
-
- WindowIdentifier m_identifier;
-};
diff --git a/Services/Taskbar/TaskbarWindow.cpp b/Services/Taskbar/TaskbarWindow.cpp
deleted file mode 100644
index fbc7946634..0000000000
--- a/Services/Taskbar/TaskbarWindow.cpp
+++ /dev/null
@@ -1,314 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "TaskbarWindow.h"
-#include "TaskbarButton.h"
-#include <AK/SharedBuffer.h>
-#include <LibCore/ConfigFile.h>
-#include <LibCore/StandardPaths.h>
-#include <LibDesktop/AppFile.h>
-#include <LibGUI/BoxLayout.h>
-#include <LibGUI/Button.h>
-#include <LibGUI/Desktop.h>
-#include <LibGUI/Frame.h>
-#include <LibGUI/Icon.h>
-#include <LibGUI/Painter.h>
-#include <LibGUI/Window.h>
-#include <LibGUI/WindowServerConnection.h>
-#include <LibGfx/Palette.h>
-#include <serenity.h>
-#include <stdio.h>
-
-//#define EVENT_DEBUG
-
-class TaskbarWidget final : public GUI::Widget {
- C_OBJECT(TaskbarWidget);
-
-public:
- virtual ~TaskbarWidget() override { }
-
-private:
- TaskbarWidget() { }
-
- virtual void paint_event(GUI::PaintEvent& event) override
- {
- GUI::Painter painter(*this);
- painter.add_clip_rect(event.rect());
- painter.fill_rect(rect(), palette().button());
- painter.draw_line({ 0, 1 }, { width() - 1, 1 }, palette().threed_highlight());
- }
-
- virtual void did_layout() override
- {
- WindowList::the().for_each_window([&](auto& window) {
- if (auto* button = window.button())
- static_cast<TaskbarButton*>(button)->update_taskbar_rect();
- });
- }
-};
-
-TaskbarWindow::TaskbarWindow()
-{
- set_window_type(GUI::WindowType::Taskbar);
- set_title("Taskbar");
-
- on_screen_rect_change(GUI::Desktop::the().rect());
-
- GUI::Desktop::the().on_rect_change = [this](const Gfx::IntRect& rect) { on_screen_rect_change(rect); };
-
- auto& widget = set_main_widget<TaskbarWidget>();
- widget.set_layout<GUI::HorizontalBoxLayout>();
- widget.layout()->set_margins({ 3, 2, 3, 2 });
- widget.layout()->set_spacing(3);
-
- m_default_icon = Gfx::Bitmap::load_from_file("/res/icons/16x16/window.png");
-
- create_quick_launch_bar();
-}
-
-TaskbarWindow::~TaskbarWindow()
-{
-}
-
-void TaskbarWindow::create_quick_launch_bar()
-{
- auto& quick_launch_bar = main_widget()->add<GUI::Frame>();
- quick_launch_bar.set_layout<GUI::HorizontalBoxLayout>();
- quick_launch_bar.layout()->set_spacing(0);
- quick_launch_bar.layout()->set_margins({ 3, 0, 3, 0 });
- quick_launch_bar.set_frame_thickness(0);
-
- int total_width = 6;
- bool first = true;
-
- auto config = Core::ConfigFile::get_for_app("Taskbar");
- constexpr const char* quick_launch = "QuickLaunch";
-
- // FIXME: Core::ConfigFile does not keep the order of the entries.
- for (auto& name : config->keys(quick_launch)) {
- auto af_name = config->read_entry(quick_launch, name);
- auto af_path = String::formatted("{}/{}", Desktop::AppFile::APP_FILES_DIRECTORY, af_name);
- auto af = Desktop::AppFile::open(af_path);
- if (!af->is_valid())
- continue;
- auto app_executable = af->executable();
- const int button_size = 24;
- auto& button = quick_launch_bar.add<GUI::Button>();
- button.set_fixed_size(button_size, button_size);
- button.set_button_style(Gfx::ButtonStyle::CoolBar);
- button.set_icon(af->icon().bitmap_for_size(16));
- button.set_tooltip(af->name());
- button.on_click = [app_executable](auto) {
- pid_t pid = fork();
- if (pid < 0) {
- perror("fork");
- } else if (pid == 0) {
- if (chdir(Core::StandardPaths::home_directory().characters()) < 0) {
- perror("chdir");
- exit(1);
- }
- execl(app_executable.characters(), app_executable.characters(), nullptr);
- perror("execl");
- ASSERT_NOT_REACHED();
- } else {
- if (disown(pid) < 0)
- perror("disown");
- }
- };
-
- if (!first)
- total_width += quick_launch_bar.layout()->spacing();
- first = false;
- total_width += button_size;
- }
-
- quick_launch_bar.set_fixed_size(total_width, 24);
-}
-
-void TaskbarWindow::on_screen_rect_change(const Gfx::IntRect& rect)
-{
- Gfx::IntRect new_rect { rect.x(), rect.bottom() - taskbar_height() + 1, rect.width(), taskbar_height() };
- set_rect(new_rect);
-}
-
-NonnullRefPtr<GUI::Button> TaskbarWindow::create_button(const WindowIdentifier& identifier)
-{
- auto& button = main_widget()->add<TaskbarButton>(identifier);
- button.set_min_size(20, 23);
- button.set_max_size(140, 23);
- button.set_text_alignment(Gfx::TextAlignment::CenterLeft);
- button.set_icon(*m_default_icon);
- return button;
-}
-
-static bool should_include_window(GUI::WindowType window_type, bool is_frameless)
-{
- return window_type == GUI::WindowType::Normal && !is_frameless;
-}
-
-void TaskbarWindow::add_window_button(::Window& window, const WindowIdentifier& identifier)
-{
- if (window.button())
- return;
- window.set_button(create_button(identifier));
- auto* button = window.button();
- button->on_click = [window = &window, identifier, button](auto) {
- // We need to look at the button's checked state here to figure
- // out if the application is active or not. That's because this
- // button's window may not actually be active when a modal window
- // is displayed, in which case window->is_active() would return
- // false because window is the modal window's owner (which is not
- // active)
- if (window->is_minimized() || !button->is_checked()) {
- GUI::WindowServerConnection::the().post_message(Messages::WindowServer::WM_SetActiveWindow(identifier.client_id(), identifier.window_id()));
- } else {
- GUI::WindowServerConnection::the().post_message(Messages::WindowServer::WM_SetWindowMinimized(identifier.client_id(), identifier.window_id(), true));
- }
- };
-}
-
-void TaskbarWindow::remove_window_button(::Window& window, bool was_removed)
-{
- auto* button = window.button();
- if (!button)
- return;
- if (!was_removed)
- static_cast<TaskbarButton*>(button)->clear_taskbar_rect();
- window.set_button(nullptr);
- button->remove_from_parent();
-}
-
-void TaskbarWindow::update_window_button(::Window& window, bool show_as_active)
-{
- auto* button = window.button();
- if (!button)
- return;
- button->set_text(window.title());
- button->set_checked(show_as_active);
-}
-
-::Window* TaskbarWindow::find_window_owner(::Window& window) const
-{
- if (!window.is_modal())
- return &window;
-
- ::Window* parent = nullptr;
- auto* current_window = &window;
- while (current_window) {
- parent = WindowList::the().find_parent(*current_window);
- if (!parent || !parent->is_modal())
- break;
- current_window = parent;
- }
- return parent;
-}
-
-void TaskbarWindow::wm_event(GUI::WMEvent& event)
-{
- WindowIdentifier identifier { event.client_id(), event.window_id() };
- switch (event.type()) {
- case GUI::Event::WM_WindowRemoved: {
-#ifdef EVENT_DEBUG
- auto& removed_event = static_cast<GUI::WMWindowRemovedEvent&>(event);
- dbgln("WM_WindowRemoved: client_id={}, window_id={}",
- removed_event.client_id(),
- removed_event.window_id());
-#endif
- if (auto* window = WindowList::the().window(identifier))
- remove_window_button(*window, true);
- WindowList::the().remove_window(identifier);
- update();
- break;
- }
- case GUI::Event::WM_WindowRectChanged: {
-#ifdef EVENT_DEBUG
- auto& changed_event = static_cast<GUI::WMWindowRectChangedEvent&>(event);
- dbgln("WM_WindowRectChanged: client_id={}, window_id={}, rect={}",
- changed_event.client_id(),
- changed_event.window_id(),
- changed_event.rect());
-#endif
- break;
- }
-
- case GUI::Event::WM_WindowIconBitmapChanged: {
- auto& changed_event = static_cast<GUI::WMWindowIconBitmapChangedEvent&>(event);
-#ifdef EVENT_DEBUG
- dbgln("WM_WindowIconBitmapChanged: client_id={}, window_id={}, icon_buffer_id={}",
- changed_event.client_id(),
- changed_event.window_id(),
- changed_event.icon_buffer_id());
-#endif
- if (auto* window = WindowList::the().window(identifier)) {
- auto buffer = SharedBuffer::create_from_shbuf_id(changed_event.icon_buffer_id());
- ASSERT(buffer);
- if (window->button())
- window->button()->set_icon(Gfx::Bitmap::create_with_shared_buffer(Gfx::BitmapFormat::RGBA32, *buffer, changed_event.icon_size()));
- }
- break;
- }
-
- case GUI::Event::WM_WindowStateChanged: {
- auto& changed_event = static_cast<GUI::WMWindowStateChangedEvent&>(event);
-#ifdef EVENT_DEBUG
- dbgln("WM_WindowStateChanged: client_id={}, window_id={}, title={}, rect={}, is_active={}, is_minimized={}",
- changed_event.client_id(),
- changed_event.window_id(),
- changed_event.title(),
- changed_event.rect(),
- changed_event.is_active(),
- changed_event.is_minimized());
-#endif
- if (!should_include_window(changed_event.window_type(), changed_event.is_frameless()))
- break;
- auto& window = WindowList::the().ensure_window(identifier);
- window.set_parent_identifier({ changed_event.parent_client_id(), changed_event.parent_window_id() });
- if (!window.is_modal())
- add_window_button(window, identifier);
- else
- remove_window_button(window, false);
- window.set_title(changed_event.title());
- window.set_rect(changed_event.rect());
- window.set_modal(changed_event.is_modal());
- window.set_active(changed_event.is_active());
- window.set_minimized(changed_event.is_minimized());
- window.set_progress(changed_event.progress());
-
- auto* window_owner = find_window_owner(window);
- if (window_owner == &window) {
- update_window_button(window, window.is_active());
- } else if (window_owner) {
- // check the window owner's button if the modal's window button
- // would have been checked
- ASSERT(window.is_modal());
- update_window_button(*window_owner, window.is_active());
- }
- break;
- }
- default:
- break;
- }
-}
diff --git a/Services/Taskbar/TaskbarWindow.h b/Services/Taskbar/TaskbarWindow.h
deleted file mode 100644
index be55a00daf..0000000000
--- a/Services/Taskbar/TaskbarWindow.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include "WindowList.h"
-#include <LibGUI/Widget.h>
-#include <LibGUI/Window.h>
-
-class TaskbarWindow final : public GUI::Window {
- C_OBJECT(TaskbarWindow)
-public:
- TaskbarWindow();
- virtual ~TaskbarWindow() override;
-
- int taskbar_height() const { return 28; }
-
-private:
- void create_quick_launch_bar();
- void on_screen_rect_change(const Gfx::IntRect&);
- NonnullRefPtr<GUI::Button> create_button(const WindowIdentifier&);
- void add_window_button(::Window&, const WindowIdentifier&);
- void remove_window_button(::Window&, bool);
- void update_window_button(::Window&, bool);
- ::Window* find_window_owner(::Window&) const;
-
- virtual void wm_event(GUI::WMEvent&) override;
-
- RefPtr<Gfx::Bitmap> m_default_icon;
-};
diff --git a/Services/Taskbar/WindowIdentifier.h b/Services/Taskbar/WindowIdentifier.h
deleted file mode 100644
index c6e996992c..0000000000
--- a/Services/Taskbar/WindowIdentifier.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <AK/Traits.h>
-
-class WindowIdentifier {
-public:
- WindowIdentifier() = default;
- WindowIdentifier(int client_id, int window_id)
- : m_client_id(client_id)
- , m_window_id(window_id)
- {
- }
-
- int client_id() const { return m_client_id; }
- int window_id() const { return m_window_id; }
-
- bool operator==(const WindowIdentifier& other) const
- {
- return m_client_id == other.m_client_id && m_window_id == other.m_window_id;
- }
-
- bool is_valid() const
- {
- return m_client_id != -1 && m_window_id != -1;
- }
-
-private:
- int m_client_id { -1 };
- int m_window_id { -1 };
-};
-
-namespace AK {
-template<>
-struct Traits<WindowIdentifier> : public GenericTraits<WindowIdentifier> {
- static unsigned hash(const WindowIdentifier& w) { return pair_int_hash(w.client_id(), w.window_id()); }
-};
-}
diff --git a/Services/Taskbar/WindowList.cpp b/Services/Taskbar/WindowList.cpp
deleted file mode 100644
index 84021be160..0000000000
--- a/Services/Taskbar/WindowList.cpp
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "WindowList.h"
-
-WindowList& WindowList::the()
-{
- static WindowList* s_the;
- if (!s_the)
- s_the = new WindowList;
- return *s_the;
-}
-
-Window* WindowList::find_parent(const Window& window)
-{
- if (!window.parent_identifier().is_valid())
- return nullptr;
- for (auto& it : m_windows) {
- auto& w = *it.value;
- if (w.identifier() == window.parent_identifier())
- return &w;
- }
- return nullptr;
-}
-
-Window* WindowList::window(const WindowIdentifier& identifier)
-{
- auto it = m_windows.find(identifier);
- if (it != m_windows.end())
- return it->value;
- return nullptr;
-}
-
-Window& WindowList::ensure_window(const WindowIdentifier& identifier)
-{
- auto it = m_windows.find(identifier);
- if (it != m_windows.end())
- return *it->value;
- auto window = make<Window>(identifier);
- auto& window_ref = *window;
- m_windows.set(identifier, move(window));
- return window_ref;
-}
-
-void WindowList::remove_window(const WindowIdentifier& identifier)
-{
- m_windows.remove(identifier);
-}
diff --git a/Services/Taskbar/WindowList.h b/Services/Taskbar/WindowList.h
deleted file mode 100644
index b86b509926..0000000000
--- a/Services/Taskbar/WindowList.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include "WindowIdentifier.h"
-#include <AK/HashMap.h>
-#include <AK/String.h>
-#include <LibGUI/Button.h>
-#include <LibGfx/Rect.h>
-
-class Window {
-public:
- explicit Window(const WindowIdentifier& identifier)
- : m_identifier(identifier)
- {
- }
-
- ~Window()
- {
- if (m_button)
- m_button->remove_from_parent();
- }
-
- const WindowIdentifier& identifier() const { return m_identifier; }
-
- void set_parent_identifier(const WindowIdentifier& parent_identifier) { m_parent_identifier = parent_identifier; }
- const WindowIdentifier& parent_identifier() const { return m_parent_identifier; }
-
- String title() const { return m_title; }
- void set_title(const String& title) { m_title = title; }
-
- Gfx::IntRect rect() const { return m_rect; }
- void set_rect(const Gfx::IntRect& rect) { m_rect = rect; }
-
- GUI::Button* button() { return m_button; }
- void set_button(GUI::Button* button) { m_button = button; }
-
- void set_active(bool active) { m_active = active; }
- bool is_active() const { return m_active; }
-
- void set_minimized(bool minimized) { m_minimized = minimized; }
- bool is_minimized() const { return m_minimized; }
-
- void set_modal(bool modal) { m_modal = modal; }
- bool is_modal() const { return m_modal; }
-
- void set_progress(int progress)
- {
- if (m_progress == progress)
- return;
- m_progress = progress;
- if (m_button)
- m_button->update();
- }
-
- int progress() const { return m_progress; }
-
- const Gfx::Bitmap* icon() const { return m_icon.ptr(); }
-
-private:
- WindowIdentifier m_identifier;
- WindowIdentifier m_parent_identifier;
- String m_title;
- Gfx::IntRect m_rect;
- RefPtr<GUI::Button> m_button;
- RefPtr<Gfx::Bitmap> m_icon;
- bool m_active { false };
- bool m_minimized { false };
- bool m_modal { false };
- int m_progress { -1 };
-};
-
-class WindowList {
-public:
- static WindowList& the();
-
- template<typename Callback>
- void for_each_window(Callback callback)
- {
- for (auto& it : m_windows)
- callback(*it.value);
- }
-
- Window* find_parent(const Window&);
- Window* window(const WindowIdentifier&);
- Window& ensure_window(const WindowIdentifier&);
- void remove_window(const WindowIdentifier&);
-
-private:
- HashMap<WindowIdentifier, NonnullOwnPtr<Window>> m_windows;
-};
diff --git a/Services/Taskbar/main.cpp b/Services/Taskbar/main.cpp
deleted file mode 100644
index 3917285497..0000000000
--- a/Services/Taskbar/main.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "TaskbarWindow.h"
-#include <LibCore/EventLoop.h>
-#include <LibGUI/Application.h>
-#include <signal.h>
-#include <stdio.h>
-#include <sys/wait.h>
-
-int main(int argc, char** argv)
-{
- if (pledge("stdio shared_buffer accept proc exec rpath unix cpath fattr sigaction", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- auto app = GUI::Application::construct(argc, argv);
- app->event_loop().register_signal(SIGCHLD, [](int) {
- // Wait all available children
- while (waitpid(-1, nullptr, WNOHANG) > 0)
- ;
- });
-
- if (pledge("stdio shared_buffer accept proc exec rpath", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- TaskbarWindow window;
- window.show();
-
- return app->exec();
-}
diff --git a/Services/TelnetServer/CMakeLists.txt b/Services/TelnetServer/CMakeLists.txt
deleted file mode 100644
index e19ae8bac6..0000000000
--- a/Services/TelnetServer/CMakeLists.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-set(SOURCES
- Client.cpp
- main.cpp
- Parser.cpp
-)
-
-serenity_bin(TelnetServer)
-target_link_libraries(TelnetServer LibCore)
diff --git a/Services/TelnetServer/Client.cpp b/Services/TelnetServer/Client.cpp
deleted file mode 100644
index 5e1accf9d1..0000000000
--- a/Services/TelnetServer/Client.cpp
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "Client.h"
-#include <AK/ByteBuffer.h>
-#include <AK/MemoryStream.h>
-#include <AK/String.h>
-#include <AK/StringBuilder.h>
-#include <AK/StringView.h>
-#include <AK/Types.h>
-#include <LibCore/Notifier.h>
-#include <LibCore/TCPSocket.h>
-#include <stdio.h>
-#include <unistd.h>
-
-Client::Client(int id, RefPtr<Core::TCPSocket> socket, int ptm_fd)
- : m_id(id)
- , m_socket(move(socket))
- , m_ptm_fd(ptm_fd)
- , m_ptm_notifier(Core::Notifier::construct(ptm_fd, Core::Notifier::Read))
-{
- m_socket->on_ready_to_read = [this] { drain_socket(); };
- m_ptm_notifier->on_ready_to_read = [this] { drain_pty(); };
- m_parser.on_command = [this](const Command& command) { handle_command(command); };
- m_parser.on_data = [this](const StringView& data) { handle_data(data); };
- m_parser.on_error = [this]() { handle_error(); };
- send_commands({
- { CMD_WILL, SUB_SUPPRESS_GO_AHEAD },
- { CMD_WILL, SUB_ECHO },
- { CMD_DO, SUB_SUPPRESS_GO_AHEAD },
- { CMD_DONT, SUB_ECHO },
- });
-}
-
-void Client::drain_socket()
-{
- NonnullRefPtr<Client> protect(*this);
- while (m_socket->can_read()) {
- auto buf = m_socket->read(1024);
-
- m_parser.write(buf);
-
- if (m_socket->eof()) {
- quit();
- break;
- }
- }
-}
-
-void Client::drain_pty()
-{
- u8 buffer[BUFSIZ];
- ssize_t nread = read(m_ptm_fd, buffer, sizeof(buffer));
- if (nread < 0) {
- perror("read(ptm)");
- quit();
- return;
- }
- if (nread == 0) {
- quit();
- return;
- }
- send_data(StringView(buffer, (size_t)nread));
-}
-
-void Client::handle_data(const StringView& data)
-{
- write(m_ptm_fd, data.characters_without_null_termination(), data.length());
-}
-
-void Client::handle_command(const Command& command)
-{
- switch (command.command) {
- case CMD_DO:
- // no response - we've already advertised our options, and none of
- // them can be disabled (or re-enabled) after connecting.
- break;
- case CMD_DONT:
- // no response - we only "support" two options (echo and suppress
- // go-ahead), and both of them are always enabled.
- break;
- case CMD_WILL:
- switch (command.subcommand) {
- case SUB_ECHO:
- // we always want to be the ones in control of the output. tell
- // the client to disable local echo.
- send_command({ CMD_DONT, SUB_ECHO });
- break;
- case SUB_SUPPRESS_GO_AHEAD:
- send_command({ CMD_DO, SUB_SUPPRESS_GO_AHEAD });
- break;
- default:
- // don't respond to unknown commands
- break;
- }
- break;
- case CMD_WONT:
- // no response - we don't care about anything the client says they
- // won't do.
- break;
- }
-}
-
-void Client::handle_error()
-{
- quit();
-}
-
-void Client::send_data(StringView data)
-{
- bool fast = true;
- for (size_t i = 0; i < data.length(); i++) {
- u8 c = data[i];
- if (c == '\n' || c == 0xff)
- fast = false;
- }
-
- if (fast) {
- m_socket->write(data);
- return;
- }
-
- StringBuilder builder;
- for (size_t i = 0; i < data.length(); i++) {
- u8 c = data[i];
-
- switch (c) {
- case '\n':
- builder.append("\r\n");
- break;
- case IAC:
- builder.append("\xff\xff");
- break;
- default:
- builder.append(c);
- break;
- }
- }
-
- m_socket->write(builder.to_string());
-}
-
-void Client::send_command(Command command)
-{
- send_commands({ command });
-}
-
-void Client::send_commands(Vector<Command> commands)
-{
- auto buffer = ByteBuffer::create_uninitialized(commands.size() * 3);
- OutputMemoryStream stream { buffer };
-
- for (auto& command : commands)
- stream << (u8)IAC << command.command << command.subcommand;
-
- ASSERT(stream.is_end());
- m_socket->write(buffer.data(), buffer.size());
-}
-
-void Client::quit()
-{
- m_ptm_notifier->set_enabled(false);
- close(m_ptm_fd);
- m_socket->close();
- if (on_exit)
- on_exit();
-}
diff --git a/Services/TelnetServer/Client.h b/Services/TelnetServer/Client.h
deleted file mode 100644
index fe345d38e3..0000000000
--- a/Services/TelnetServer/Client.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <AK/String.h>
-#include <AK/StringView.h>
-#include <AK/Types.h>
-#include <LibCore/Notifier.h>
-#include <LibCore/TCPSocket.h>
-
-#include "Command.h"
-#include "Parser.h"
-
-class Client : public RefCounted<Client> {
-public:
- static NonnullRefPtr<Client> create(int id, RefPtr<Core::TCPSocket> socket, int ptm_fd)
- {
- return adopt(*new Client(id, move(socket), ptm_fd));
- }
-
- Function<void()> on_exit;
-
-protected:
- Client(int id, RefPtr<Core::TCPSocket> socket, int ptm_fd);
-
- void drain_socket();
- void drain_pty();
- void handle_data(const StringView&);
- void handle_command(const Command& command);
- void handle_error();
- void send_data(StringView str);
- void send_command(Command command);
- void send_commands(Vector<Command> commands);
- void quit();
-
-private:
- // client id
- int m_id { 0 };
- // client resources
- RefPtr<Core::TCPSocket> m_socket;
- Parser m_parser;
- // pty resources
- int m_ptm_fd { -1 };
- RefPtr<Core::Notifier> m_ptm_notifier;
-};
diff --git a/Services/TelnetServer/Command.h b/Services/TelnetServer/Command.h
deleted file mode 100644
index 25afb1fe22..0000000000
--- a/Services/TelnetServer/Command.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <AK/String.h>
-#include <AK/StringBuilder.h>
-#include <AK/Types.h>
-
-#define CMD_WILL 0xfb
-#define CMD_WONT 0xfc
-#define CMD_DO 0xfd
-#define CMD_DONT 0xfe
-#define SUB_ECHO 0x01
-#define SUB_SUPPRESS_GO_AHEAD 0x03
-
-struct Command {
- u8 command;
- u8 subcommand;
-
- String to_string() const
- {
- StringBuilder builder;
-
- switch (command) {
- case CMD_WILL:
- builder.append("WILL");
- break;
- case CMD_WONT:
- builder.append("WONT");
- break;
- case CMD_DO:
- builder.append("DO");
- break;
- case CMD_DONT:
- builder.append("DONT");
- break;
- default:
- builder.append(String::format("UNKNOWN<%02x>", command));
- break;
- }
-
- builder.append(" ");
-
- switch (subcommand) {
- case SUB_ECHO:
- builder.append("ECHO");
- break;
- case SUB_SUPPRESS_GO_AHEAD:
- builder.append("SUPPRESS_GO_AHEAD");
- break;
- default:
- builder.append(String::format("UNKNOWN<%02x>", subcommand));
- break;
- }
-
- return builder.to_string();
- };
-};
diff --git a/Services/TelnetServer/Parser.cpp b/Services/TelnetServer/Parser.cpp
deleted file mode 100644
index 9fc1aabcd1..0000000000
--- a/Services/TelnetServer/Parser.cpp
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <AK/Function.h>
-#include <AK/String.h>
-#include <AK/Types.h>
-
-#include "Parser.h"
-
-void Parser::write(const StringView& data)
-{
- for (size_t i = 0; i < data.length(); i++) {
- u8 ch = data[i];
-
- switch (m_state) {
- case State::Free:
- switch (ch) {
- case IAC:
- m_state = State::ReadCommand;
- break;
- case '\r':
- if (on_data)
- on_data("\n");
- break;
- default:
- if (on_data)
- on_data(StringView(&ch, 1));
- break;
- }
- break;
- case State::ReadCommand:
- switch (ch) {
- case IAC: {
- m_state = State::Free;
- if (on_data)
- on_data("\xff");
- break;
- }
- case CMD_WILL:
- case CMD_WONT:
- case CMD_DO:
- case CMD_DONT:
- m_command = ch;
- m_state = State::ReadSubcommand;
- break;
- default:
- m_state = State::Error;
- if (on_error)
- on_error();
- break;
- }
- break;
- case State::ReadSubcommand: {
- auto command = m_command;
- m_command = 0;
- m_state = State::Free;
- if (on_command)
- on_command({ command, ch });
- break;
- }
- case State::Error:
- // ignore everything
- break;
- }
- }
-}
diff --git a/Services/TelnetServer/Parser.h b/Services/TelnetServer/Parser.h
deleted file mode 100644
index 64688881df..0000000000
--- a/Services/TelnetServer/Parser.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <AK/Function.h>
-#include <AK/String.h>
-#include <AK/StringView.h>
-#include <AK/Types.h>
-
-#include "Command.h"
-
-#define IAC 0xff
-
-class Parser {
-public:
- Function<void(const Command&)> on_command;
- Function<void(const StringView&)> on_data;
- Function<void()> on_error;
-
- void write(const StringView&);
-
-protected:
- enum State {
- Free,
- ReadCommand,
- ReadSubcommand,
- Error,
- };
-
- void write(const String& str);
-
-private:
- State m_state { State::Free };
- u8 m_command { 0 };
-};
diff --git a/Services/TelnetServer/main.cpp b/Services/TelnetServer/main.cpp
deleted file mode 100644
index dc5ddf1a04..0000000000
--- a/Services/TelnetServer/main.cpp
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "Client.h"
-#include <AK/ByteBuffer.h>
-#include <AK/HashMap.h>
-#include <AK/IPv4Address.h>
-#include <AK/String.h>
-#include <AK/StringBuilder.h>
-#include <AK/Types.h>
-#include <LibCore/ArgsParser.h>
-#include <LibCore/EventLoop.h>
-#include <LibCore/TCPServer.h>
-#include <LibCore/TCPSocket.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/ioctl.h>
-
-static void run_command(int ptm_fd, String command)
-{
- pid_t pid = fork();
- if (pid == 0) {
- const char* tty_name = ptsname(ptm_fd);
- if (!tty_name) {
- perror("ptsname");
- exit(1);
- }
- close(ptm_fd);
- int pts_fd = open(tty_name, O_RDWR);
- if (pts_fd < 0) {
- perror("open");
- exit(1);
- }
-
- // NOTE: It's okay if this fails.
- [[maybe_unused]] auto rc = ioctl(0, TIOCNOTTY);
-
- close(0);
- close(1);
- close(2);
-
- rc = dup2(pts_fd, 0);
- if (rc < 0) {
- perror("dup2");
- exit(1);
- }
- rc = dup2(pts_fd, 1);
- if (rc < 0) {
- perror("dup2");
- exit(1);
- }
- rc = dup2(pts_fd, 2);
- if (rc < 0) {
- perror("dup2");
- exit(1);
- }
- rc = close(pts_fd);
- if (rc < 0) {
- perror("close");
- exit(1);
- }
- rc = ioctl(0, TIOCSCTTY);
- if (rc < 0) {
- perror("ioctl(TIOCSCTTY)");
- exit(1);
- }
- const char* args[4] = { "/bin/Shell", nullptr, nullptr, nullptr };
- if (!command.is_empty()) {
- args[1] = "-c";
- args[2] = command.characters();
- }
- const char* envs[] = { "TERM=xterm", "PATH=/bin:/usr/bin:/usr/local/bin", nullptr };
- rc = execve("/bin/Shell", const_cast<char**>(args), const_cast<char**>(envs));
- if (rc < 0) {
- perror("execve");
- exit(1);
- }
- ASSERT_NOT_REACHED();
- }
-}
-
-int main(int argc, char** argv)
-{
- int port = 23;
- const char* command = "";
-
- Core::ArgsParser args_parser;
- args_parser.add_option(port, "Port to listen on", nullptr, 'p', "port");
- args_parser.add_option(command, "Program to run on connection", nullptr, 'c', "command");
- args_parser.parse(argc, argv);
-
- if ((u16)port != port) {
- warnln("Invalid port number: {}", port);
- exit(1);
- }
-
- Core::EventLoop event_loop;
- auto server = Core::TCPServer::construct();
-
- if (!server->listen({}, port)) {
- warnln("Listening on 0.0.0.0:{} failed", port);
- exit(1);
- }
-
- HashMap<int, NonnullRefPtr<Client>> clients;
- int next_id = 0;
-
- server->on_ready_to_accept = [&next_id, &clients, &server, command] {
- int id = next_id++;
-
- auto client_socket = server->accept();
- if (!client_socket) {
- perror("accept");
- return;
- }
-
- int ptm_fd = posix_openpt(O_RDWR);
- if (ptm_fd < 0) {
- perror("posix_openpt");
- client_socket->close();
- return;
- }
- if (grantpt(ptm_fd) < 0) {
- perror("grantpt");
- client_socket->close();
- return;
- }
- if (unlockpt(ptm_fd) < 0) {
- perror("unlockpt");
- client_socket->close();
- return;
- }
-
- run_command(ptm_fd, command);
-
- auto client = Client::create(id, move(client_socket), ptm_fd);
- client->on_exit = [&clients, id] { clients.remove(id); };
- clients.set(id, client);
- };
-
- int rc = event_loop.exec();
- if (rc != 0) {
- fprintf(stderr, "event loop exited badly; rc=%d", rc);
- exit(1);
- }
-
- return 0;
-}
diff --git a/Services/WebContent/CMakeLists.txt b/Services/WebContent/CMakeLists.txt
deleted file mode 100644
index a7e367ff94..0000000000
--- a/Services/WebContent/CMakeLists.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-compile_ipc(WebContentServer.ipc WebContentServerEndpoint.h)
-compile_ipc(WebContentClient.ipc WebContentClientEndpoint.h)
-
-set(SOURCES
- ClientConnection.cpp
- main.cpp
- PageHost.cpp
- WebContentServerEndpoint.h
- WebContentClientEndpoint.h
-)
-
-serenity_bin(WebContent)
-target_link_libraries(WebContent LibCore LibIPC LibGfx LibWeb)
diff --git a/Services/WebContent/ClientConnection.cpp b/Services/WebContent/ClientConnection.cpp
deleted file mode 100644
index 46b38f440b..0000000000
--- a/Services/WebContent/ClientConnection.cpp
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <AK/Badge.h>
-#include <AK/SharedBuffer.h>
-#include <LibGfx/Bitmap.h>
-#include <LibGfx/SystemTheme.h>
-#include <WebContent/ClientConnection.h>
-#include <WebContent/PageHost.h>
-#include <WebContent/WebContentClientEndpoint.h>
-
-namespace WebContent {
-
-static HashMap<int, RefPtr<ClientConnection>> s_connections;
-
-ClientConnection::ClientConnection(NonnullRefPtr<Core::LocalSocket> socket, int client_id)
- : IPC::ClientConnection<WebContentClientEndpoint, WebContentServerEndpoint>(*this, move(socket), client_id)
- , m_page_host(PageHost::create(*this))
-{
- s_connections.set(client_id, *this);
- m_paint_flush_timer = Core::Timer::create_single_shot(0, [this] { flush_pending_paint_requests(); });
-}
-
-ClientConnection::~ClientConnection()
-{
-}
-
-void ClientConnection::die()
-{
- s_connections.remove(client_id());
- if (s_connections.is_empty())
- Core::EventLoop::current().quit(0);
-}
-
-Web::Page& ClientConnection::page()
-{
- return m_page_host->page();
-}
-
-const Web::Page& ClientConnection::page() const
-{
- return m_page_host->page();
-}
-
-OwnPtr<Messages::WebContentServer::GreetResponse> ClientConnection::handle(const Messages::WebContentServer::Greet& message)
-{
- set_client_pid(message.client_pid());
- return make<Messages::WebContentServer::GreetResponse>(client_id(), getpid());
-}
-
-void ClientConnection::handle(const Messages::WebContentServer::UpdateSystemTheme& message)
-{
- auto shared_buffer = SharedBuffer::create_from_shbuf_id(message.shbuf_id());
- if (!shared_buffer) {
- dbgln("WebContentServer::UpdateSystemTheme: SharedBuffer already gone! Ignoring :^)");
- return;
- }
- Gfx::set_system_theme(*shared_buffer);
- auto impl = Gfx::PaletteImpl::create_with_shared_buffer(*shared_buffer);
- m_page_host->set_palette_impl(*impl);
-}
-
-void ClientConnection::handle(const Messages::WebContentServer::LoadURL& message)
-{
-#ifdef DEBUG_SPAM
- dbg() << "handle: WebContentServer::LoadURL: url=" << message.url();
-#endif
- page().load(message.url());
-}
-
-void ClientConnection::handle(const Messages::WebContentServer::LoadHTML& message)
-{
-#ifdef DEBUG_SPAM
- dbg() << "handle: WebContentServer::LoadHTML: html=" << message.html() << ", url=" << message.url();
-#endif
- page().load_html(message.html(), message.url());
-}
-
-void ClientConnection::handle(const Messages::WebContentServer::SetViewportRect& message)
-{
-#ifdef DEBUG_SPAM
- dbg() << "handle: WebContentServer::SetViewportRect: rect=" << message.rect();
-#endif
- m_page_host->set_viewport_rect(message.rect());
-}
-
-void ClientConnection::handle(const Messages::WebContentServer::Paint& message)
-{
-#ifdef DEBUG_SPAM
- dbg() << "handle: WebContentServer::Paint: content_rect=" << message.content_rect() << ", shbuf_id=" << message.shbuf_id();
-#endif
-
- for (auto& pending_paint : m_pending_paint_requests) {
- if (pending_paint.bitmap->shbuf_id() == message.shbuf_id()) {
- pending_paint.content_rect = message.content_rect();
- return;
- }
- }
-
- auto shared_buffer = SharedBuffer::create_from_shbuf_id(message.shbuf_id());
- if (!shared_buffer) {
-#ifdef DEBUG_SPAM
- dbgln("WebContentServer::Paint: SharedBuffer already gone! Ignoring :^)");
-#endif
- return;
- }
- auto shared_bitmap = Gfx::Bitmap::create_with_shared_buffer(Gfx::BitmapFormat::RGB32, shared_buffer.release_nonnull(), message.content_rect().size());
- if (!shared_bitmap) {
- did_misbehave("WebContentServer::Paint: Cannot create Gfx::Bitmap wrapper around SharedBuffer");
- return;
- }
-
- m_pending_paint_requests.append({ message.content_rect(), shared_bitmap.release_nonnull() });
- m_paint_flush_timer->start();
-}
-
-void ClientConnection::flush_pending_paint_requests()
-{
- for (auto& pending_paint : m_pending_paint_requests) {
- m_page_host->paint(pending_paint.content_rect, *pending_paint.bitmap);
- post_message(Messages::WebContentClient::DidPaint(pending_paint.content_rect, pending_paint.bitmap->shbuf_id()));
- }
- m_pending_paint_requests.clear();
-}
-
-void ClientConnection::handle(const Messages::WebContentServer::MouseDown& message)
-{
- page().handle_mousedown(message.position(), message.button(), message.modifiers());
-}
-
-void ClientConnection::handle(const Messages::WebContentServer::MouseMove& message)
-{
- page().handle_mousemove(message.position(), message.buttons(), message.modifiers());
-}
-
-void ClientConnection::handle(const Messages::WebContentServer::MouseUp& message)
-{
- page().handle_mouseup(message.position(), message.button(), message.modifiers());
-}
-
-void ClientConnection::handle(const Messages::WebContentServer::KeyDown& message)
-{
- page().handle_keydown((KeyCode)message.key(), message.modifiers(), message.code_point());
-}
-
-}
diff --git a/Services/WebContent/ClientConnection.h b/Services/WebContent/ClientConnection.h
deleted file mode 100644
index 42e2ab8313..0000000000
--- a/Services/WebContent/ClientConnection.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <AK/HashMap.h>
-#include <LibIPC/ClientConnection.h>
-#include <LibWeb/Forward.h>
-#include <WebContent/Forward.h>
-#include <WebContent/WebContentClientEndpoint.h>
-#include <WebContent/WebContentServerEndpoint.h>
-
-namespace WebContent {
-
-class ClientConnection final
- : public IPC::ClientConnection<WebContentClientEndpoint, WebContentServerEndpoint>
- , public WebContentServerEndpoint {
- C_OBJECT(ClientConnection);
-
-public:
- explicit ClientConnection(NonnullRefPtr<Core::LocalSocket>, int client_id);
- ~ClientConnection() override;
-
- virtual void die() override;
-
-private:
- Web::Page& page();
- const Web::Page& page() const;
-
- virtual OwnPtr<Messages::WebContentServer::GreetResponse> handle(const Messages::WebContentServer::Greet&) override;
- virtual void handle(const Messages::WebContentServer::UpdateSystemTheme&) override;
- virtual void handle(const Messages::WebContentServer::LoadURL&) override;
- virtual void handle(const Messages::WebContentServer::LoadHTML&) override;
- virtual void handle(const Messages::WebContentServer::Paint&) override;
- virtual void handle(const Messages::WebContentServer::SetViewportRect&) override;
- virtual void handle(const Messages::WebContentServer::MouseDown&) override;
- virtual void handle(const Messages::WebContentServer::MouseMove&) override;
- virtual void handle(const Messages::WebContentServer::MouseUp&) override;
- virtual void handle(const Messages::WebContentServer::KeyDown&) override;
-
- void flush_pending_paint_requests();
-
- NonnullOwnPtr<PageHost> m_page_host;
-
- struct PaintRequest {
- Gfx::IntRect content_rect;
- NonnullRefPtr<Gfx::Bitmap> bitmap;
- };
- Vector<PaintRequest> m_pending_paint_requests;
- RefPtr<Core::Timer> m_paint_flush_timer;
-};
-
-}
diff --git a/Services/WebContent/Documentation.txt b/Services/WebContent/Documentation.txt
deleted file mode 100644
index e82190106a..0000000000
--- a/Services/WebContent/Documentation.txt
+++ /dev/null
@@ -1,27 +0,0 @@
-=====================
-Multi-process model:
-=====================
-
-Server Client
-
-WebContent GUI process (OutOfProcessWebView embedder)
-
- OutOfProcessWebView (this is a GUI::Widget)
-WebContent::ClientConnection <---> WebContentClient
- WebContent::PageHost (Web::PageClient)
- Web::Page
- Web::Frame
- Web::Document
- ..
-
-
-=====================
-Single process model:
-=====================
-
-Web::InProcessWebView (this is a GUI::Widget, and also a Web::PageClient)
- Web::Page
- Web::Frame
- Web::Document
- ..
-
diff --git a/Services/WebContent/Forward.h b/Services/WebContent/Forward.h
deleted file mode 100644
index e43ca83960..0000000000
--- a/Services/WebContent/Forward.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-namespace WebContent {
-
-class ClientConnection;
-class PageHost;
-
-}
diff --git a/Services/WebContent/PageHost.cpp b/Services/WebContent/PageHost.cpp
deleted file mode 100644
index 11641235eb..0000000000
--- a/Services/WebContent/PageHost.cpp
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "PageHost.h"
-#include "ClientConnection.h"
-#include <AK/SharedBuffer.h>
-#include <LibGfx/Painter.h>
-#include <LibGfx/SystemTheme.h>
-#include <LibWeb/Layout/InitialContainingBlockBox.h>
-#include <LibWeb/Page/Frame.h>
-#include <WebContent/WebContentClientEndpoint.h>
-
-namespace WebContent {
-
-PageHost::PageHost(ClientConnection& client)
- : m_client(client)
- , m_page(make<Web::Page>(*this))
-{
- setup_palette();
-}
-
-PageHost::~PageHost()
-{
-}
-
-void PageHost::setup_palette()
-{
- // FIXME: Get the proper palette from our peer somehow
- auto buffer = SharedBuffer::create_with_size(sizeof(Gfx::SystemTheme));
- auto* theme = buffer->data<Gfx::SystemTheme>();
- theme->color[(int)Gfx::ColorRole::Window] = Color::Magenta;
- theme->color[(int)Gfx::ColorRole::WindowText] = Color::Cyan;
- m_palette_impl = Gfx::PaletteImpl::create_with_shared_buffer(*buffer);
-}
-
-Gfx::Palette PageHost::palette() const
-{
- return Gfx::Palette(*m_palette_impl);
-}
-
-void PageHost::set_palette_impl(const Gfx::PaletteImpl& impl)
-{
- m_palette_impl = impl;
-}
-
-Web::Layout::InitialContainingBlockBox* PageHost::layout_root()
-{
- auto* document = page().main_frame().document();
- if (!document)
- return nullptr;
- return document->layout_node();
-}
-
-void PageHost::paint(const Gfx::IntRect& content_rect, Gfx::Bitmap& target)
-{
- Gfx::Painter painter(target);
- Gfx::IntRect bitmap_rect { {}, content_rect.size() };
-
- auto* layout_root = this->layout_root();
- if (!layout_root) {
- painter.fill_rect(bitmap_rect, Color::White);
- return;
- }
-
- painter.fill_rect(bitmap_rect, layout_root->document().background_color(palette()));
-
- if (auto background_bitmap = layout_root->document().background_image()) {
- painter.draw_tiled_bitmap(bitmap_rect, *background_bitmap);
- }
-
- painter.translate(-content_rect.x(), -content_rect.y());
-
- Web::PaintContext context(painter, palette(), Gfx::IntPoint());
- context.set_viewport_rect(content_rect);
- layout_root->paint_all_phases(context);
-}
-
-void PageHost::set_viewport_rect(const Gfx::IntRect& rect)
-{
- page().main_frame().set_size(rect.size());
- if (page().main_frame().document())
- page().main_frame().document()->update_layout();
- page().main_frame().set_viewport_scroll_offset(rect.location());
-}
-
-void PageHost::page_did_invalidate(const Gfx::IntRect& content_rect)
-{
- m_client.post_message(Messages::WebContentClient::DidInvalidateContentRect(content_rect));
-}
-
-void PageHost::page_did_change_selection()
-{
- m_client.post_message(Messages::WebContentClient::DidChangeSelection());
-}
-
-void PageHost::page_did_layout()
-{
- auto* layout_root = this->layout_root();
- ASSERT(layout_root);
- auto content_size = enclosing_int_rect(layout_root->absolute_rect()).size();
- m_client.post_message(Messages::WebContentClient::DidLayout(content_size));
-}
-
-void PageHost::page_did_change_title(const String& title)
-{
- m_client.post_message(Messages::WebContentClient::DidChangeTitle(title));
-}
-
-void PageHost::page_did_request_scroll_into_view(const Gfx::IntRect& rect)
-{
- m_client.post_message(Messages::WebContentClient::DidRequestScrollIntoView(rect));
-}
-
-void PageHost::page_did_hover_link(const URL& url)
-{
- m_client.post_message(Messages::WebContentClient::DidHoverLink(url));
-}
-
-void PageHost::page_did_unhover_link()
-{
- m_client.post_message(Messages::WebContentClient::DidUnhoverLink());
-}
-
-void PageHost::page_did_click_link(const URL& url, const String& target, unsigned modifiers)
-{
- m_client.post_message(Messages::WebContentClient::DidClickLink(url, target, modifiers));
-}
-
-void PageHost::page_did_middle_click_link(const URL& url, [[maybe_unused]] const String& target, [[maybe_unused]] unsigned modifiers)
-{
- m_client.post_message(Messages::WebContentClient::DidMiddleClickLink(url, target, modifiers));
-}
-
-void PageHost::page_did_start_loading(const URL& url)
-{
- m_client.post_message(Messages::WebContentClient::DidStartLoading(url));
-}
-
-void PageHost::page_did_finish_loading(const URL& url)
-{
- m_client.post_message(Messages::WebContentClient::DidFinishLoading(url));
-}
-
-void PageHost::page_did_request_context_menu(const Gfx::IntPoint& content_position)
-{
- m_client.post_message(Messages::WebContentClient::DidRequestContextMenu(content_position));
-}
-
-void PageHost::page_did_request_link_context_menu(const Gfx::IntPoint& content_position, const URL& url, const String& target, unsigned modifiers)
-{
- m_client.post_message(Messages::WebContentClient::DidRequestLinkContextMenu(content_position, url, target, modifiers));
-}
-
-void PageHost::page_did_request_alert(const String& message)
-{
- m_client.send_sync<Messages::WebContentClient::DidRequestAlert>(message);
-}
-
-}
diff --git a/Services/WebContent/PageHost.h b/Services/WebContent/PageHost.h
deleted file mode 100644
index 0ee9e393d9..0000000000
--- a/Services/WebContent/PageHost.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <LibWeb/Page/Page.h>
-
-namespace WebContent {
-
-class ClientConnection;
-
-class PageHost final : public Web::PageClient {
- AK_MAKE_NONCOPYABLE(PageHost);
- AK_MAKE_NONMOVABLE(PageHost);
-
-public:
- static NonnullOwnPtr<PageHost> create(ClientConnection& client) { return adopt_own(*new PageHost(client)); }
- virtual ~PageHost();
-
- Web::Page& page() { return *m_page; }
- const Web::Page& page() const { return *m_page; }
-
- void paint(const Gfx::IntRect& content_rect, Gfx::Bitmap&);
-
- void set_palette_impl(const Gfx::PaletteImpl&);
- void set_viewport_rect(const Gfx::IntRect&);
-
-private:
- // ^PageClient
- virtual Gfx::Palette palette() const override;
- virtual void page_did_invalidate(const Gfx::IntRect&) override;
- virtual void page_did_change_selection() override;
- virtual void page_did_layout() override;
- virtual void page_did_change_title(const String&) override;
- virtual void page_did_request_scroll_into_view(const Gfx::IntRect&) override;
- virtual void page_did_hover_link(const URL&) override;
- virtual void page_did_unhover_link() override;
- virtual void page_did_click_link(const URL&, const String& target, unsigned modifiers) override;
- virtual void page_did_middle_click_link(const URL&, const String& target, unsigned modifiers) override;
- virtual void page_did_request_context_menu(const Gfx::IntPoint&) override;
- virtual void page_did_request_link_context_menu(const Gfx::IntPoint&, const URL&, const String& target, unsigned modifiers) override;
- virtual void page_did_start_loading(const URL&) override;
- virtual void page_did_finish_loading(const URL&) override;
- virtual void page_did_request_alert(const String&) override;
-
- explicit PageHost(ClientConnection&);
-
- Web::Layout::InitialContainingBlockBox* layout_root();
- void setup_palette();
-
- ClientConnection& m_client;
- NonnullOwnPtr<Web::Page> m_page;
- RefPtr<Gfx::PaletteImpl> m_palette_impl;
-};
-
-}
diff --git a/Services/WebContent/WebContentClient.ipc b/Services/WebContent/WebContentClient.ipc
deleted file mode 100644
index 10008a765c..0000000000
--- a/Services/WebContent/WebContentClient.ipc
+++ /dev/null
@@ -1,18 +0,0 @@
-endpoint WebContentClient = 90
-{
- DidStartLoading(URL url) =|
- DidFinishLoading(URL url) =|
- DidPaint(Gfx::IntRect content_rect, i32 shbuf_id) =|
- DidInvalidateContentRect(Gfx::IntRect content_rect) =|
- DidChangeSelection() =|
- DidLayout(Gfx::IntSize content_size) =|
- DidChangeTitle(String title) =|
- DidRequestScrollIntoView(Gfx::IntRect rect) =|
- DidHoverLink(URL url) =|
- DidUnhoverLink() =|
- DidClickLink(URL url, String target, unsigned modifiers) =|
- DidMiddleClickLink(URL url, String target, unsigned modifiers) =|
- DidRequestContextMenu(Gfx::IntPoint content_position) =|
- DidRequestLinkContextMenu(Gfx::IntPoint content_position, URL url, String target, unsigned modifiers) =|
- DidRequestAlert(String message) => ()
-}
diff --git a/Services/WebContent/WebContentServer.ipc b/Services/WebContent/WebContentServer.ipc
deleted file mode 100644
index 143650dab7..0000000000
--- a/Services/WebContent/WebContentServer.ipc
+++ /dev/null
@@ -1,18 +0,0 @@
-endpoint WebContentServer = 89
-{
- Greet(i32 client_pid) => (i32 client_id, i32 server_pid)
-
- UpdateSystemTheme(i32 shbuf_id) =|
-
- LoadURL(URL url) =|
- LoadHTML(String html, URL url) =|
-
- Paint(Gfx::IntRect content_rect, i32 shbuf_id) =|
- SetViewportRect(Gfx::IntRect rect) =|
-
- MouseDown(Gfx::IntPoint position, unsigned button, unsigned buttons, unsigned modifiers) =|
- MouseMove(Gfx::IntPoint position, unsigned button, unsigned buttons, unsigned modifiers) =|
- MouseUp(Gfx::IntPoint position, unsigned button, unsigned buttons, unsigned modifiers) =|
-
- KeyDown(i32 key, unsigned modifiers, u32 code_point) =|
-}
diff --git a/Services/WebContent/main.cpp b/Services/WebContent/main.cpp
deleted file mode 100644
index 5367f2cce3..0000000000
--- a/Services/WebContent/main.cpp
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <LibCore/EventLoop.h>
-#include <LibCore/LocalServer.h>
-#include <LibIPC/ClientConnection.h>
-#include <WebContent/ClientConnection.h>
-
-int main(int, char**)
-{
- Core::EventLoop event_loop;
- if (pledge("stdio shared_buffer accept unix rpath recvfd", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
- if (unveil("/res", "r") < 0) {
- perror("unveil");
- return 1;
- }
- if (unveil("/tmp/portal/protocol", "rw") < 0) {
- perror("unveil");
- return 1;
- }
- if (unveil("/tmp/portal/image", "rw") < 0) {
- perror("unveil");
- return 1;
- }
- if (unveil(nullptr, nullptr) < 0) {
- perror("unveil");
- return 1;
- }
-
- auto socket = Core::LocalSocket::take_over_accepted_socket_from_system_server();
- ASSERT(socket);
- IPC::new_client_connection<WebContent::ClientConnection>(socket.release_nonnull(), 1);
- return event_loop.exec();
-}
diff --git a/Services/WebServer/CMakeLists.txt b/Services/WebServer/CMakeLists.txt
deleted file mode 100644
index 34b1f037c9..0000000000
--- a/Services/WebServer/CMakeLists.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-set(SOURCES
- Client.cpp
- main.cpp
-)
-
-serenity_bin(WebServer)
-target_link_libraries(WebServer LibCore LibHTTP)
diff --git a/Services/WebServer/Client.cpp b/Services/WebServer/Client.cpp
deleted file mode 100644
index c3840bd118..0000000000
--- a/Services/WebServer/Client.cpp
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "Client.h"
-#include <AK/Base64.h>
-#include <AK/LexicalPath.h>
-#include <AK/MappedFile.h>
-#include <AK/StringBuilder.h>
-#include <AK/URLParser.h>
-#include <LibCore/DateTime.h>
-#include <LibCore/DirIterator.h>
-#include <LibCore/File.h>
-#include <LibCore/MimeData.h>
-#include <LibHTTP/HttpRequest.h>
-#include <stdio.h>
-#include <sys/stat.h>
-#include <time.h>
-#include <unistd.h>
-
-namespace WebServer {
-
-Client::Client(NonnullRefPtr<Core::TCPSocket> socket, const String& root, Core::Object* parent)
- : Core::Object(parent)
- , m_socket(socket)
- , m_root_path(root)
-{
-}
-
-void Client::die()
-{
- remove_from_parent();
-}
-
-void Client::start()
-{
- m_socket->on_ready_to_read = [this] {
- auto raw_request = m_socket->read_all();
- if (raw_request.is_null()) {
- die();
- return;
- }
-
- dbg() << "Got raw request: '" << String::copy(raw_request) << "'";
-
- handle_request(raw_request.bytes());
- die();
- };
-}
-
-void Client::handle_request(ReadonlyBytes raw_request)
-{
- auto request_or_error = HTTP::HttpRequest::from_raw_request(raw_request);
- if (!request_or_error.has_value())
- return;
- auto& request = request_or_error.value();
-
- dbg() << "Got HTTP request: " << request.method_name() << " " << request.resource();
- for (auto& header : request.headers()) {
- dbg() << " " << header.name << " => " << header.value;
- }
-
- if (request.method() != HTTP::HttpRequest::Method::GET) {
- send_error_response(403, "Forbidden!", request);
- return;
- }
-
- auto requested_path = LexicalPath::canonicalized_path(request.resource());
- dbg() << "Canonical requested path: '" << requested_path << "'";
-
- StringBuilder path_builder;
- path_builder.append(m_root_path);
- path_builder.append('/');
- path_builder.append(requested_path);
- auto real_path = path_builder.to_string();
-
- if (Core::File::is_directory(real_path)) {
-
- if (!request.resource().ends_with("/")) {
- StringBuilder red;
-
- red.append(requested_path);
- red.append("/");
-
- send_redirect(red.to_string(), request);
- return;
- }
-
- StringBuilder index_html_path_builder;
- index_html_path_builder.append(real_path);
- index_html_path_builder.append("/index.html");
- auto index_html_path = index_html_path_builder.to_string();
- if (!Core::File::exists(index_html_path)) {
- handle_directory_listing(requested_path, real_path, request);
- return;
- }
- real_path = index_html_path;
- }
-
- auto file = Core::File::construct(real_path);
- if (!file->open(Core::File::ReadOnly)) {
- send_error_response(404, "Not found!", request);
- return;
- }
-
- send_response(file->read_all(), request, Core::guess_mime_type_based_on_filename(real_path));
-}
-
-void Client::send_response(StringView response, const HTTP::HttpRequest& request, const String& content_type)
-{
- StringBuilder builder;
- builder.append("HTTP/1.0 200 OK\r\n");
- builder.append("Server: WebServer (SerenityOS)\r\n");
- builder.append("Content-Type: ");
- builder.append(content_type);
- builder.append("\r\n");
- builder.append("\r\n");
-
- m_socket->write(builder.to_string());
- m_socket->write(response);
-
- log_response(200, request);
-}
-
-void Client::send_redirect(StringView redirect_path, const HTTP::HttpRequest& request)
-{
- StringBuilder builder;
- builder.append("HTTP/1.0 301 Moved Permanently\r\n");
- builder.append("Location: ");
- builder.append(redirect_path);
- builder.append("\r\n");
- builder.append("\r\n");
-
- m_socket->write(builder.to_string());
-
- log_response(301, request);
-}
-
-static String folder_image_data()
-{
- static String cache;
- if (cache.is_empty()) {
- auto file_or_error = MappedFile::map("/res/icons/16x16/filetype-folder.png");
- ASSERT(!file_or_error.is_error());
- cache = encode_base64(file_or_error.value()->bytes());
- }
- return cache;
-}
-
-static String file_image_data()
-{
- static String cache;
- if (cache.is_empty()) {
- auto file_or_error = MappedFile::map("/res/icons/16x16/filetype-unknown.png");
- ASSERT(!file_or_error.is_error());
- cache = encode_base64(file_or_error.value()->bytes());
- }
- return cache;
-}
-
-void Client::handle_directory_listing(const String& requested_path, const String& real_path, const HTTP::HttpRequest& request)
-{
- StringBuilder builder;
-
- builder.append("<!DOCTYPE html>\n");
- builder.append("<html>\n");
- builder.append("<head><title>Index of ");
- builder.append(escape_html_entities(requested_path));
- builder.append("</title><style>\n");
- builder.append(".folder { width: 16px; height: 16px; background-image: url('data:image/png;base64,");
- builder.append(folder_image_data());
- builder.append("'); }\n");
- builder.append(".file { width: 16px; height: 16px; background-image: url('data:image/png;base64,");
- builder.append(file_image_data());
- builder.append("'); }\n");
- builder.append("</style></head><body>\n");
- builder.append("<h1>Index of ");
- builder.append(escape_html_entities(requested_path));
- builder.append("</h1>\n");
- builder.append("<hr>\n");
- builder.append("<code><table>\n");
-
- Core::DirIterator dt(real_path);
- while (dt.has_next()) {
- auto name = dt.next_path();
-
- StringBuilder path_builder;
- path_builder.append(real_path);
- path_builder.append('/');
- path_builder.append(name);
- struct stat st;
- memset(&st, 0, sizeof(st));
- int rc = stat(path_builder.to_string().characters(), &st);
- if (rc < 0) {
- perror("stat");
- }
-
- bool is_directory = S_ISDIR(st.st_mode) || name.is_one_of(".", "..");
-
- builder.append("<tr>");
- builder.appendf("<td><div class=\"%s\"></div></td>", is_directory ? "folder" : "file");
- builder.append("<td><a href=\"");
- builder.append(urlencode(name));
- builder.append("\">");
- builder.append(escape_html_entities(name));
- builder.append("</a></td><td>&nbsp;</td>");
-
- builder.appendf("<td>%10zd</td><td>&nbsp;</td>", st.st_size);
- builder.append("<td>");
- builder.append(Core::DateTime::from_timestamp(st.st_mtime).to_string());
- builder.append("</td>");
- builder.append("</tr>\n");
- }
-
- builder.append("</table></code>\n");
- builder.append("<hr>\n");
- builder.append("<i>Generated by WebServer (SerenityOS)</i>\n");
- builder.append("</body>\n");
- builder.append("</html>\n");
-
- send_response(builder.to_string(), request, "text/html");
-}
-
-void Client::send_error_response(unsigned code, const StringView& message, const HTTP::HttpRequest& request)
-{
- StringBuilder builder;
- builder.appendf("HTTP/1.0 %u ", code);
- builder.append(message);
- builder.append("\r\n\r\n");
- builder.append("<!DOCTYPE html><html><body><h1>");
- builder.appendf("%u ", code);
- builder.append(message);
- builder.append("</h1></body></html>");
- m_socket->write(builder.to_string());
-
- log_response(code, request);
-}
-
-void Client::log_response(unsigned code, const HTTP::HttpRequest& request)
-{
- printf("%s :: %03u :: %s %s\n",
- Core::DateTime::now().to_string().characters(),
- code,
- request.method_name().characters(),
- request.resource().characters());
-}
-
-}
diff --git a/Services/WebServer/Client.h b/Services/WebServer/Client.h
deleted file mode 100644
index f363c9d9eb..0000000000
--- a/Services/WebServer/Client.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <LibCore/Object.h>
-#include <LibCore/TCPSocket.h>
-#include <LibHTTP/Forward.h>
-
-namespace WebServer {
-
-class Client final : public Core::Object {
- C_OBJECT(Client);
-
-public:
- void start();
-
-private:
- Client(NonnullRefPtr<Core::TCPSocket>, const String&, Core::Object* parent);
-
- void handle_request(ReadonlyBytes);
- void send_response(StringView, const HTTP::HttpRequest&, const String& content_type);
- void send_redirect(StringView redirect, const HTTP::HttpRequest& request);
- void send_error_response(unsigned code, const StringView& message, const HTTP::HttpRequest&);
- void die();
- void log_response(unsigned code, const HTTP::HttpRequest&);
- void handle_directory_listing(const String& requested_path, const String& real_path, const HTTP::HttpRequest&);
-
- NonnullRefPtr<Core::TCPSocket> m_socket;
- String m_root_path;
-};
-
-}
diff --git a/Services/WebServer/main.cpp b/Services/WebServer/main.cpp
deleted file mode 100644
index 8c326c84a8..0000000000
--- a/Services/WebServer/main.cpp
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "Client.h"
-#include <AK/MappedFile.h>
-#include <LibCore/ArgsParser.h>
-#include <LibCore/EventLoop.h>
-#include <LibCore/File.h>
-#include <LibCore/TCPServer.h>
-#include <stdio.h>
-#include <unistd.h>
-
-int main(int argc, char** argv)
-{
- u16 default_port = 8000;
- const char* root_path = "/www";
-
- int port = default_port;
-
- Core::ArgsParser args_parser;
- args_parser.add_option(port, "Port to listen on", "port", 'p', "port");
- args_parser.add_positional_argument(root_path, "Path to serve the contents of", "path", Core::ArgsParser::Required::No);
- args_parser.parse(argc, argv);
-
- if ((u16)port != port) {
- printf("Warning: invalid port number: %d\n", port);
- port = default_port;
- }
-
- auto real_root_path = Core::File::real_path_for(root_path);
-
- if (!Core::File::exists(real_root_path)) {
- fprintf(stderr, "Root path does not exist: '%s'\n", root_path);
- return 1;
- }
-
- if (pledge("stdio accept rpath inet unix cpath fattr", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- Core::EventLoop loop;
-
- auto server = Core::TCPServer::construct();
-
- server->on_ready_to_accept = [&] {
- auto client_socket = server->accept();
- ASSERT(client_socket);
- auto client = WebServer::Client::construct(client_socket.release_nonnull(), real_root_path, server);
- client->start();
- };
-
- if (!server->listen({}, port)) {
- warnln("Failed to listen on 0.0.0.0:{}", port);
- return 1;
- }
-
- outln("Listening on 0.0.0.0:{}", port);
-
- if (unveil("/res/icons", "r") < 0) {
- perror("unveil");
- return 1;
- }
-
- if (unveil(real_root_path.characters(), "r") < 0) {
- perror("unveil");
- return 1;
- }
-
- unveil(nullptr, nullptr);
-
- if (pledge("stdio accept rpath", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- return loop.exec();
-}
diff --git a/Services/WindowServer/AppletManager.cpp b/Services/WindowServer/AppletManager.cpp
deleted file mode 100644
index 509d5de3d0..0000000000
--- a/Services/WindowServer/AppletManager.cpp
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright (c) 2020, Hüseyin Aslıtürk <asliturk@hotmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "AppletManager.h"
-#include <AK/QuickSort.h>
-#include <LibGfx/Painter.h>
-#include <WindowServer/MenuManager.h>
-
-namespace WindowServer {
-
-static AppletManager* s_the;
-Vector<String> order_vector;
-
-AppletManager::AppletManager()
-{
- s_the = this;
-
- auto wm_config = Core::ConfigFile::open("/etc/WindowServer/WindowServer.ini");
- auto order = wm_config->read_entry("Applet", "Order");
- order_vector = order.split(',');
-}
-
-AppletManager::~AppletManager()
-{
-}
-
-AppletManager& AppletManager::the()
-{
- ASSERT(s_the);
- return *s_the;
-}
-
-void AppletManager::event(Core::Event& event)
-{
- auto& mouse_event = static_cast<MouseEvent&>(event);
-
- for (auto& applet : m_applets) {
- if (!applet)
- continue;
- if (!applet->rect_in_menubar().contains(mouse_event.position()))
- continue;
- auto local_event = mouse_event.translated(-applet->rect_in_menubar().location());
- applet->event(local_event);
- }
-}
-
-void AppletManager::add_applet(Window& applet)
-{
- m_applets.append(applet);
-
- // Prune any dead weak pointers from the applet list.
- m_applets.remove_all_matching([](auto& entry) {
- return entry.is_null();
- });
-
- quick_sort(m_applets, [](auto& a, auto& b) {
- auto index_a = order_vector.find_first_index(a->title());
- auto index_b = order_vector.find_first_index(b->title());
- return index_a.value_or(0) > index_b.value_or(0);
- });
-
- calculate_applet_rects(MenuManager::the().window());
-
- MenuManager::the().refresh();
-}
-
-void AppletManager::calculate_applet_rects(Window& window)
-{
- auto menubar_rect = window.rect();
- int right_edge_x = menubar_rect.width() - 4;
- for (auto& existing_applet : m_applets) {
-
- Gfx::IntRect new_applet_rect(right_edge_x - existing_applet->size().width(), 0, existing_applet->size().width(), existing_applet->size().height());
- Gfx::IntRect dummy_menubar_rect(0, 0, 0, 18);
- new_applet_rect.center_vertically_within(dummy_menubar_rect);
-
- existing_applet->set_rect_in_menubar(new_applet_rect);
- right_edge_x = existing_applet->rect_in_menubar().x() - 4;
- }
-}
-
-void AppletManager::remove_applet(Window& applet)
-{
- m_applets.remove_first_matching([&](auto& entry) {
- return &applet == entry.ptr();
- });
-
- MenuManager::the().refresh();
-}
-
-void AppletManager::draw()
-{
- for (auto& applet : m_applets) {
- if (!applet)
- continue;
- draw_applet(*applet);
- }
-}
-
-void AppletManager::draw_applet(const Window& applet)
-{
- if (!applet.backing_store())
- return;
-
- Gfx::Painter painter(*MenuManager::the().window().backing_store());
- Gfx::PainterStateSaver saver(painter);
- painter.add_clip_rect(applet.rect_in_menubar());
- painter.fill_rect(applet.rect_in_menubar(), WindowManager::the().palette().window());
- painter.blit(applet.rect_in_menubar().location(), *applet.backing_store(), applet.backing_store()->rect());
-}
-
-void AppletManager::invalidate_applet(const Window& applet, const Gfx::IntRect& rect)
-{
- draw_applet(applet);
- MenuManager::the().window().invalidate(rect.translated(applet.rect_in_menubar().location()));
-}
-
-}
diff --git a/Services/WindowServer/AppletManager.h b/Services/WindowServer/AppletManager.h
deleted file mode 100644
index 92f39fbe6d..0000000000
--- a/Services/WindowServer/AppletManager.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (c) 2020, Hüseyin Aslıtürk <asliturk@hotmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <WindowServer/Window.h>
-#include <WindowServer/WindowManager.h>
-
-namespace WindowServer {
-
-class AppletManager : public Core::Object {
- C_OBJECT(AppletManager)
-public:
- AppletManager();
- ~AppletManager();
-
- static AppletManager& the();
-
- virtual void event(Core::Event&) override;
-
- void add_applet(Window& applet);
- void remove_applet(Window& applet);
- void draw();
- void invalidate_applet(const Window& applet, const Gfx::IntRect& rect);
- void calculate_applet_rects(Window& window);
-
-private:
- void draw_applet(const Window& applet);
-
- Vector<WeakPtr<Window>> m_applets;
-};
-
-}
diff --git a/Services/WindowServer/Button.cpp b/Services/WindowServer/Button.cpp
deleted file mode 100644
index 7265494b31..0000000000
--- a/Services/WindowServer/Button.cpp
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <LibGfx/CharacterBitmap.h>
-#include <LibGfx/Painter.h>
-#include <LibGfx/StylePainter.h>
-#include <WindowServer/Button.h>
-#include <WindowServer/Event.h>
-#include <WindowServer/WindowManager.h>
-
-namespace WindowServer {
-
-Button::Button(WindowFrame& frame, Function<void(Button&)>&& on_click_handler)
- : on_click(move(on_click_handler))
- , m_frame(frame)
-{
-}
-
-Button::~Button()
-{
-}
-
-void Button::paint(Gfx::Painter& painter)
-{
- auto palette = WindowManager::the().palette();
- Gfx::PainterStateSaver saver(painter);
- painter.translate(relative_rect().location());
- Gfx::StylePainter::paint_button(painter, rect(), palette, Gfx::ButtonStyle::Normal, m_pressed, m_hovered);
-
- if (m_icon) {
- auto icon_location = rect().center().translated(-(m_icon->width() / 2), -(m_icon->height() / 2));
- if (m_pressed)
- painter.translate(1, 1);
- painter.blit(icon_location, *m_icon, m_icon->rect());
- }
-}
-
-void Button::on_mouse_event(const MouseEvent& event)
-{
- auto& wm = WindowManager::the();
-
- if (event.type() == Event::MouseDown && event.button() == MouseButton::Left) {
- m_pressed = true;
- wm.set_cursor_tracking_button(this);
- m_frame.invalidate(m_relative_rect);
- return;
- }
-
- if (event.type() == Event::MouseUp && event.button() == MouseButton::Left) {
- if (wm.cursor_tracking_button() != this)
- return;
- wm.set_cursor_tracking_button(nullptr);
- bool old_pressed = m_pressed;
- m_pressed = false;
- if (rect().contains(event.position())) {
- if (on_click)
- on_click(*this);
- }
- if (old_pressed != m_pressed) {
- // Would like to compute:
- // m_hovered = rect_after_action().contains(event.position());
- // However, we don't know that rect yet. We can make an educated
- // guess which also looks okay even when wrong:
- m_hovered = false;
- m_frame.invalidate(m_relative_rect);
- }
- return;
- }
-
- if (event.type() == Event::MouseMove) {
- bool old_hovered = m_hovered;
- m_hovered = rect().contains(event.position());
- wm.set_hovered_button(m_hovered ? this : nullptr);
- if (old_hovered != m_hovered)
- m_frame.invalidate(m_relative_rect);
- }
-
- if (event.type() == Event::MouseMove && event.buttons() & (unsigned)MouseButton::Left) {
- if (wm.cursor_tracking_button() != this)
- return;
- bool old_pressed = m_pressed;
- m_pressed = m_hovered;
- if (old_pressed != m_pressed)
- m_frame.invalidate(m_relative_rect);
- }
-}
-
-Gfx::IntRect Button::screen_rect() const
-{
- return m_relative_rect.translated(m_frame.rect().location());
-}
-
-}
diff --git a/Services/WindowServer/Button.h b/Services/WindowServer/Button.h
deleted file mode 100644
index 7a2d6b82e9..0000000000
--- a/Services/WindowServer/Button.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <AK/Function.h>
-#include <AK/Weakable.h>
-#include <LibGfx/Forward.h>
-#include <LibGfx/Rect.h>
-
-namespace WindowServer {
-
-class MouseEvent;
-class WindowFrame;
-
-class Button : public Weakable<Button> {
-public:
- Button(WindowFrame&, Function<void(Button&)>&& on_click_handler);
- ~Button();
-
- Gfx::IntRect relative_rect() const { return m_relative_rect; }
- void set_relative_rect(const Gfx::IntRect& rect) { m_relative_rect = rect; }
-
- Gfx::IntRect rect() const { return { {}, m_relative_rect.size() }; }
- Gfx::IntRect screen_rect() const;
-
- void paint(Gfx::Painter&);
-
- void on_mouse_event(const MouseEvent&);
-
- Function<void(Button&)> on_click;
-
- bool is_visible() const { return m_visible; }
-
- void set_icon(const Gfx::Bitmap& icon) { m_icon = icon; }
-
-private:
- WindowFrame& m_frame;
- Gfx::IntRect m_relative_rect;
- RefPtr<Gfx::Bitmap> m_icon;
- bool m_pressed { false };
- bool m_visible { true };
- bool m_hovered { false };
-};
-
-}
diff --git a/Services/WindowServer/CMakeLists.txt b/Services/WindowServer/CMakeLists.txt
deleted file mode 100644
index b822fec6b5..0000000000
--- a/Services/WindowServer/CMakeLists.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-compile_ipc(WindowServer.ipc WindowServerEndpoint.h)
-compile_ipc(WindowClient.ipc WindowClientEndpoint.h)
-
-set(SOURCES
- AppletManager.cpp
- Button.cpp
- ClientConnection.cpp
- Compositor.cpp
- Cursor.cpp
- EventLoop.cpp
- main.cpp
- MenuBar.cpp
- Menu.cpp
- MenuItem.cpp
- MenuManager.cpp
- Screen.cpp
- Window.cpp
- WindowFrame.cpp
- WindowManager.cpp
- WindowSwitcher.cpp
- WindowServerEndpoint.h
- WindowClientEndpoint.h
-)
-
-serenity_bin(WindowServer)
-target_link_libraries(WindowServer LibCore LibGfx LibThread LibPthread LibIPC)
diff --git a/Services/WindowServer/ClientConnection.cpp b/Services/WindowServer/ClientConnection.cpp
deleted file mode 100644
index f0e4402d81..0000000000
--- a/Services/WindowServer/ClientConnection.cpp
+++ /dev/null
@@ -1,941 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <AK/Badge.h>
-#include <AK/SharedBuffer.h>
-#include <LibGfx/Bitmap.h>
-#include <LibGfx/StandardCursor.h>
-#include <LibGfx/SystemTheme.h>
-#include <WindowServer/AppletManager.h>
-#include <WindowServer/ClientConnection.h>
-#include <WindowServer/Compositor.h>
-#include <WindowServer/Menu.h>
-#include <WindowServer/MenuBar.h>
-#include <WindowServer/MenuItem.h>
-#include <WindowServer/Screen.h>
-#include <WindowServer/Window.h>
-#include <WindowServer/WindowClientEndpoint.h>
-#include <WindowServer/WindowManager.h>
-#include <WindowServer/WindowSwitcher.h>
-#include <errno.h>
-#include <serenity.h>
-#include <stdio.h>
-#include <unistd.h>
-
-namespace WindowServer {
-
-HashMap<int, NonnullRefPtr<ClientConnection>>* s_connections;
-
-static Gfx::IntRect normalize_window_rect(Gfx::IntRect rect, WindowType window_type)
-{
- auto min_size = 1;
- if (window_type == WindowType::Normal)
- min_size = 50;
- Gfx::IntRect normalized_rect = { rect.x(), rect.y(), max(rect.width(), min_size), max(rect.height(), min_size) };
- return normalized_rect;
-}
-
-void ClientConnection::for_each_client(Function<void(ClientConnection&)> callback)
-{
- if (!s_connections)
- return;
- for (auto& it : *s_connections) {
- callback(*it.value);
- }
-}
-
-ClientConnection* ClientConnection::from_client_id(int client_id)
-{
- if (!s_connections)
- return nullptr;
- auto it = s_connections->find(client_id);
- if (it == s_connections->end())
- return nullptr;
- return (*it).value.ptr();
-}
-
-ClientConnection::ClientConnection(NonnullRefPtr<Core::LocalSocket> client_socket, int client_id)
- : IPC::ClientConnection<WindowClientEndpoint, WindowServerEndpoint>(*this, move(client_socket), client_id)
-{
- if (!s_connections)
- s_connections = new HashMap<int, NonnullRefPtr<ClientConnection>>;
- s_connections->set(client_id, *this);
-}
-
-ClientConnection::~ClientConnection()
-{
- if (m_has_display_link)
- Compositor::the().decrement_display_link_count({});
-
- MenuManager::the().close_all_menus_from_client({}, *this);
- auto windows = move(m_windows);
- for (auto& window : windows) {
- window.value->detach_client({});
- if (window.value->type() == WindowType::MenuApplet)
- AppletManager::the().remove_applet(window.value);
- }
-}
-
-void ClientConnection::die()
-{
- deferred_invoke([this](auto&) {
- s_connections->remove(client_id());
- });
-}
-
-void ClientConnection::notify_about_new_screen_rect(const Gfx::IntRect& rect)
-{
- post_message(Messages::WindowClient::ScreenRectChanged(rect));
-}
-
-OwnPtr<Messages::WindowServer::CreateMenubarResponse> ClientConnection::handle(const Messages::WindowServer::CreateMenubar&)
-{
- int menubar_id = m_next_menubar_id++;
- auto menubar = make<MenuBar>(*this, menubar_id);
- m_menubars.set(menubar_id, move(menubar));
- return make<Messages::WindowServer::CreateMenubarResponse>(menubar_id);
-}
-
-OwnPtr<Messages::WindowServer::DestroyMenubarResponse> ClientConnection::handle(const Messages::WindowServer::DestroyMenubar& message)
-{
- int menubar_id = message.menubar_id();
- auto it = m_menubars.find(menubar_id);
- if (it == m_menubars.end()) {
- did_misbehave("DestroyMenubar: Bad menubar ID");
- return {};
- }
- auto& menubar = *(*it).value;
- MenuManager::the().close_menubar(menubar);
- m_menubars.remove(it);
- return make<Messages::WindowServer::DestroyMenubarResponse>();
-}
-
-OwnPtr<Messages::WindowServer::CreateMenuResponse> ClientConnection::handle(const Messages::WindowServer::CreateMenu& message)
-{
- int menu_id = m_next_menu_id++;
- auto menu = Menu::construct(this, menu_id, message.menu_title());
- m_menus.set(menu_id, move(menu));
- return make<Messages::WindowServer::CreateMenuResponse>(menu_id);
-}
-
-OwnPtr<Messages::WindowServer::DestroyMenuResponse> ClientConnection::handle(const Messages::WindowServer::DestroyMenu& message)
-{
- int menu_id = message.menu_id();
- auto it = m_menus.find(menu_id);
- if (it == m_menus.end()) {
- did_misbehave("DestroyMenu: Bad menu ID");
- return {};
- }
- auto& menu = *(*it).value;
- menu.close();
- m_menus.remove(it);
- remove_child(menu);
- return make<Messages::WindowServer::DestroyMenuResponse>();
-}
-
-OwnPtr<Messages::WindowServer::SetApplicationMenubarResponse> ClientConnection::handle(const Messages::WindowServer::SetApplicationMenubar& message)
-{
- int menubar_id = message.menubar_id();
- auto it = m_menubars.find(menubar_id);
- if (it == m_menubars.end()) {
- did_misbehave("SetApplicationMenubar: Bad menubar ID");
- return {};
- }
- auto& menubar = *(*it).value;
- m_app_menubar = menubar.make_weak_ptr();
- WindowManager::the().notify_client_changed_app_menubar(*this);
- return make<Messages::WindowServer::SetApplicationMenubarResponse>();
-}
-
-OwnPtr<Messages::WindowServer::AddMenuToMenubarResponse> ClientConnection::handle(const Messages::WindowServer::AddMenuToMenubar& message)
-{
- int menubar_id = message.menubar_id();
- int menu_id = message.menu_id();
- auto it = m_menubars.find(menubar_id);
- auto jt = m_menus.find(menu_id);
- if (it == m_menubars.end()) {
- did_misbehave("AddMenuToMenubar: Bad menubar ID");
- return {};
- }
- if (jt == m_menus.end()) {
- did_misbehave("AddMenuToMenubar: Bad menu ID");
- return {};
- }
- auto& menubar = *(*it).value;
- auto& menu = *(*jt).value;
- menubar.add_menu(menu);
- return make<Messages::WindowServer::AddMenuToMenubarResponse>();
-}
-
-OwnPtr<Messages::WindowServer::AddMenuItemResponse> ClientConnection::handle(const Messages::WindowServer::AddMenuItem& message)
-{
- int menu_id = message.menu_id();
- unsigned identifier = message.identifier();
- auto it = m_menus.find(menu_id);
- if (it == m_menus.end()) {
- dbg() << "AddMenuItem: Bad menu ID: " << menu_id;
- return {};
- }
- auto& menu = *(*it).value;
- auto menu_item = make<MenuItem>(menu, identifier, message.text(), message.shortcut(), message.enabled(), message.checkable(), message.checked());
- if (message.is_default())
- menu_item->set_default(true);
- if (message.icon_buffer_id() != -1) {
- auto icon_buffer = SharedBuffer::create_from_shbuf_id(message.icon_buffer_id());
- if (!icon_buffer)
- return {};
- // FIXME: Verify that the icon buffer can accommodate a 16x16 bitmap view.
- auto shared_icon = Gfx::Bitmap::create_with_shared_buffer(Gfx::BitmapFormat::RGBA32, icon_buffer.release_nonnull(), { 16, 16 });
- menu_item->set_icon(shared_icon);
- }
- menu_item->set_submenu_id(message.submenu_id());
- menu_item->set_exclusive(message.exclusive());
- menu.add_item(move(menu_item));
- return make<Messages::WindowServer::AddMenuItemResponse>();
-}
-
-OwnPtr<Messages::WindowServer::PopupMenuResponse> ClientConnection::handle(const Messages::WindowServer::PopupMenu& message)
-{
- int menu_id = message.menu_id();
- auto position = message.screen_position();
- auto it = m_menus.find(menu_id);
- if (it == m_menus.end()) {
- did_misbehave("PopupMenu: Bad menu ID");
- return {};
- }
- auto& menu = *(*it).value;
- menu.popup(position);
- return make<Messages::WindowServer::PopupMenuResponse>();
-}
-
-OwnPtr<Messages::WindowServer::DismissMenuResponse> ClientConnection::handle(const Messages::WindowServer::DismissMenu& message)
-{
- int menu_id = message.menu_id();
- auto it = m_menus.find(menu_id);
- if (it == m_menus.end()) {
- did_misbehave("DismissMenu: Bad menu ID");
- return {};
- }
- auto& menu = *(*it).value;
- menu.close();
- return make<Messages::WindowServer::DismissMenuResponse>();
-}
-
-OwnPtr<Messages::WindowServer::UpdateMenuItemResponse> ClientConnection::handle(const Messages::WindowServer::UpdateMenuItem& message)
-{
- int menu_id = message.menu_id();
- auto it = m_menus.find(menu_id);
- if (it == m_menus.end()) {
- did_misbehave("UpdateMenuItem: Bad menu ID");
- return {};
- }
- auto& menu = *(*it).value;
- auto* menu_item = menu.item_with_identifier(message.identifier());
- if (!menu_item) {
- did_misbehave("UpdateMenuItem: Bad menu item identifier");
- return {};
- }
- menu_item->set_text(message.text());
- menu_item->set_shortcut_text(message.shortcut());
- menu_item->set_enabled(message.enabled());
- menu_item->set_checkable(message.checkable());
- menu_item->set_default(message.is_default());
- if (message.checkable())
- menu_item->set_checked(message.checked());
- return make<Messages::WindowServer::UpdateMenuItemResponse>();
-}
-
-OwnPtr<Messages::WindowServer::AddMenuSeparatorResponse> ClientConnection::handle(const Messages::WindowServer::AddMenuSeparator& message)
-{
- int menu_id = message.menu_id();
- auto it = m_menus.find(menu_id);
- if (it == m_menus.end()) {
- did_misbehave("AddMenuSeparator: Bad menu ID");
- return {};
- }
- auto& menu = *(*it).value;
- menu.add_item(make<MenuItem>(menu, MenuItem::Separator));
- return make<Messages::WindowServer::AddMenuSeparatorResponse>();
-}
-
-OwnPtr<Messages::WindowServer::MoveWindowToFrontResponse> ClientConnection::handle(const Messages::WindowServer::MoveWindowToFront& message)
-{
- auto it = m_windows.find(message.window_id());
- if (it == m_windows.end()) {
- did_misbehave("MoveWindowToFront: Bad window ID");
- return {};
- }
- WindowManager::the().move_to_front_and_make_active(*(*it).value);
- return make<Messages::WindowServer::MoveWindowToFrontResponse>();
-}
-
-OwnPtr<Messages::WindowServer::SetFullscreenResponse> ClientConnection::handle(const Messages::WindowServer::SetFullscreen& message)
-{
- auto it = m_windows.find(message.window_id());
- if (it == m_windows.end()) {
- did_misbehave("SetFullscreen: Bad window ID");
- return {};
- }
- it->value->set_fullscreen(message.fullscreen());
- return make<Messages::WindowServer::SetFullscreenResponse>();
-}
-
-OwnPtr<Messages::WindowServer::SetWindowOpacityResponse> ClientConnection::handle(const Messages::WindowServer::SetWindowOpacity& message)
-{
- auto it = m_windows.find(message.window_id());
- if (it == m_windows.end()) {
- did_misbehave("SetWindowOpacity: Bad window ID");
- return {};
- }
- it->value->set_opacity(message.opacity());
- return make<Messages::WindowServer::SetWindowOpacityResponse>();
-}
-
-void ClientConnection::handle(const Messages::WindowServer::AsyncSetWallpaper& message)
-{
- Compositor::the().set_wallpaper(message.path(), [&](bool success) {
- post_message(Messages::WindowClient::AsyncSetWallpaperFinished(success));
- });
-}
-
-OwnPtr<Messages::WindowServer::SetBackgroundColorResponse> ClientConnection::handle(const Messages::WindowServer::SetBackgroundColor& message)
-{
- Compositor::the().set_background_color(message.background_color());
- return make<Messages::WindowServer::SetBackgroundColorResponse>();
-}
-
-OwnPtr<Messages::WindowServer::SetWallpaperModeResponse> ClientConnection::handle(const Messages::WindowServer::SetWallpaperMode& message)
-{
- Compositor::the().set_wallpaper_mode(message.mode());
- return make<Messages::WindowServer::SetWallpaperModeResponse>();
-}
-
-OwnPtr<Messages::WindowServer::GetWallpaperResponse> ClientConnection::handle(const Messages::WindowServer::GetWallpaper&)
-{
- return make<Messages::WindowServer::GetWallpaperResponse>(Compositor::the().wallpaper_path());
-}
-
-OwnPtr<Messages::WindowServer::SetResolutionResponse> ClientConnection::handle(const Messages::WindowServer::SetResolution& message)
-{
- return make<Messages::WindowServer::SetResolutionResponse>(WindowManager::the().set_resolution(message.resolution().width(), message.resolution().height()), WindowManager::the().resolution());
-}
-
-OwnPtr<Messages::WindowServer::SetWindowTitleResponse> ClientConnection::handle(const Messages::WindowServer::SetWindowTitle& message)
-{
- auto it = m_windows.find(message.window_id());
- if (it == m_windows.end()) {
- did_misbehave("SetWindowTitle: Bad window ID");
- return {};
- }
- it->value->set_title(message.title());
- return make<Messages::WindowServer::SetWindowTitleResponse>();
-}
-
-OwnPtr<Messages::WindowServer::GetWindowTitleResponse> ClientConnection::handle(const Messages::WindowServer::GetWindowTitle& message)
-{
- auto it = m_windows.find(message.window_id());
- if (it == m_windows.end()) {
- did_misbehave("GetWindowTitle: Bad window ID");
- return {};
- }
- return make<Messages::WindowServer::GetWindowTitleResponse>(it->value->title());
-}
-
-OwnPtr<Messages::WindowServer::IsMaximizedResponse> ClientConnection::handle(const Messages::WindowServer::IsMaximized& message)
-{
- auto it = m_windows.find(message.window_id());
- if (it == m_windows.end()) {
- did_misbehave("IsMaximized: Bad window ID");
- return {};
- }
- return make<Messages::WindowServer::IsMaximizedResponse>(it->value->is_maximized());
-}
-
-OwnPtr<Messages::WindowServer::SetWindowIconBitmapResponse> ClientConnection::handle(const Messages::WindowServer::SetWindowIconBitmap& message)
-{
- auto it = m_windows.find(message.window_id());
- if (it == m_windows.end()) {
- did_misbehave("SetWindowIconBitmap: Bad window ID");
- return {};
- }
- auto& window = *(*it).value;
-
- if (message.icon().is_valid()) {
- window.set_icon(*message.icon().bitmap());
- } else {
- window.set_default_icon();
- }
-
- window.frame().invalidate_title_bar();
- WindowManager::the().tell_wm_listeners_window_icon_changed(window);
- return make<Messages::WindowServer::SetWindowIconBitmapResponse>();
-}
-
-OwnPtr<Messages::WindowServer::SetWindowRectResponse> ClientConnection::handle(const Messages::WindowServer::SetWindowRect& message)
-{
- int window_id = message.window_id();
- auto it = m_windows.find(window_id);
- if (it == m_windows.end()) {
- did_misbehave("SetWindowRect: Bad window ID");
- return {};
- }
- auto& window = *(*it).value;
- if (window.is_fullscreen()) {
- dbgln("ClientConnection: Ignoring SetWindowRect request for fullscreen window");
- return {};
- }
-
- if (message.rect().location() != window.rect().location()) {
- window.set_default_positioned(false);
- }
- auto normalized_rect = normalize_window_rect(message.rect(), window.type());
- window.set_rect(normalized_rect);
- window.request_update(normalized_rect);
- return make<Messages::WindowServer::SetWindowRectResponse>(normalized_rect);
-}
-
-OwnPtr<Messages::WindowServer::GetWindowRectResponse> ClientConnection::handle(const Messages::WindowServer::GetWindowRect& message)
-{
- int window_id = message.window_id();
- auto it = m_windows.find(window_id);
- if (it == m_windows.end()) {
- did_misbehave("GetWindowRect: Bad window ID");
- return {};
- }
- return make<Messages::WindowServer::GetWindowRectResponse>(it->value->rect());
-}
-
-OwnPtr<Messages::WindowServer::GetWindowRectInMenubarResponse> ClientConnection::handle(const Messages::WindowServer::GetWindowRectInMenubar& message)
-{
- int window_id = message.window_id();
- auto it = m_windows.find(window_id);
- if (it == m_windows.end()) {
- did_misbehave("GetWindowRectInMenubar: Bad window ID");
- return {};
- }
- return make<Messages::WindowServer::GetWindowRectInMenubarResponse>(it->value->rect_in_menubar());
-}
-
-Window* ClientConnection::window_from_id(i32 window_id)
-{
- auto it = m_windows.find(window_id);
- if (it == m_windows.end())
- return nullptr;
- return it->value.ptr();
-}
-
-OwnPtr<Messages::WindowServer::CreateWindowResponse> ClientConnection::handle(const Messages::WindowServer::CreateWindow& message)
-{
- Window* parent_window = nullptr;
- if (message.parent_window_id()) {
- parent_window = window_from_id(message.parent_window_id());
- if (!parent_window) {
- did_misbehave("CreateWindow with bad parent_window_id");
- return {};
- }
- }
-
- int window_id = m_next_window_id++;
- auto window = Window::construct(*this, (WindowType)message.type(), window_id, message.modal(), message.minimizable(), message.frameless(), message.resizable(), message.fullscreen(), message.accessory(), parent_window);
-
- window->set_has_alpha_channel(message.has_alpha_channel());
- window->set_title(message.title());
- if (!message.fullscreen()) {
- auto rect = message.rect();
- if (message.auto_position() && window->type() == WindowType::Normal) {
- rect = { WindowManager::the().get_recommended_window_position({ 100, 100 }), message.rect().size() };
- window->set_default_positioned(true);
- }
- auto normalized_rect = normalize_window_rect(rect, window->type());
- window->set_rect(normalized_rect);
- }
- if (window->type() == WindowType::Desktop) {
- window->set_rect(WindowManager::the().desktop_rect());
- window->recalculate_rect();
- }
- window->set_opacity(message.opacity());
- window->set_size_increment(message.size_increment());
- window->set_base_size(message.base_size());
- window->set_resize_aspect_ratio(message.resize_aspect_ratio());
- window->invalidate();
- if (window->type() == WindowType::MenuApplet)
- AppletManager::the().add_applet(*window);
- m_windows.set(window_id, move(window));
- return make<Messages::WindowServer::CreateWindowResponse>(window_id);
-}
-
-void ClientConnection::destroy_window(Window& window, Vector<i32>& destroyed_window_ids)
-{
- for (auto& child_window : window.child_windows()) {
- if (!child_window)
- continue;
- ASSERT(child_window->window_id() != window.window_id());
- destroy_window(*child_window, destroyed_window_ids);
- }
-
- for (auto& accessory_window : window.accessory_windows()) {
- if (!accessory_window)
- continue;
- ASSERT(accessory_window->window_id() != window.window_id());
- destroy_window(*accessory_window, destroyed_window_ids);
- }
-
- destroyed_window_ids.append(window.window_id());
-
- if (window.type() == WindowType::MenuApplet)
- AppletManager::the().remove_applet(window);
-
- window.destroy();
- remove_child(window);
- m_windows.remove(window.window_id());
-}
-
-OwnPtr<Messages::WindowServer::DestroyWindowResponse> ClientConnection::handle(const Messages::WindowServer::DestroyWindow& message)
-{
- auto it = m_windows.find(message.window_id());
- if (it == m_windows.end()) {
- did_misbehave("DestroyWindow: Bad window ID");
- return {};
- }
- auto& window = *(*it).value;
- Vector<i32> destroyed_window_ids;
- destroy_window(window, destroyed_window_ids);
- return make<Messages::WindowServer::DestroyWindowResponse>(destroyed_window_ids);
-}
-
-void ClientConnection::post_paint_message(Window& window, bool ignore_occlusion)
-{
- auto rect_set = window.take_pending_paint_rects();
- if (window.is_minimized() || (!ignore_occlusion && window.is_occluded()))
- return;
-
- post_message(Messages::WindowClient::Paint(window.window_id(), window.size(), rect_set.rects()));
-}
-
-void ClientConnection::handle(const Messages::WindowServer::InvalidateRect& message)
-{
- auto it = m_windows.find(message.window_id());
- if (it == m_windows.end()) {
- did_misbehave("InvalidateRect: Bad window ID");
- return;
- }
- auto& window = *(*it).value;
- for (size_t i = 0; i < message.rects().size(); ++i)
- window.request_update(message.rects()[i].intersected({ {}, window.size() }), message.ignore_occlusion());
-}
-
-void ClientConnection::handle(const Messages::WindowServer::DidFinishPainting& message)
-{
- int window_id = message.window_id();
- auto it = m_windows.find(window_id);
- if (it == m_windows.end()) {
- did_misbehave("DidFinishPainting: Bad window ID");
- return;
- }
- auto& window = *(*it).value;
- for (auto& rect : message.rects())
- window.invalidate(rect);
-
- WindowSwitcher::the().refresh_if_needed();
-}
-
-OwnPtr<Messages::WindowServer::SetWindowBackingStoreResponse> ClientConnection::handle(const Messages::WindowServer::SetWindowBackingStore& message)
-{
- int window_id = message.window_id();
- auto it = m_windows.find(window_id);
- if (it == m_windows.end()) {
- did_misbehave("SetWindowBackingStore: Bad window ID");
- return {};
- }
- auto& window = *(*it).value;
- if (window.last_backing_store() && window.last_backing_store()->shbuf_id() == message.shbuf_id()) {
- window.swap_backing_stores();
- } else {
- auto shared_buffer = SharedBuffer::create_from_shbuf_id(message.shbuf_id());
- if (!shared_buffer)
- return make<Messages::WindowServer::SetWindowBackingStoreResponse>();
- auto backing_store = Gfx::Bitmap::create_with_shared_buffer(
- message.has_alpha_channel() ? Gfx::BitmapFormat::RGBA32 : Gfx::BitmapFormat::RGB32,
- *shared_buffer,
- message.size());
- window.set_backing_store(move(backing_store));
- }
-
- if (message.flush_immediately())
- window.invalidate(false);
-
- return make<Messages::WindowServer::SetWindowBackingStoreResponse>();
-}
-
-OwnPtr<Messages::WindowServer::SetGlobalCursorTrackingResponse> ClientConnection::handle(const Messages::WindowServer::SetGlobalCursorTracking& message)
-{
- int window_id = message.window_id();
- auto it = m_windows.find(window_id);
- if (it == m_windows.end()) {
- did_misbehave("SetGlobalCursorTracking: Bad window ID");
- return {};
- }
- it->value->set_global_cursor_tracking_enabled(message.enabled());
- return make<Messages::WindowServer::SetGlobalCursorTrackingResponse>();
-}
-
-OwnPtr<Messages::WindowServer::SetWindowCursorResponse> ClientConnection::handle(const Messages::WindowServer::SetWindowCursor& message)
-{
- auto it = m_windows.find(message.window_id());
- if (it == m_windows.end()) {
- did_misbehave("SetWindowCursor: Bad window ID");
- return {};
- }
- auto& window = *(*it).value;
- if (message.cursor_type() < 0 || message.cursor_type() >= (i32)Gfx::StandardCursor::__Count) {
- did_misbehave("SetWindowCursor: Bad cursor type");
- return {};
- }
- window.set_cursor(Cursor::create((Gfx::StandardCursor)message.cursor_type()));
- Compositor::the().invalidate_cursor();
- return make<Messages::WindowServer::SetWindowCursorResponse>();
-}
-
-OwnPtr<Messages::WindowServer::SetWindowCustomCursorResponse> ClientConnection::handle(const Messages::WindowServer::SetWindowCustomCursor& message)
-{
- auto it = m_windows.find(message.window_id());
- if (it == m_windows.end()) {
- did_misbehave("SetWindowCustomCursor: Bad window ID");
- return {};
- }
-
- auto& window = *(*it).value;
- if (!message.cursor().is_valid()) {
- did_misbehave("SetWindowCustomCursor: Bad cursor");
- return {};
- }
-
- window.set_cursor(Cursor::create(*message.cursor().bitmap()));
- Compositor::the().invalidate_cursor();
- return make<Messages::WindowServer::SetWindowCustomCursorResponse>();
-}
-
-OwnPtr<Messages::WindowServer::SetWindowHasAlphaChannelResponse> ClientConnection::handle(const Messages::WindowServer::SetWindowHasAlphaChannel& message)
-{
- auto it = m_windows.find(message.window_id());
- if (it == m_windows.end()) {
- did_misbehave("SetWindowHasAlphaChannel: Bad window ID");
- return {};
- }
- it->value->set_has_alpha_channel(message.has_alpha_channel());
- return make<Messages::WindowServer::SetWindowHasAlphaChannelResponse>();
-}
-
-void ClientConnection::handle(const Messages::WindowServer::WM_SetActiveWindow& message)
-{
- auto* client = ClientConnection::from_client_id(message.client_id());
- if (!client) {
- did_misbehave("WM_SetActiveWindow: Bad client ID");
- return;
- }
- auto it = client->m_windows.find(message.window_id());
- if (it == client->m_windows.end()) {
- did_misbehave("WM_SetActiveWindow: Bad window ID");
- return;
- }
- auto& window = *(*it).value;
- WindowManager::the().minimize_windows(window, false);
- WindowManager::the().move_to_front_and_make_active(window);
-}
-
-void ClientConnection::handle(const Messages::WindowServer::WM_PopupWindowMenu& message)
-{
- auto* client = ClientConnection::from_client_id(message.client_id());
- if (!client) {
- did_misbehave("WM_PopupWindowMenu: Bad client ID");
- return;
- }
- auto it = client->m_windows.find(message.window_id());
- if (it == client->m_windows.end()) {
- did_misbehave("WM_PopupWindowMenu: Bad window ID");
- return;
- }
- auto& window = *(*it).value;
- if (auto* modal_window = window.blocking_modal_window()) {
- modal_window->popup_window_menu(message.screen_position(), WindowMenuDefaultAction::BasedOnWindowState);
- } else {
- window.popup_window_menu(message.screen_position(), WindowMenuDefaultAction::BasedOnWindowState);
- }
-}
-
-void ClientConnection::handle(const Messages::WindowServer::WM_StartWindowResize& request)
-{
- auto* client = ClientConnection::from_client_id(request.client_id());
- if (!client) {
- did_misbehave("WM_StartWindowResize: Bad client ID");
- return;
- }
- auto it = client->m_windows.find(request.window_id());
- if (it == client->m_windows.end()) {
- did_misbehave("WM_StartWindowResize: Bad window ID");
- return;
- }
- auto& window = *(*it).value;
- // FIXME: We are cheating a bit here by using the current cursor location and hard-coding the left button.
- // Maybe the client should be allowed to specify what initiated this request?
- WindowManager::the().start_window_resize(window, Screen::the().cursor_location(), MouseButton::Left);
-}
-
-void ClientConnection::handle(const Messages::WindowServer::WM_SetWindowMinimized& message)
-{
- auto* client = ClientConnection::from_client_id(message.client_id());
- if (!client) {
- did_misbehave("WM_SetWindowMinimized: Bad client ID");
- return;
- }
- auto it = client->m_windows.find(message.window_id());
- if (it == client->m_windows.end()) {
- did_misbehave("WM_SetWindowMinimized: Bad window ID");
- return;
- }
- auto& window = *(*it).value;
- WindowManager::the().minimize_windows(window, message.minimized());
-}
-
-OwnPtr<Messages::WindowServer::GreetResponse> ClientConnection::handle(const Messages::WindowServer::Greet&)
-{
- return make<Messages::WindowServer::GreetResponse>(client_id(), Screen::the().rect(), Gfx::current_system_theme_buffer_id());
-}
-
-void ClientConnection::handle(const Messages::WindowServer::WM_SetWindowTaskbarRect& message)
-{
- // Because the Taskbar (which should be the only user of this API) does not own the
- // window or the client id, there is a possibility that it may send this message for
- // a window or client that may have been destroyed already. This is not an error,
- // and we should not call did_misbehave() for either.
- auto* client = ClientConnection::from_client_id(message.client_id());
- if (!client)
- return;
-
- auto it = client->m_windows.find(message.window_id());
- if (it == client->m_windows.end())
- return;
-
- auto& window = *(*it).value;
- window.set_taskbar_rect(message.rect());
-}
-
-OwnPtr<Messages::WindowServer::StartDragResponse> ClientConnection::handle(const Messages::WindowServer::StartDrag& message)
-{
- auto& wm = WindowManager::the();
- if (wm.dnd_client())
- return make<Messages::WindowServer::StartDragResponse>(false);
-
- RefPtr<Gfx::Bitmap> bitmap;
- if (message.bitmap_id() != -1) {
- auto shared_buffer = SharedBuffer::create_from_shbuf_id(message.bitmap_id());
- ssize_t size_in_bytes = message.bitmap_size().area() * sizeof(Gfx::RGBA32);
- if (size_in_bytes > shared_buffer->size()) {
- did_misbehave("SetAppletBackingStore: Shared buffer is too small for applet size");
- return {};
- }
- bitmap = Gfx::Bitmap::create_with_shared_buffer(Gfx::BitmapFormat::RGBA32, *shared_buffer, message.bitmap_size());
- }
-
- wm.start_dnd_drag(*this, message.text(), bitmap, Core::MimeData::construct(message.mime_data()));
- return make<Messages::WindowServer::StartDragResponse>(true);
-}
-
-OwnPtr<Messages::WindowServer::SetSystemMenuResponse> ClientConnection::handle(const Messages::WindowServer::SetSystemMenu& message)
-{
- auto it = m_menus.find(message.menu_id());
- if (it == m_menus.end()) {
- did_misbehave("SetSystemMenu called with invalid menu ID");
- return {};
- }
-
- auto& menu = it->value;
- MenuManager::the().set_system_menu(menu);
- return make<Messages::WindowServer::SetSystemMenuResponse>();
-}
-
-OwnPtr<Messages::WindowServer::SetSystemThemeResponse> ClientConnection::handle(const Messages::WindowServer::SetSystemTheme& message)
-{
- bool success = WindowManager::the().update_theme(message.theme_path(), message.theme_name());
- return make<Messages::WindowServer::SetSystemThemeResponse>(success);
-}
-
-OwnPtr<Messages::WindowServer::GetSystemThemeResponse> ClientConnection::handle(const Messages::WindowServer::GetSystemTheme&)
-{
- auto wm_config = Core::ConfigFile::open("/etc/WindowServer/WindowServer.ini");
- auto name = wm_config->read_entry("Theme", "Name");
- return make<Messages::WindowServer::GetSystemThemeResponse>(name);
-}
-
-void ClientConnection::boost()
-{
- // FIXME: Re-enable this when we have a solution for boosting.
-#if 0
- if (set_process_boost(client_pid(), 10) < 0)
- perror("boost: set_process_boost");
-#endif
-}
-
-void ClientConnection::deboost()
-{
- // FIXME: Re-enable this when we have a solution for boosting.
-#if 0
- if (set_process_boost(client_pid(), 0) < 0)
- perror("deboost: set_process_boost");
-#endif
-}
-
-OwnPtr<Messages::WindowServer::SetWindowBaseSizeAndSizeIncrementResponse> ClientConnection::handle(const Messages::WindowServer::SetWindowBaseSizeAndSizeIncrement& message)
-{
- auto it = m_windows.find(message.window_id());
- if (it == m_windows.end()) {
- did_misbehave("SetWindowBaseSizeAndSizeIncrementResponse: Bad window ID");
- return {};
- }
-
- auto& window = *it->value;
- window.set_base_size(message.base_size());
- window.set_size_increment(message.size_increment());
-
- return make<Messages::WindowServer::SetWindowBaseSizeAndSizeIncrementResponse>();
-}
-
-OwnPtr<Messages::WindowServer::SetWindowResizeAspectRatioResponse> ClientConnection::handle(const Messages::WindowServer::SetWindowResizeAspectRatio& message)
-{
- auto it = m_windows.find(message.window_id());
- if (it == m_windows.end()) {
- did_misbehave("SetWindowResizeAspectRatioResponse: Bad window ID");
- return {};
- }
-
- auto& window = *it->value;
- window.set_resize_aspect_ratio(message.resize_aspect_ratio());
-
- return make<Messages::WindowServer::SetWindowResizeAspectRatioResponse>();
-}
-
-void ClientConnection::handle(const Messages::WindowServer::EnableDisplayLink&)
-{
- if (m_has_display_link)
- return;
- m_has_display_link = true;
- Compositor::the().increment_display_link_count({});
-}
-
-void ClientConnection::handle(const Messages::WindowServer::DisableDisplayLink&)
-{
- if (!m_has_display_link)
- return;
- m_has_display_link = false;
- Compositor::the().decrement_display_link_count({});
-}
-
-void ClientConnection::notify_display_link(Badge<Compositor>)
-{
- if (!m_has_display_link)
- return;
-
- post_message(Messages::WindowClient::DisplayLinkNotification());
-}
-
-void ClientConnection::handle(const Messages::WindowServer::SetWindowProgress& message)
-{
- auto it = m_windows.find(message.window_id());
- if (it == m_windows.end()) {
- did_misbehave("SetWindowProgress with bad window ID");
- return;
- }
- it->value->set_progress(message.progress());
-}
-
-void ClientConnection::handle(const Messages::WindowServer::Pong&)
-{
- m_ping_timer = nullptr;
- set_unresponsive(false);
-}
-
-OwnPtr<Messages::WindowServer::GetGlobalCursorPositionResponse> ClientConnection::handle(const Messages::WindowServer::GetGlobalCursorPosition&)
-{
- return make<Messages::WindowServer::GetGlobalCursorPositionResponse>(Screen::the().cursor_location());
-}
-
-OwnPtr<Messages::WindowServer::SetMouseAccelerationResponse> ClientConnection::handle(const Messages::WindowServer::SetMouseAcceleration& message)
-{
- if (message.factor() < mouse_accel_min || message.factor() > mouse_accel_max) {
- did_misbehave("SetMouseAcceleration with bad acceleration factor");
- return {};
- }
- WindowManager::the().set_acceleration_factor(message.factor());
- return make<Messages::WindowServer::SetMouseAccelerationResponse>();
-}
-
-OwnPtr<Messages::WindowServer::GetMouseAccelerationResponse> ClientConnection::handle(const Messages::WindowServer::GetMouseAcceleration&)
-{
- return make<Messages::WindowServer::GetMouseAccelerationResponse>(Screen::the().acceleration_factor());
-}
-
-OwnPtr<Messages::WindowServer::SetScrollStepSizeResponse> ClientConnection::handle(const Messages::WindowServer::SetScrollStepSize& message)
-{
- if (message.step_size() < scroll_step_size_min) {
- did_misbehave("SetScrollStepSize with bad scroll step size");
- return {};
- }
- WindowManager::the().set_scroll_step_size(message.step_size());
- return make<Messages::WindowServer::SetScrollStepSizeResponse>();
-}
-OwnPtr<Messages::WindowServer::GetScrollStepSizeResponse> ClientConnection::handle(const Messages::WindowServer::GetScrollStepSize&)
-{
- return make<Messages::WindowServer::GetScrollStepSizeResponse>(Screen::the().scroll_step_size());
-}
-
-void ClientConnection::set_unresponsive(bool unresponsive)
-{
- if (m_unresponsive == unresponsive)
- return;
- m_unresponsive = unresponsive;
- for (auto& it : m_windows) {
- auto& window = *it.value;
- window.invalidate();
- if (unresponsive)
- window.set_cursor(WindowManager::the().wait_cursor());
- }
- Compositor::the().invalidate_cursor();
-}
-
-void ClientConnection::may_have_become_unresponsive()
-{
- post_message(Messages::WindowClient::Ping());
- m_ping_timer = Core::Timer::create_single_shot(1000, [this] {
- set_unresponsive(true);
- });
-}
-
-void ClientConnection::did_become_responsive()
-{
- set_unresponsive(false);
-}
-
-}
diff --git a/Services/WindowServer/ClientConnection.h b/Services/WindowServer/ClientConnection.h
deleted file mode 100644
index 12174e9189..0000000000
--- a/Services/WindowServer/ClientConnection.h
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <AK/Badge.h>
-#include <AK/Function.h>
-#include <AK/HashMap.h>
-#include <AK/OwnPtr.h>
-#include <AK/WeakPtr.h>
-#include <LibCore/Object.h>
-#include <LibGfx/Bitmap.h>
-#include <LibIPC/ClientConnection.h>
-#include <WindowServer/Event.h>
-#include <WindowServer/WindowClientEndpoint.h>
-#include <WindowServer/WindowServerEndpoint.h>
-
-namespace WindowServer {
-
-class Compositor;
-class Window;
-class Menu;
-class MenuBar;
-
-class ClientConnection final
- : public IPC::ClientConnection<WindowClientEndpoint, WindowServerEndpoint>
- , public WindowServerEndpoint {
- C_OBJECT(ClientConnection)
-public:
- ~ClientConnection() override;
-
- bool is_unresponsive() const { return m_unresponsive; }
-
- void boost();
- void deboost();
-
- static ClientConnection* from_client_id(int client_id);
- static void for_each_client(Function<void(ClientConnection&)>);
-
- MenuBar* app_menubar() { return m_app_menubar.ptr(); }
-
- void notify_about_new_screen_rect(const Gfx::IntRect&);
- void post_paint_message(Window&, bool ignore_occlusion = false);
-
- Menu* find_menu_by_id(int menu_id)
- {
- auto menu = m_menus.get(menu_id);
- if (!menu.has_value())
- return nullptr;
- return const_cast<Menu*>(menu.value().ptr());
- }
- const Menu* find_menu_by_id(int menu_id) const
- {
- auto menu = m_menus.get(menu_id);
- if (!menu.has_value())
- return nullptr;
- return menu.value().ptr();
- }
-
- void notify_display_link(Badge<Compositor>);
-
-private:
- explicit ClientConnection(NonnullRefPtr<Core::LocalSocket>, int client_id);
-
- // ^ClientConnection
- virtual void die() override;
- virtual void may_have_become_unresponsive() override;
- virtual void did_become_responsive() override;
-
- void set_unresponsive(bool);
- void destroy_window(Window&, Vector<i32>& destroyed_window_ids);
-
- virtual OwnPtr<Messages::WindowServer::GreetResponse> handle(const Messages::WindowServer::Greet&) override;
- virtual OwnPtr<Messages::WindowServer::CreateMenubarResponse> handle(const Messages::WindowServer::CreateMenubar&) override;
- virtual OwnPtr<Messages::WindowServer::DestroyMenubarResponse> handle(const Messages::WindowServer::DestroyMenubar&) override;
- virtual OwnPtr<Messages::WindowServer::CreateMenuResponse> handle(const Messages::WindowServer::CreateMenu&) override;
- virtual OwnPtr<Messages::WindowServer::DestroyMenuResponse> handle(const Messages::WindowServer::DestroyMenu&) override;
- virtual OwnPtr<Messages::WindowServer::AddMenuToMenubarResponse> handle(const Messages::WindowServer::AddMenuToMenubar&) override;
- virtual OwnPtr<Messages::WindowServer::SetApplicationMenubarResponse> handle(const Messages::WindowServer::SetApplicationMenubar&) override;
- virtual OwnPtr<Messages::WindowServer::AddMenuItemResponse> handle(const Messages::WindowServer::AddMenuItem&) override;
- virtual OwnPtr<Messages::WindowServer::AddMenuSeparatorResponse> handle(const Messages::WindowServer::AddMenuSeparator&) override;
- virtual OwnPtr<Messages::WindowServer::UpdateMenuItemResponse> handle(const Messages::WindowServer::UpdateMenuItem&) override;
- virtual OwnPtr<Messages::WindowServer::CreateWindowResponse> handle(const Messages::WindowServer::CreateWindow&) override;
- virtual OwnPtr<Messages::WindowServer::DestroyWindowResponse> handle(const Messages::WindowServer::DestroyWindow&) override;
- virtual OwnPtr<Messages::WindowServer::SetWindowTitleResponse> handle(const Messages::WindowServer::SetWindowTitle&) override;
- virtual OwnPtr<Messages::WindowServer::GetWindowTitleResponse> handle(const Messages::WindowServer::GetWindowTitle&) override;
- virtual OwnPtr<Messages::WindowServer::IsMaximizedResponse> handle(const Messages::WindowServer::IsMaximized&) override;
- virtual OwnPtr<Messages::WindowServer::SetWindowRectResponse> handle(const Messages::WindowServer::SetWindowRect&) override;
- virtual OwnPtr<Messages::WindowServer::GetWindowRectResponse> handle(const Messages::WindowServer::GetWindowRect&) override;
- virtual OwnPtr<Messages::WindowServer::GetWindowRectInMenubarResponse> handle(const Messages::WindowServer::GetWindowRectInMenubar&) override;
- virtual void handle(const Messages::WindowServer::InvalidateRect&) override;
- virtual void handle(const Messages::WindowServer::DidFinishPainting&) override;
- virtual OwnPtr<Messages::WindowServer::SetGlobalCursorTrackingResponse> handle(const Messages::WindowServer::SetGlobalCursorTracking&) override;
- virtual OwnPtr<Messages::WindowServer::SetWindowOpacityResponse> handle(const Messages::WindowServer::SetWindowOpacity&) override;
- virtual OwnPtr<Messages::WindowServer::SetWindowBackingStoreResponse> handle(const Messages::WindowServer::SetWindowBackingStore&) override;
- virtual void handle(const Messages::WindowServer::WM_SetActiveWindow&) override;
- virtual void handle(const Messages::WindowServer::WM_SetWindowMinimized&) override;
- virtual void handle(const Messages::WindowServer::WM_StartWindowResize&) override;
- virtual void handle(const Messages::WindowServer::WM_PopupWindowMenu&) override;
- virtual OwnPtr<Messages::WindowServer::SetWindowHasAlphaChannelResponse> handle(const Messages::WindowServer::SetWindowHasAlphaChannel&) override;
- virtual OwnPtr<Messages::WindowServer::MoveWindowToFrontResponse> handle(const Messages::WindowServer::MoveWindowToFront&) override;
- virtual OwnPtr<Messages::WindowServer::SetFullscreenResponse> handle(const Messages::WindowServer::SetFullscreen&) override;
- virtual void handle(const Messages::WindowServer::AsyncSetWallpaper&) override;
- virtual OwnPtr<Messages::WindowServer::SetBackgroundColorResponse> handle(const Messages::WindowServer::SetBackgroundColor&) override;
- virtual OwnPtr<Messages::WindowServer::SetWallpaperModeResponse> handle(const Messages::WindowServer::SetWallpaperMode&) override;
- virtual OwnPtr<Messages::WindowServer::GetWallpaperResponse> handle(const Messages::WindowServer::GetWallpaper&) override;
- virtual OwnPtr<Messages::WindowServer::SetResolutionResponse> handle(const Messages::WindowServer::SetResolution&) override;
- virtual OwnPtr<Messages::WindowServer::SetWindowCursorResponse> handle(const Messages::WindowServer::SetWindowCursor&) override;
- virtual OwnPtr<Messages::WindowServer::SetWindowCustomCursorResponse> handle(const Messages::WindowServer::SetWindowCustomCursor&) override;
- virtual OwnPtr<Messages::WindowServer::PopupMenuResponse> handle(const Messages::WindowServer::PopupMenu&) override;
- virtual OwnPtr<Messages::WindowServer::DismissMenuResponse> handle(const Messages::WindowServer::DismissMenu&) override;
- virtual OwnPtr<Messages::WindowServer::SetWindowIconBitmapResponse> handle(const Messages::WindowServer::SetWindowIconBitmap&) override;
- virtual void handle(const Messages::WindowServer::WM_SetWindowTaskbarRect&) override;
- virtual OwnPtr<Messages::WindowServer::StartDragResponse> handle(const Messages::WindowServer::StartDrag&) override;
- virtual OwnPtr<Messages::WindowServer::SetSystemMenuResponse> handle(const Messages::WindowServer::SetSystemMenu&) override;
- virtual OwnPtr<Messages::WindowServer::SetSystemThemeResponse> handle(const Messages::WindowServer::SetSystemTheme&) override;
- virtual OwnPtr<Messages::WindowServer::GetSystemThemeResponse> handle(const Messages::WindowServer::GetSystemTheme&) override;
- virtual OwnPtr<Messages::WindowServer::SetWindowBaseSizeAndSizeIncrementResponse> handle(const Messages::WindowServer::SetWindowBaseSizeAndSizeIncrement&) override;
- virtual OwnPtr<Messages::WindowServer::SetWindowResizeAspectRatioResponse> handle(const Messages::WindowServer::SetWindowResizeAspectRatio&) override;
- virtual void handle(const Messages::WindowServer::EnableDisplayLink&) override;
- virtual void handle(const Messages::WindowServer::DisableDisplayLink&) override;
- virtual void handle(const Messages::WindowServer::SetWindowProgress&) override;
- virtual void handle(const Messages::WindowServer::Pong&) override;
- virtual OwnPtr<Messages::WindowServer::GetGlobalCursorPositionResponse> handle(const Messages::WindowServer::GetGlobalCursorPosition&) override;
- virtual OwnPtr<Messages::WindowServer::SetMouseAccelerationResponse> handle(const Messages::WindowServer::SetMouseAcceleration&) override;
- virtual OwnPtr<Messages::WindowServer::GetMouseAccelerationResponse> handle(const Messages::WindowServer::GetMouseAcceleration&) override;
- virtual OwnPtr<Messages::WindowServer::SetScrollStepSizeResponse> handle(const Messages::WindowServer::SetScrollStepSize&) override;
- virtual OwnPtr<Messages::WindowServer::GetScrollStepSizeResponse> handle(const Messages::WindowServer::GetScrollStepSize&) override;
-
- Window* window_from_id(i32 window_id);
-
- HashMap<int, NonnullRefPtr<Window>> m_windows;
- HashMap<int, NonnullOwnPtr<MenuBar>> m_menubars;
- HashMap<int, NonnullRefPtr<Menu>> m_menus;
- WeakPtr<MenuBar> m_app_menubar;
-
- RefPtr<Core::Timer> m_ping_timer;
-
- int m_next_menubar_id { 10000 };
- int m_next_menu_id { 20000 };
- int m_next_window_id { 1982 };
-
- bool m_has_display_link { false };
- bool m_unresponsive { false };
-};
-
-}
diff --git a/Services/WindowServer/Compositor.cpp b/Services/WindowServer/Compositor.cpp
deleted file mode 100644
index 470a8e53a7..0000000000
--- a/Services/WindowServer/Compositor.cpp
+++ /dev/null
@@ -1,1040 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "Compositor.h"
-#include "ClientConnection.h"
-#include "Event.h"
-#include "EventLoop.h"
-#include "Screen.h"
-#include "Window.h"
-#include "WindowManager.h"
-#include <AK/Memory.h>
-#include <AK/ScopeGuard.h>
-#include <LibCore/Timer.h>
-#include <LibGfx/Font.h>
-#include <LibGfx/Painter.h>
-#include <LibGfx/StylePainter.h>
-#include <LibThread/BackgroundAction.h>
-
-//#define COMPOSE_DEBUG
-//#define OCCLUSIONS_DEBUG
-
-namespace WindowServer {
-
-Compositor& Compositor::the()
-{
- static Compositor s_the;
- return s_the;
-}
-
-static WallpaperMode mode_to_enum(const String& name)
-{
- if (name == "simple")
- return WallpaperMode::Simple;
- if (name == "tile")
- return WallpaperMode::Tile;
- if (name == "center")
- return WallpaperMode::Center;
- if (name == "scaled")
- return WallpaperMode::Scaled;
- return WallpaperMode::Simple;
-}
-
-Compositor::Compositor()
-{
- m_display_link_notify_timer = add<Core::Timer>(
- 1000 / 60, [this] {
- notify_display_links();
- });
- m_display_link_notify_timer->stop();
-
- m_compose_timer = Core::Timer::create_single_shot(
- 1000 / 60,
- [this] {
- compose();
- },
- this);
-
- m_immediate_compose_timer = Core::Timer::create_single_shot(
- 0,
- [this] {
- compose();
- },
- this);
-
- m_screen_can_set_buffer = Screen::the().can_set_buffer();
- init_bitmaps();
-}
-
-void Compositor::init_bitmaps()
-{
- auto& screen = Screen::the();
- auto size = screen.size();
-
- m_front_bitmap = Gfx::Bitmap::create_wrapper(Gfx::BitmapFormat::RGB32, size, screen.pitch(), screen.scanline(0));
-
- if (m_screen_can_set_buffer)
- m_back_bitmap = Gfx::Bitmap::create_wrapper(Gfx::BitmapFormat::RGB32, size, screen.pitch(), screen.scanline(size.height()));
- else
- m_back_bitmap = Gfx::Bitmap::create(Gfx::BitmapFormat::RGB32, size);
-
- m_temp_bitmap = Gfx::Bitmap::create(Gfx::BitmapFormat::RGB32, size);
-
- m_front_painter = make<Gfx::Painter>(*m_front_bitmap);
- m_back_painter = make<Gfx::Painter>(*m_back_bitmap);
- m_temp_painter = make<Gfx::Painter>(*m_temp_bitmap);
-
- m_buffers_are_flipped = false;
-
- invalidate_screen();
-}
-
-void Compositor::did_construct_window_manager(Badge<WindowManager>)
-{
- auto& wm = WindowManager::the();
- m_wallpaper_mode = mode_to_enum(wm.config()->read_entry("Background", "Mode", "simple"));
- m_custom_background_color = Color::from_string(wm.config()->read_entry("Background", "Color", ""));
-
- invalidate_screen();
- invalidate_occlusions();
- compose();
-}
-
-void Compositor::compose()
-{
- auto& wm = WindowManager::the();
- auto& ws = Screen::the();
-
- {
- auto& current_cursor = wm.active_cursor();
- if (m_current_cursor != &current_cursor)
- change_cursor(&current_cursor);
- }
-
- if (!m_invalidated_any) {
- // nothing dirtied since the last compose pass.
- return;
- }
-
- if (m_occlusions_dirty) {
- m_occlusions_dirty = false;
- recompute_occlusions();
- }
-
- auto dirty_screen_rects = move(m_dirty_screen_rects);
- dirty_screen_rects.add(m_last_geometry_label_damage_rect.intersected(ws.rect()));
- dirty_screen_rects.add(m_last_dnd_rect.intersected(ws.rect()));
- if (m_invalidated_cursor) {
- if (wm.dnd_client())
- dirty_screen_rects.add(wm.dnd_rect().intersected(ws.rect()));
- }
-
- // Mark window regions as dirty that need to be re-rendered
- wm.for_each_visible_window_from_back_to_front([&](Window& window) {
- auto frame_rect = window.frame().rect();
- for (auto& dirty_rect : dirty_screen_rects.rects()) {
- auto invalidate_rect = dirty_rect.intersected(frame_rect);
- if (!invalidate_rect.is_empty()) {
- auto inner_rect_offset = window.rect().location() - frame_rect.location();
- invalidate_rect.move_by(-(frame_rect.location() + inner_rect_offset));
- window.invalidate_no_notify(invalidate_rect);
- m_invalidated_window = true;
- }
- }
- window.prepare_dirty_rects();
- return IterationDecision::Continue;
- });
-
- // Any windows above or below a given window that need to be re-rendered
- // also require us to re-render that window's intersecting area, regardless
- // of whether that window has any dirty rectangles
- wm.for_each_visible_window_from_back_to_front([&](Window& window) {
- auto& transparency_rects = window.transparency_rects();
- if (transparency_rects.is_empty())
- return IterationDecision::Continue;
-
- auto frame_rect = window.frame().rect();
- auto& dirty_rects = window.dirty_rects();
- wm.for_each_visible_window_from_back_to_front([&](Window& w) {
- if (&w == &window)
- return IterationDecision::Continue;
- auto frame_rect2 = w.frame().rect();
- if (!frame_rect2.intersects(frame_rect))
- return IterationDecision::Continue;
- transparency_rects.for_each_intersected(w.dirty_rects(), [&](const Gfx::IntRect& intersected_dirty) {
- dirty_rects.add(intersected_dirty);
- return IterationDecision::Continue;
- });
- return IterationDecision::Continue;
- });
- return IterationDecision::Continue;
- });
-
- Color background_color = wm.palette().desktop_background();
- if (m_custom_background_color.has_value())
- background_color = m_custom_background_color.value();
-
-#ifdef COMPOSE_DEBUG
- dbg() << "COMPOSE: invalidated: window:" << m_invalidated_window << " cursor:" << m_invalidated_cursor << " any: " << m_invalidated_any;
- for (auto& r : dirty_screen_rects.rects())
- dbg() << "dirty screen: " << r;
-#endif
- Gfx::DisjointRectSet flush_rects;
- Gfx::DisjointRectSet flush_transparent_rects;
- Gfx::DisjointRectSet flush_special_rects;
- auto cursor_rect = current_cursor_rect();
- bool need_to_draw_cursor = false;
-
- auto check_restore_cursor_back = [&](const Gfx::IntRect& rect) {
- if (!need_to_draw_cursor && rect.intersects(cursor_rect)) {
- // Restore what's behind the cursor if anything touches the area of the cursor
- need_to_draw_cursor = true;
- restore_cursor_back();
- }
- };
-
- auto prepare_rect = [&](const Gfx::IntRect& rect) {
-#ifdef COMPOSE_DEBUG
- dbg() << " -> flush opaque: " << rect;
-#endif
- ASSERT(!flush_rects.intersects(rect));
- ASSERT(!flush_transparent_rects.intersects(rect));
- flush_rects.add(rect);
- check_restore_cursor_back(rect);
- };
-
- auto prepare_transparency_rect = [&](const Gfx::IntRect& rect) {
-#ifdef COMPOSE_DEBUG
- dbg() << " -> flush transparent: " << rect;
-#endif
- ASSERT(!flush_rects.intersects(rect));
- bool have_rect = false;
- for (auto& r : flush_transparent_rects.rects()) {
- if (r == rect) {
- have_rect = true;
- break;
- }
- }
-
- if (!have_rect) {
- flush_transparent_rects.add(rect);
- check_restore_cursor_back(rect);
- }
- };
-
- if (!m_cursor_back_bitmap || m_invalidated_cursor)
- check_restore_cursor_back(cursor_rect);
-
- auto back_painter = *m_back_painter;
- auto temp_painter = *m_temp_painter;
-
- auto paint_wallpaper = [&](Gfx::Painter& painter, const Gfx::IntRect& rect) {
- // FIXME: If the wallpaper is opaque, no need to fill with color!
- painter.fill_rect(rect, background_color);
- if (m_wallpaper) {
- if (m_wallpaper_mode == WallpaperMode::Simple) {
- painter.blit(rect.location(), *m_wallpaper, rect);
- } else if (m_wallpaper_mode == WallpaperMode::Center) {
- Gfx::IntPoint offset { ws.size().width() / 2 - m_wallpaper->size().width() / 2,
- ws.size().height() / 2 - m_wallpaper->size().height() / 2 };
- painter.blit_offset(rect.location(), *m_wallpaper,
- rect, offset);
- } else if (m_wallpaper_mode == WallpaperMode::Tile) {
- painter.draw_tiled_bitmap(rect, *m_wallpaper);
- } else if (m_wallpaper_mode == WallpaperMode::Scaled) {
- float hscale = (float)m_wallpaper->size().width() / (float)ws.size().width();
- float vscale = (float)m_wallpaper->size().height() / (float)ws.size().height();
-
- // TODO: this may look ugly, we should scale to a backing bitmap and then blit
- painter.blit_scaled(rect, *m_wallpaper, rect, hscale, vscale);
- } else {
- ASSERT_NOT_REACHED();
- }
- }
- };
-
- m_opaque_wallpaper_rects.for_each_intersected(dirty_screen_rects, [&](const Gfx::IntRect& render_rect) {
-#ifdef COMPOSE_DEBUG
- dbg() << " render wallpaper opaque: " << render_rect;
-#endif
- prepare_rect(render_rect);
- paint_wallpaper(back_painter, render_rect);
- return IterationDecision::Continue;
- });
-
- auto compose_window = [&](Window& window) -> IterationDecision {
- auto frame_rect = window.frame().rect();
- if (!frame_rect.intersects(ws.rect()))
- return IterationDecision::Continue;
- auto frame_rects = frame_rect.shatter(window.rect());
-
-#ifdef COMPOSE_DEBUG
- dbg() << " window " << window.title() << " frame rect: " << frame_rect;
-#endif
-
- RefPtr<Gfx::Bitmap> backing_store = window.backing_store();
- auto compose_window_rect = [&](Gfx::Painter& painter, const Gfx::IntRect& rect) {
- if (!window.is_fullscreen()) {
- rect.for_each_intersected(frame_rects, [&](const Gfx::IntRect& intersected_rect) {
- // TODO: Should optimize this to use a backing buffer
- Gfx::PainterStateSaver saver(painter);
- painter.add_clip_rect(intersected_rect);
-#ifdef COMPOSE_DEBUG
- dbg() << " render frame: " << intersected_rect;
-#endif
- window.frame().paint(painter);
- return IterationDecision::Continue;
- });
- }
-
- if (!backing_store) {
- if (window.is_opaque())
- painter.fill_rect(window.rect().intersected(rect), wm.palette().window());
- return;
- }
-
- // Decide where we would paint this window's backing store.
- // This is subtly different from widow.rect(), because window
- // size may be different from its backing store size. This
- // happens when the window has been resized and the client
- // has not yet attached a new backing store. In this case,
- // we want to try to blit the backing store at the same place
- // it was previously, and fill the rest of the window with its
- // background color.
- Gfx::IntRect backing_rect;
- backing_rect.set_size(backing_store->size());
- switch (WindowManager::the().resize_direction_of_window(window)) {
- case ResizeDirection::None:
- case ResizeDirection::Right:
- case ResizeDirection::Down:
- case ResizeDirection::DownRight:
- backing_rect.set_location(window.rect().location());
- break;
- case ResizeDirection::Left:
- case ResizeDirection::Up:
- case ResizeDirection::UpLeft:
- backing_rect.set_right_without_resize(window.rect().right());
- backing_rect.set_bottom_without_resize(window.rect().bottom());
- break;
- case ResizeDirection::UpRight:
- backing_rect.set_left(window.rect().left());
- backing_rect.set_bottom_without_resize(window.rect().bottom());
- break;
- case ResizeDirection::DownLeft:
- backing_rect.set_right_without_resize(window.rect().right());
- backing_rect.set_top(window.rect().top());
- break;
- }
-
- Gfx::IntRect dirty_rect_in_backing_coordinates = rect.intersected(window.rect())
- .intersected(backing_rect)
- .translated(-backing_rect.location());
-
- if (dirty_rect_in_backing_coordinates.is_empty())
- return;
- auto dst = backing_rect.location().translated(dirty_rect_in_backing_coordinates.location());
-
- if (window.client() && window.client()->is_unresponsive()) {
- painter.blit_filtered(dst, *backing_store, dirty_rect_in_backing_coordinates, [](Color src) {
- return src.to_grayscale().darkened(0.75f);
- });
- } else {
- painter.blit(dst, *backing_store, dirty_rect_in_backing_coordinates, window.opacity());
- }
-
- if (window.is_opaque()) {
- for (auto background_rect : window.rect().shatter(backing_rect))
- painter.fill_rect(background_rect, wm.palette().window());
- }
- };
-
- auto& dirty_rects = window.dirty_rects();
-#ifdef COMPOSE_DEBUG
- for (auto& dirty_rect : dirty_rects.rects())
- dbg() << " dirty: " << dirty_rect;
- for (auto& r : window.opaque_rects().rects())
- dbg() << " opaque: " << r;
- for (auto& r : window.transparency_rects().rects())
- dbg() << " transparent: " << r;
-#endif
-
- // Render opaque portions directly to the back buffer
- auto& opaque_rects = window.opaque_rects();
- if (!opaque_rects.is_empty()) {
- opaque_rects.for_each_intersected(dirty_rects, [&](const Gfx::IntRect& render_rect) {
-#ifdef COMPOSE_DEBUG
- dbg() << " render opaque: " << render_rect;
-#endif
- prepare_rect(render_rect);
- Gfx::PainterStateSaver saver(back_painter);
- back_painter.add_clip_rect(render_rect);
- compose_window_rect(back_painter, render_rect);
- return IterationDecision::Continue;
- });
- }
-
- // Render the wallpaper for any transparency directly covering
- // the wallpaper
- auto& transparency_wallpaper_rects = window.transparency_wallpaper_rects();
- if (!transparency_wallpaper_rects.is_empty()) {
- transparency_wallpaper_rects.for_each_intersected(dirty_rects, [&](const Gfx::IntRect& render_rect) {
-#ifdef COMPOSE_DEBUG
- dbg() << " render wallpaper: " << render_rect;
-#endif
- prepare_transparency_rect(render_rect);
- paint_wallpaper(temp_painter, render_rect);
- return IterationDecision::Continue;
- });
- }
- auto& transparency_rects = window.transparency_rects();
- if (!transparency_rects.is_empty()) {
- transparency_rects.for_each_intersected(dirty_rects, [&](const Gfx::IntRect& render_rect) {
-#ifdef COMPOSE_DEBUG
- dbg() << " render transparent: " << render_rect;
-#endif
- prepare_transparency_rect(render_rect);
- Gfx::PainterStateSaver saver(temp_painter);
- temp_painter.add_clip_rect(render_rect);
- compose_window_rect(temp_painter, render_rect);
- return IterationDecision::Continue;
- });
- }
- return IterationDecision::Continue;
- };
-
- // Paint the window stack.
- if (m_invalidated_window) {
- if (auto* fullscreen_window = wm.active_fullscreen_window()) {
- compose_window(*fullscreen_window);
- } else {
- wm.for_each_visible_window_from_back_to_front([&](Window& window) {
- compose_window(window);
- window.clear_dirty_rects();
- return IterationDecision::Continue;
- });
- }
-
- // Check that there are no overlapping transparent and opaque flush rectangles
- ASSERT(![&]() {
- for (auto& rect_transparent : flush_transparent_rects.rects()) {
- for (auto& rect_opaque : flush_rects.rects()) {
- if (rect_opaque.intersects(rect_transparent)) {
- dbg() << "Transparent rect " << rect_transparent << " overlaps opaque rect: " << rect_opaque << ": " << rect_opaque.intersected(rect_transparent);
- return true;
- }
- }
- }
- return false;
- }());
-
- // Copy anything rendered to the temporary buffer to the back buffer
- for (auto& rect : flush_transparent_rects.rects())
- back_painter.blit(rect.location(), *m_temp_bitmap, rect);
-
- Gfx::IntRect geometry_label_damage_rect;
- if (draw_geometry_label(geometry_label_damage_rect))
- flush_special_rects.add(geometry_label_damage_rect);
- }
-
- m_invalidated_any = false;
- m_invalidated_window = false;
- m_invalidated_cursor = false;
-
- if (wm.dnd_client()) {
- auto dnd_rect = wm.dnd_rect();
-
- // TODO: render once into a backing bitmap, then just blit...
- auto render_dnd = [&]() {
- back_painter.fill_rect(dnd_rect, wm.palette().selection().with_alpha(200));
- back_painter.draw_rect(dnd_rect, wm.palette().selection());
- if (!wm.dnd_text().is_empty()) {
- auto text_rect = dnd_rect;
- if (wm.dnd_bitmap())
- text_rect.move_by(wm.dnd_bitmap()->width() + 8, 0);
- back_painter.draw_text(text_rect, wm.dnd_text(), Gfx::TextAlignment::CenterLeft, wm.palette().selection_text());
- }
- if (wm.dnd_bitmap()) {
- back_painter.blit(dnd_rect.top_left().translated(4, 4), *wm.dnd_bitmap(), wm.dnd_bitmap()->rect());
- }
- };
-
- dirty_screen_rects.for_each_intersected(dnd_rect, [&](const Gfx::IntRect& render_rect) {
- Gfx::PainterStateSaver saver(back_painter);
- back_painter.add_clip_rect(render_rect);
- render_dnd();
- return IterationDecision::Continue;
- });
- flush_transparent_rects.for_each_intersected(dnd_rect, [&](const Gfx::IntRect& render_rect) {
- Gfx::PainterStateSaver saver(back_painter);
- back_painter.add_clip_rect(render_rect);
- render_dnd();
- return IterationDecision::Continue;
- });
- m_last_dnd_rect = dnd_rect;
- } else {
- if (!m_last_dnd_rect.is_empty()) {
- invalidate_screen(m_last_dnd_rect);
- m_last_dnd_rect = {};
- }
- }
-
- run_animations(flush_special_rects);
-
- if (need_to_draw_cursor) {
- flush_rects.add(cursor_rect);
- if (cursor_rect != m_last_cursor_rect)
- flush_rects.add(m_last_cursor_rect);
- draw_cursor(cursor_rect);
- }
-
- if (m_flash_flush) {
- for (auto& rect : flush_rects.rects())
- m_front_painter->fill_rect(rect, Color::Yellow);
- }
-
- if (m_screen_can_set_buffer)
- flip_buffers();
-
- for (auto& rect : flush_rects.rects())
- flush(rect);
- for (auto& rect : flush_transparent_rects.rects())
- flush(rect);
- for (auto& rect : flush_special_rects.rects())
- flush(rect);
-}
-
-void Compositor::flush(const Gfx::IntRect& a_rect)
-{
- auto rect = Gfx::IntRect::intersection(a_rect, Screen::the().rect());
-
- Gfx::RGBA32* front_ptr = m_front_bitmap->scanline(rect.y()) + rect.x();
- Gfx::RGBA32* back_ptr = m_back_bitmap->scanline(rect.y()) + rect.x();
- size_t pitch = m_back_bitmap->pitch();
-
- // NOTE: The meaning of a flush depends on whether we can flip buffers or not.
- //
- // If flipping is supported, flushing means that we've flipped, and now we
- // copy the changed bits from the front buffer to the back buffer, to keep
- // them in sync.
- //
- // If flipping is not supported, flushing means that we copy the changed
- // rects from the backing bitmap to the display framebuffer.
-
- Gfx::RGBA32* to_ptr;
- const Gfx::RGBA32* from_ptr;
-
- if (m_screen_can_set_buffer) {
- to_ptr = back_ptr;
- from_ptr = front_ptr;
- } else {
- to_ptr = front_ptr;
- from_ptr = back_ptr;
- }
-
- for (int y = 0; y < rect.height(); ++y) {
- fast_u32_copy(to_ptr, from_ptr, rect.width());
- from_ptr = (const Gfx::RGBA32*)((const u8*)from_ptr + pitch);
- to_ptr = (Gfx::RGBA32*)((u8*)to_ptr + pitch);
- }
-}
-
-void Compositor::invalidate_screen()
-{
- invalidate_screen(Screen::the().rect());
-}
-
-void Compositor::invalidate_screen(const Gfx::IntRect& screen_rect)
-{
- m_dirty_screen_rects.add(screen_rect.intersected(Screen::the().rect()));
-
- if (m_invalidated_any)
- return;
-
- m_invalidated_any = true;
- m_invalidated_window = true;
- start_compose_async_timer();
-}
-
-void Compositor::invalidate_window()
-{
- if (m_invalidated_window)
- return;
- m_invalidated_window = true;
- m_invalidated_any = true;
-
- start_compose_async_timer();
-}
-
-void Compositor::start_compose_async_timer()
-{
- // We delay composition by a timer interval, but to not affect latency too
- // much, if a pending compose is not already scheduled, we also schedule an
- // immediate compose the next spin of the event loop.
- if (!m_compose_timer->is_active()) {
- m_compose_timer->start();
- m_immediate_compose_timer->start();
- }
-}
-
-bool Compositor::set_background_color(const String& background_color)
-{
- auto color = Color::from_string(background_color);
- if (!color.has_value())
- return false;
-
- m_custom_background_color = color;
-
- auto& wm = WindowManager::the();
- wm.config()->write_entry("Background", "Color", background_color);
- bool ret_val = wm.config()->sync();
-
- if (ret_val)
- Compositor::invalidate_screen();
-
- return ret_val;
-}
-
-bool Compositor::set_wallpaper_mode(const String& mode)
-{
- auto& wm = WindowManager::the();
- wm.config()->write_entry("Background", "Mode", mode);
- bool ret_val = wm.config()->sync();
-
- if (ret_val) {
- m_wallpaper_mode = mode_to_enum(mode);
- Compositor::invalidate_screen();
- }
-
- return ret_val;
-}
-
-bool Compositor::set_wallpaper(const String& path, Function<void(bool)>&& callback)
-{
- LibThread::BackgroundAction<RefPtr<Gfx::Bitmap>>::create(
- [path] {
- return Gfx::Bitmap::load_from_file(path);
- },
-
- [this, path, callback = move(callback)](RefPtr<Gfx::Bitmap> bitmap) {
- m_wallpaper_path = path;
- m_wallpaper = move(bitmap);
- invalidate_screen();
- callback(true);
- });
- return true;
-}
-
-void Compositor::flip_buffers()
-{
- ASSERT(m_screen_can_set_buffer);
- swap(m_front_bitmap, m_back_bitmap);
- swap(m_front_painter, m_back_painter);
- Screen::the().set_buffer(m_buffers_are_flipped ? 0 : 1);
- m_buffers_are_flipped = !m_buffers_are_flipped;
-}
-
-void Compositor::run_animations(Gfx::DisjointRectSet& flush_rects)
-{
- static const int minimize_animation_steps = 10;
- auto& painter = *m_back_painter;
- Gfx::PainterStateSaver saver(painter);
- painter.set_draw_op(Gfx::Painter::DrawOp::Invert);
-
- WindowManager::the().for_each_window([&](Window& window) {
- if (window.in_minimize_animation()) {
- int animation_index = window.minimize_animation_index();
-
- auto from_rect = window.is_minimized() ? window.frame().rect() : window.taskbar_rect();
- auto to_rect = window.is_minimized() ? window.taskbar_rect() : window.frame().rect();
-
- float x_delta_per_step = (float)(from_rect.x() - to_rect.x()) / minimize_animation_steps;
- float y_delta_per_step = (float)(from_rect.y() - to_rect.y()) / minimize_animation_steps;
- float width_delta_per_step = (float)(from_rect.width() - to_rect.width()) / minimize_animation_steps;
- float height_delta_per_step = (float)(from_rect.height() - to_rect.height()) / minimize_animation_steps;
-
- Gfx::IntRect rect {
- from_rect.x() - (int)(x_delta_per_step * animation_index),
- from_rect.y() - (int)(y_delta_per_step * animation_index),
- from_rect.width() - (int)(width_delta_per_step * animation_index),
- from_rect.height() - (int)(height_delta_per_step * animation_index)
- };
-
-#ifdef MINIMIZE_ANIMATION_DEBUG
- dbg() << "Minimize animation from " << from_rect << " to " << to_rect << " frame# " << animation_index << " " << rect;
-#endif
-
- painter.draw_rect(rect, Color::Transparent); // Color doesn't matter, we draw inverted
- flush_rects.add(rect);
- invalidate_screen(rect);
-
- window.step_minimize_animation();
- if (window.minimize_animation_index() >= minimize_animation_steps)
- window.end_minimize_animation();
- }
- return IterationDecision::Continue;
- });
-}
-
-bool Compositor::set_resolution(int desired_width, int desired_height)
-{
- auto screen_rect = Screen::the().rect();
- if (screen_rect.width() == desired_width && screen_rect.height() == desired_height)
- return true;
-
- // Make sure it's impossible to set an invalid resolution
- if (!(desired_width >= 640 && desired_height >= 480)) {
- dbg() << "Compositor: Tried to set invalid resolution: " << desired_width << "x" << desired_height;
- return false;
- }
- bool success = Screen::the().set_resolution(desired_width, desired_height);
- init_bitmaps();
- invalidate_occlusions();
- compose();
- return success;
-}
-
-Gfx::IntRect Compositor::current_cursor_rect() const
-{
- auto& wm = WindowManager::the();
- auto& current_cursor = m_current_cursor ? *m_current_cursor : wm.active_cursor();
- return { Screen::the().cursor_location().translated(-current_cursor.params().hotspot()), current_cursor.size() };
-}
-
-void Compositor::invalidate_cursor(bool compose_immediately)
-{
- if (m_invalidated_cursor)
- return;
- m_invalidated_cursor = true;
- m_invalidated_any = true;
-
- if (compose_immediately)
- compose();
- else
- start_compose_async_timer();
-}
-
-bool Compositor::draw_geometry_label(Gfx::IntRect& geometry_label_damage_rect)
-{
- auto& wm = WindowManager::the();
- auto* window_being_moved_or_resized = wm.m_move_window ? wm.m_move_window.ptr() : (wm.m_resize_window ? wm.m_resize_window.ptr() : nullptr);
- if (!window_being_moved_or_resized) {
- m_last_geometry_label_damage_rect = {};
- return false;
- }
- auto geometry_string = window_being_moved_or_resized->rect().to_string();
- if (!window_being_moved_or_resized->size_increment().is_null()) {
- int width_steps = (window_being_moved_or_resized->width() - window_being_moved_or_resized->base_size().width()) / window_being_moved_or_resized->size_increment().width();
- int height_steps = (window_being_moved_or_resized->height() - window_being_moved_or_resized->base_size().height()) / window_being_moved_or_resized->size_increment().height();
- geometry_string = String::format("%s (%dx%d)", geometry_string.characters(), width_steps, height_steps);
- }
- auto geometry_label_rect = Gfx::IntRect { 0, 0, wm.font().width(geometry_string) + 16, wm.font().glyph_height() + 10 };
- geometry_label_rect.center_within(window_being_moved_or_resized->rect());
- auto& back_painter = *m_back_painter;
- back_painter.fill_rect(geometry_label_rect.translated(1, 1), Color(Color::Black).with_alpha(80));
- Gfx::StylePainter::paint_button(back_painter, geometry_label_rect.translated(-1, -1), wm.palette(), Gfx::ButtonStyle::Normal, false);
- back_painter.draw_text(geometry_label_rect.translated(-1, -1), geometry_string, Gfx::TextAlignment::Center, wm.palette().window_text());
-
- geometry_label_damage_rect = geometry_label_rect.inflated(2, 2);
- m_last_geometry_label_damage_rect = geometry_label_damage_rect;
- return true;
-}
-
-void Compositor::change_cursor(const Cursor* cursor)
-{
- if (m_current_cursor == cursor)
- return;
- m_current_cursor = cursor;
- m_current_cursor_frame = 0;
- if (m_cursor_timer) {
- m_cursor_timer->stop();
- m_cursor_timer = nullptr;
- }
- if (cursor && cursor->params().frames() > 1 && cursor->params().frame_ms() != 0) {
- m_cursor_timer = add<Core::Timer>(
- cursor->params().frame_ms(), [this, cursor] {
- if (m_current_cursor != cursor)
- return;
- auto frames = cursor->params().frames();
- if (++m_current_cursor_frame >= frames)
- m_current_cursor_frame = 0;
- invalidate_cursor(true);
- });
- }
-}
-
-void Compositor::draw_cursor(const Gfx::IntRect& cursor_rect)
-{
- auto& wm = WindowManager::the();
-
- if (!m_cursor_back_bitmap || m_cursor_back_bitmap->size() != cursor_rect.size()) {
- m_cursor_back_bitmap = Gfx::Bitmap::create(Gfx::BitmapFormat::RGB32, cursor_rect.size());
- m_cursor_back_painter = make<Gfx::Painter>(*m_cursor_back_bitmap);
- }
-
- auto& current_cursor = m_current_cursor ? *m_current_cursor : wm.active_cursor();
- m_cursor_back_painter->blit({ 0, 0 }, *m_back_bitmap, current_cursor.rect().translated(cursor_rect.location()).intersected(Screen::the().rect()));
- auto& back_painter = *m_back_painter;
- back_painter.blit(cursor_rect.location(), current_cursor.bitmap(), current_cursor.source_rect(m_current_cursor_frame));
-
- m_last_cursor_rect = cursor_rect;
-}
-
-void Compositor::restore_cursor_back()
-{
- if (!m_cursor_back_bitmap)
- return;
-
- m_back_painter->blit(m_last_cursor_rect.location().constrained(Screen::the().rect()), *m_cursor_back_bitmap, { { 0, 0 }, m_last_cursor_rect.intersected(Screen::the().rect()).size() });
-}
-
-void Compositor::notify_display_links()
-{
- ClientConnection::for_each_client([](auto& client) {
- client.notify_display_link({});
- });
-}
-
-void Compositor::increment_display_link_count(Badge<ClientConnection>)
-{
- ++m_display_link_count;
- if (m_display_link_count == 1)
- m_display_link_notify_timer->start();
-}
-
-void Compositor::decrement_display_link_count(Badge<ClientConnection>)
-{
- ASSERT(m_display_link_count);
- --m_display_link_count;
- if (!m_display_link_count)
- m_display_link_notify_timer->stop();
-}
-
-bool Compositor::any_opaque_window_above_this_one_contains_rect(const Window& a_window, const Gfx::IntRect& rect)
-{
- bool found_containing_window = false;
- bool checking = false;
- WindowManager::the().for_each_visible_window_from_back_to_front([&](Window& window) {
- if (&window == &a_window) {
- checking = true;
- return IterationDecision::Continue;
- }
- if (!checking)
- return IterationDecision::Continue;
- if (!window.is_visible())
- return IterationDecision::Continue;
- if (window.is_minimized())
- return IterationDecision::Continue;
- if (!window.is_opaque())
- return IterationDecision::Continue;
- if (window.frame().rect().contains(rect)) {
- found_containing_window = true;
- return IterationDecision::Break;
- }
- return IterationDecision::Continue;
- });
- return found_containing_window;
-};
-
-void Compositor::recompute_occlusions()
-{
- auto& wm = WindowManager::the();
- wm.for_each_visible_window_from_back_to_front([&](Window& window) {
- if (wm.m_switcher.is_visible()) {
- window.set_occluded(false);
- } else {
- if (any_opaque_window_above_this_one_contains_rect(window, window.frame().rect()))
- window.set_occluded(true);
- else
- window.set_occluded(false);
- }
- return IterationDecision::Continue;
- });
-
-#ifdef OCCLUSIONS_DEBUG
- dbgln("OCCLUSIONS:");
-#endif
-
- auto screen_rect = Screen::the().rect();
-
- if (auto* fullscreen_window = wm.active_fullscreen_window()) {
- WindowManager::the().for_each_visible_window_from_front_to_back([&](Window& w) {
- auto& visible_opaque = w.opaque_rects();
- auto& transparency_rects = w.transparency_rects();
- auto& transparency_wallpaper_rects = w.transparency_wallpaper_rects();
- if (&w == fullscreen_window) {
- if (w.is_opaque()) {
- visible_opaque = screen_rect;
- transparency_rects.clear();
- transparency_wallpaper_rects.clear();
- } else {
- visible_opaque.clear();
- transparency_rects = screen_rect;
- transparency_wallpaper_rects = screen_rect;
- }
- } else {
- visible_opaque.clear();
- transparency_rects.clear();
- transparency_wallpaper_rects.clear();
- }
- return IterationDecision::Continue;
- });
-
- m_opaque_wallpaper_rects.clear();
- } else {
- Gfx::DisjointRectSet visible_rects(screen_rect);
- bool have_transparent = false;
- WindowManager::the().for_each_visible_window_from_front_to_back([&](Window& w) {
- auto window_frame_rect = w.frame().rect().intersected(screen_rect);
- w.transparency_wallpaper_rects().clear();
- auto& visible_opaque = w.opaque_rects();
- auto& transparency_rects = w.transparency_rects();
- if (w.is_minimized() || window_frame_rect.is_empty()) {
- visible_opaque.clear();
- transparency_rects.clear();
- return IterationDecision::Continue;
- }
-
- Gfx::DisjointRectSet opaque_covering;
- if (w.is_opaque()) {
- visible_opaque = visible_rects.intersected(window_frame_rect);
- transparency_rects.clear();
- } else {
- visible_opaque.clear();
- transparency_rects = visible_rects.intersected(window_frame_rect);
- }
-
- bool found_this_window = false;
- WindowManager::the().for_each_visible_window_from_back_to_front([&](Window& w2) {
- if (!found_this_window) {
- if (&w == &w2)
- found_this_window = true;
- return IterationDecision::Continue;
- }
-
- if (w2.is_minimized())
- return IterationDecision::Continue;
- auto window_frame_rect2 = w2.frame().rect().intersected(screen_rect);
- auto covering_rect = window_frame_rect2.intersected(window_frame_rect);
- if (covering_rect.is_empty())
- return IterationDecision::Continue;
-
- if (w2.is_opaque()) {
- opaque_covering.add(covering_rect);
- if (opaque_covering.contains(window_frame_rect)) {
- // This window is entirely covered by another opaque window
- visible_opaque.clear();
- transparency_rects.clear();
- return IterationDecision::Break;
- }
-
- if (!visible_opaque.is_empty()) {
- auto uncovered_opaque = visible_opaque.shatter(covering_rect);
- visible_opaque = move(uncovered_opaque);
- }
-
- if (!transparency_rects.is_empty()) {
- auto uncovered_transparency = transparency_rects.shatter(covering_rect);
- transparency_rects = move(uncovered_transparency);
- }
- } else {
- visible_rects.for_each_intersected(covering_rect, [&](const Gfx::IntRect& intersected) {
- transparency_rects.add(intersected);
- if (!visible_opaque.is_empty()) {
- auto uncovered_opaque = visible_opaque.shatter(intersected);
- visible_opaque = move(uncovered_opaque);
- }
- return IterationDecision::Continue;
- });
- }
-
- return IterationDecision::Continue;
- });
-
- if (!transparency_rects.is_empty())
- have_transparent = true;
-
- ASSERT(!visible_opaque.intersects(transparency_rects));
-
- if (w.is_opaque()) {
- // Determine visible area for the window below
- auto visible_rects_below_window = visible_rects.shatter(window_frame_rect);
- visible_rects = move(visible_rects_below_window);
- }
- return IterationDecision::Continue;
- });
-
- if (have_transparent) {
- // Determine what transparent window areas need to render the wallpaper first
- WindowManager::the().for_each_visible_window_from_back_to_front([&](Window& w) {
- auto& transparency_wallpaper_rects = w.transparency_wallpaper_rects();
- if (w.is_opaque() || w.is_minimized()) {
- transparency_wallpaper_rects.clear();
- return IterationDecision::Continue;
- }
- Gfx::DisjointRectSet& transparency_rects = w.transparency_rects();
- if (transparency_rects.is_empty()) {
- transparency_wallpaper_rects.clear();
- return IterationDecision::Continue;
- }
-
- transparency_wallpaper_rects = visible_rects.intersected(transparency_rects);
-
- auto remaining_visible = visible_rects.shatter(transparency_wallpaper_rects);
- visible_rects = move(remaining_visible);
- return IterationDecision::Continue;
- });
- }
-
- m_opaque_wallpaper_rects = move(visible_rects);
- }
-
-#ifdef OCCLUSIONS_DEBUG
- for (auto& r : m_opaque_wallpaper_rects.rects())
- dbg() << " wallpaper opaque: " << r;
-#endif
-
- wm.for_each_visible_window_from_back_to_front([&](Window& w) {
- auto window_frame_rect = w.frame().rect().intersected(screen_rect);
- if (w.is_minimized() || window_frame_rect.is_empty())
- return IterationDecision::Continue;
-
-#ifdef OCCLUSIONS_DEBUG
- dbg() << " Window " << w.title() << " frame rect: " << window_frame_rect;
- for (auto& r : w.opaque_rects().rects())
- dbg() << " opaque: " << r;
- for (auto& r : w.transparency_wallpaper_rects().rects())
- dbg() << " transparent wallpaper: " << r;
- for (auto& r : w.transparency_rects().rects())
- dbg() << " transparent: " << r;
-#endif
- ASSERT(!w.opaque_rects().intersects(m_opaque_wallpaper_rects));
- ASSERT(!w.transparency_rects().intersects(m_opaque_wallpaper_rects));
- ASSERT(!w.transparency_wallpaper_rects().intersects(m_opaque_wallpaper_rects));
- return IterationDecision::Continue;
- });
-}
-
-}
diff --git a/Services/WindowServer/Compositor.h b/Services/WindowServer/Compositor.h
deleted file mode 100644
index 1e6a3e2014..0000000000
--- a/Services/WindowServer/Compositor.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <AK/OwnPtr.h>
-#include <AK/RefPtr.h>
-#include <LibCore/Object.h>
-#include <LibGfx/Color.h>
-#include <LibGfx/DisjointRectSet.h>
-
-namespace WindowServer {
-
-class ClientConnection;
-class Cursor;
-class Window;
-class WindowManager;
-
-enum class WallpaperMode {
- Simple,
- Tile,
- Center,
- Scaled,
- Unchecked
-};
-
-class Compositor final : public Core::Object {
- C_OBJECT(Compositor)
-public:
- static Compositor& the();
-
- void compose();
- void invalidate_window();
- void invalidate_screen();
- void invalidate_screen(const Gfx::IntRect&);
-
- bool set_resolution(int desired_width, int desired_height);
-
- bool set_background_color(const String& background_color);
-
- bool set_wallpaper_mode(const String& mode);
-
- bool set_wallpaper(const String& path, Function<void(bool)>&& callback);
- String wallpaper_path() const { return m_wallpaper_path; }
-
- void invalidate_cursor(bool = false);
- Gfx::IntRect current_cursor_rect() const;
-
- void increment_display_link_count(Badge<ClientConnection>);
- void decrement_display_link_count(Badge<ClientConnection>);
-
- void invalidate_occlusions() { m_occlusions_dirty = true; }
-
- void did_construct_window_manager(Badge<WindowManager>);
-
-private:
- Compositor();
- void init_bitmaps();
- void flip_buffers();
- void flush(const Gfx::IntRect&);
- void draw_menubar();
- void run_animations(Gfx::DisjointRectSet&);
- void notify_display_links();
- void start_compose_async_timer();
- void recompute_occlusions();
- bool any_opaque_window_above_this_one_contains_rect(const Window&, const Gfx::IntRect&);
- void change_cursor(const Cursor*);
- void draw_cursor(const Gfx::IntRect&);
- void restore_cursor_back();
- bool draw_geometry_label(Gfx::IntRect&);
-
- RefPtr<Core::Timer> m_compose_timer;
- RefPtr<Core::Timer> m_immediate_compose_timer;
- bool m_flash_flush { false };
- bool m_buffers_are_flipped { false };
- bool m_screen_can_set_buffer { false };
- bool m_occlusions_dirty { true };
- bool m_invalidated_any { true };
- bool m_invalidated_window { false };
- bool m_invalidated_cursor { false };
-
- RefPtr<Gfx::Bitmap> m_front_bitmap;
- RefPtr<Gfx::Bitmap> m_back_bitmap;
- RefPtr<Gfx::Bitmap> m_temp_bitmap;
- OwnPtr<Gfx::Painter> m_back_painter;
- OwnPtr<Gfx::Painter> m_front_painter;
- OwnPtr<Gfx::Painter> m_temp_painter;
-
- Gfx::DisjointRectSet m_dirty_screen_rects;
- Gfx::DisjointRectSet m_opaque_wallpaper_rects;
-
- RefPtr<Gfx::Bitmap> m_cursor_back_bitmap;
- OwnPtr<Gfx::Painter> m_cursor_back_painter;
- Gfx::IntRect m_last_cursor_rect;
- Gfx::IntRect m_last_dnd_rect;
- Gfx::IntRect m_last_geometry_label_damage_rect;
-
- String m_wallpaper_path { "" };
- WallpaperMode m_wallpaper_mode { WallpaperMode::Unchecked };
- RefPtr<Gfx::Bitmap> m_wallpaper;
-
- const Cursor* m_current_cursor { nullptr };
- unsigned m_current_cursor_frame { 0 };
- RefPtr<Core::Timer> m_cursor_timer;
-
- RefPtr<Core::Timer> m_display_link_notify_timer;
- size_t m_display_link_count { 0 };
-
- Optional<Gfx::Color> m_custom_background_color;
-};
-
-}
diff --git a/Services/WindowServer/Cursor.cpp b/Services/WindowServer/Cursor.cpp
deleted file mode 100644
index db18aa4281..0000000000
--- a/Services/WindowServer/Cursor.cpp
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <AK/LexicalPath.h>
-#include <WindowServer/Cursor.h>
-#include <WindowServer/WindowManager.h>
-
-namespace WindowServer {
-
-CursorParams CursorParams::parse_from_file_name(const StringView& cursor_path, const Gfx::IntPoint& default_hotspot)
-{
- LexicalPath path(cursor_path);
- if (!path.is_valid()) {
- dbgln("Cannot parse invalid cursor path, use default cursor params");
- return { default_hotspot };
- }
- auto file_title = path.title();
- auto last_dot_in_title = StringView(file_title).find_last_of('.');
- if (!last_dot_in_title.has_value() || last_dot_in_title.value() == 0) {
- // No encoded params in filename. Not an error, we'll just use defaults
- return { default_hotspot };
- }
- auto params_str = file_title.substring_view(last_dot_in_title.value() + 1);
-
- CursorParams params(default_hotspot);
- for (size_t i = 0; i + 1 < params_str.length();) {
- auto property = params_str[i++];
-
- auto value = [&]() -> Optional<size_t> {
- size_t k = i;
- while (k < params_str.length()) {
- auto ch = params_str[k];
- if (ch < '0' || ch > '9')
- break;
- k++;
- }
- if (k == i)
- return {};
- auto parsed_number = params_str.substring_view(i, k - i).to_uint();
- if (!parsed_number.has_value())
- return {};
- i = k;
- return parsed_number.value();
- }();
- if (!value.has_value()) {
- dbg() << "Failed to parse value for property '" << property << "' from parsed cursor path: " << cursor_path;
- return { default_hotspot };
- }
- switch (property) {
- case 'x':
- params.m_hotspot.set_x(value.value());
- params.m_have_hotspot = true;
- break;
- case 'y':
- params.m_hotspot.set_y(value.value());
- params.m_have_hotspot = true;
- break;
- case 'f':
- if (value.value() > 1)
- params.m_frames = value.value();
- break;
- case 't':
- if (value.value() >= 100 && value.value() <= 1000)
- params.m_frame_ms = value.value();
- else
- dbgln("Cursor frame rate outside of valid range (100-1000ms)");
- break;
- default:
- dbg() << "Ignore unknown property '" << property << "' with value " << value.value() << " parsed from cursor path: " << cursor_path;
- return { default_hotspot };
- }
- }
- return params;
-}
-
-CursorParams CursorParams::constrained(const Gfx::Bitmap& bitmap) const
-{
- CursorParams params(*this);
- auto rect = bitmap.rect();
- if (params.m_frames > 1) {
- if (rect.width() % params.m_frames == 0) {
- rect.set_width(rect.width() / (int)params.m_frames);
- } else {
- dbg() << "Cannot divide cursor dimensions " << rect << " into " << params.m_frames << " frames";
- params.m_frames = 1;
- }
- }
- if (params.m_have_hotspot)
- params.m_hotspot = params.m_hotspot.constrained(rect);
- else
- params.m_hotspot = rect.center();
- return params;
-}
-
-Cursor::Cursor(NonnullRefPtr<Gfx::Bitmap>&& bitmap, const CursorParams& cursor_params)
- : m_bitmap(move(bitmap))
- , m_params(cursor_params.constrained(*m_bitmap))
- , m_rect(m_bitmap->rect())
-{
- if (m_params.frames() > 1) {
- ASSERT(m_rect.width() % m_params.frames() == 0);
- m_rect.set_width(m_rect.width() / m_params.frames());
- }
-}
-
-Cursor::~Cursor()
-{
-}
-
-NonnullRefPtr<Cursor> Cursor::create(NonnullRefPtr<Gfx::Bitmap>&& bitmap)
-{
- auto hotspot = bitmap->rect().center();
- return adopt(*new Cursor(move(bitmap), CursorParams(hotspot)));
-}
-
-NonnullRefPtr<Cursor> Cursor::create(NonnullRefPtr<Gfx::Bitmap>&& bitmap, const StringView& filename)
-{
- auto default_hotspot = bitmap->rect().center();
- return adopt(*new Cursor(move(bitmap), CursorParams::parse_from_file_name(filename, default_hotspot)));
-}
-
-RefPtr<Cursor> Cursor::create(Gfx::StandardCursor standard_cursor)
-{
- switch (standard_cursor) {
- case Gfx::StandardCursor::None:
- return nullptr;
- case Gfx::StandardCursor::Hidden:
- return WindowManager::the().hidden_cursor();
- case Gfx::StandardCursor::Arrow:
- return WindowManager::the().arrow_cursor();
- case Gfx::StandardCursor::Crosshair:
- return WindowManager::the().crosshair_cursor();
- case Gfx::StandardCursor::IBeam:
- return WindowManager::the().i_beam_cursor();
- case Gfx::StandardCursor::ResizeHorizontal:
- return WindowManager::the().resize_horizontally_cursor();
- case Gfx::StandardCursor::ResizeVertical:
- return WindowManager::the().resize_vertically_cursor();
- case Gfx::StandardCursor::ResizeDiagonalTLBR:
- return WindowManager::the().resize_diagonally_tlbr_cursor();
- case Gfx::StandardCursor::ResizeDiagonalBLTR:
- return WindowManager::the().resize_diagonally_bltr_cursor();
- case Gfx::StandardCursor::ResizeColumn:
- return WindowManager::the().resize_column_cursor();
- case Gfx::StandardCursor::ResizeRow:
- return WindowManager::the().resize_row_cursor();
- case Gfx::StandardCursor::Hand:
- return WindowManager::the().hand_cursor();
- case Gfx::StandardCursor::Help:
- return WindowManager::the().help_cursor();
- case Gfx::StandardCursor::Drag:
- return WindowManager::the().drag_cursor();
- case Gfx::StandardCursor::Move:
- return WindowManager::the().move_cursor();
- case Gfx::StandardCursor::Wait:
- return WindowManager::the().wait_cursor();
- default:
- ASSERT_NOT_REACHED();
- }
-}
-
-}
diff --git a/Services/WindowServer/Cursor.h b/Services/WindowServer/Cursor.h
deleted file mode 100644
index efe014a735..0000000000
--- a/Services/WindowServer/Cursor.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <LibGfx/Bitmap.h>
-#include <LibGfx/StandardCursor.h>
-
-namespace WindowServer {
-
-class CursorParams {
-public:
- static CursorParams parse_from_file_name(const StringView&, const Gfx::IntPoint&);
- CursorParams(const Gfx::IntPoint& hotspot)
- : m_hotspot(hotspot)
- {
- }
- CursorParams constrained(const Gfx::Bitmap&) const;
-
- const Gfx::IntPoint& hotspot() const { return m_hotspot; }
- unsigned frames() const { return m_frames; }
- unsigned frame_ms() const { return m_frame_ms; }
-
-private:
- CursorParams() = default;
- Gfx::IntPoint m_hotspot;
- unsigned m_frames { 1 };
- unsigned m_frame_ms { 0 };
- bool m_have_hotspot { false };
-};
-
-class Cursor : public RefCounted<Cursor> {
-public:
- static NonnullRefPtr<Cursor> create(NonnullRefPtr<Gfx::Bitmap>&&, const StringView&);
- static NonnullRefPtr<Cursor> create(NonnullRefPtr<Gfx::Bitmap>&&);
- static RefPtr<Cursor> create(Gfx::StandardCursor);
- ~Cursor();
-
- const CursorParams& params() const { return m_params; }
- const Gfx::Bitmap& bitmap() const { return *m_bitmap; }
-
- Gfx::IntRect source_rect(unsigned frame) const
- {
- return m_rect.translated(frame * m_rect.width(), 0);
- }
-
- Gfx::IntRect rect() const { return m_rect; }
- Gfx::IntSize size() const { return m_rect.size(); }
-
-private:
- Cursor(NonnullRefPtr<Gfx::Bitmap>&&, const CursorParams&);
-
- RefPtr<Gfx::Bitmap> m_bitmap;
- CursorParams m_params;
- Gfx::IntRect m_rect;
-};
-
-}
diff --git a/Services/WindowServer/Event.h b/Services/WindowServer/Event.h
deleted file mode 100644
index e82df2d4c9..0000000000
--- a/Services/WindowServer/Event.h
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <AK/String.h>
-#include <Kernel/API/KeyCode.h>
-#include <LibCore/Event.h>
-#include <LibCore/MimeData.h>
-#include <LibGfx/Rect.h>
-#include <WindowServer/Cursor.h>
-#include <WindowServer/WindowType.h>
-
-namespace WindowServer {
-
-class Event : public Core::Event {
-public:
- enum Type {
- Invalid = 3000,
- MouseMove,
- MouseDown,
- MouseDoubleClick,
- MouseUp,
- MouseWheel,
- WindowEntered,
- WindowLeft,
- KeyDown,
- KeyUp,
- WindowActivated,
- WindowDeactivated,
- WindowInputEntered,
- WindowInputLeft,
- WindowCloseRequest,
- WindowResized,
- };
-
- Event() { }
- explicit Event(Type type)
- : Core::Event(type)
- {
- }
- virtual ~Event() { }
-
- bool is_mouse_event() const { return type() == MouseMove || type() == MouseDown || type() == MouseDoubleClick || type() == MouseUp || type() == MouseWheel; }
- bool is_key_event() const { return type() == KeyUp || type() == KeyDown; }
-};
-
-enum class MouseButton : u8 {
- None = 0,
- Left = 1,
- Right = 2,
- Middle = 4,
- Back = 8,
- Forward = 16,
-};
-
-class KeyEvent final : public Event {
-public:
- KeyEvent(Type type, int key, u32 code_point, u8 modifiers, u32 scancode)
- : Event(type)
- , m_key(key)
- , m_code_point(code_point)
- , m_modifiers(modifiers)
- , m_scancode(scancode)
- {
- }
-
- int key() const { return m_key; }
- bool ctrl() const { return m_modifiers & Mod_Ctrl; }
- bool alt() const { return m_modifiers & Mod_Alt; }
- bool shift() const { return m_modifiers & Mod_Shift; }
- bool logo() const { return m_modifiers & Mod_Logo; }
- u8 modifiers() const { return m_modifiers; }
- u32 code_point() const { return m_code_point; }
- u32 scancode() const { return m_scancode; }
-
-private:
- friend class EventLoop;
- friend class Screen;
- int m_key { 0 };
- u32 m_code_point { 0 };
- u8 m_modifiers { 0 };
- u32 m_scancode { 0 };
-};
-
-class MouseEvent final : public Event {
-public:
- MouseEvent(Type type, const Gfx::IntPoint& position, unsigned buttons, MouseButton button, unsigned modifiers, int wheel_delta = 0)
- : Event(type)
- , m_position(position)
- , m_buttons(buttons)
- , m_button(button)
- , m_modifiers(modifiers)
- , m_wheel_delta(wheel_delta)
- {
- }
-
- const Gfx::IntPoint& position() const { return m_position; }
- int x() const { return m_position.x(); }
- int y() const { return m_position.y(); }
- MouseButton button() const { return m_button; }
- unsigned buttons() const { return m_buttons; }
- unsigned modifiers() const { return m_modifiers; }
- int wheel_delta() const { return m_wheel_delta; }
- bool is_drag() const { return m_drag; }
-
- Vector<String> mime_types() const
- {
- if (!m_mime_data)
- return {};
- return m_mime_data->formats();
- }
-
- void set_drag(bool b) { m_drag = b; }
- void set_mime_data(const Core::MimeData& mime_data) { m_mime_data = mime_data; }
-
- MouseEvent translated(const Gfx::IntPoint& delta) const { return MouseEvent((Type)type(), m_position.translated(delta), m_buttons, m_button, m_modifiers, m_wheel_delta); }
-
-private:
- Gfx::IntPoint m_position;
- unsigned m_buttons { 0 };
- MouseButton m_button { MouseButton::None };
- unsigned m_modifiers { 0 };
- int m_wheel_delta { 0 };
- bool m_drag { false };
- RefPtr<const Core::MimeData> m_mime_data;
-};
-
-class ResizeEvent final : public Event {
-public:
- ResizeEvent(const Gfx::IntRect& rect)
- : Event(Event::WindowResized)
- , m_rect(rect)
- {
- }
-
- const Gfx::IntRect& rect() const { return m_rect; }
-
-private:
- Gfx::IntRect m_rect;
-};
-
-}
diff --git a/Services/WindowServer/EventLoop.cpp b/Services/WindowServer/EventLoop.cpp
deleted file mode 100644
index 21dae58823..0000000000
--- a/Services/WindowServer/EventLoop.cpp
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <Kernel/API/MousePacket.h>
-#include <LibCore/LocalSocket.h>
-#include <LibCore/Object.h>
-#include <WindowServer/ClientConnection.h>
-#include <WindowServer/Cursor.h>
-#include <WindowServer/Event.h>
-#include <WindowServer/EventLoop.h>
-#include <WindowServer/Screen.h>
-#include <WindowServer/WindowManager.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <sys/select.h>
-#include <sys/socket.h>
-#include <sys/time.h>
-#include <time.h>
-#include <unistd.h>
-
-//#define WSMESSAGELOOP_DEBUG
-
-namespace WindowServer {
-
-EventLoop::EventLoop()
- : m_server(Core::LocalServer::construct())
-{
- m_keyboard_fd = open("/dev/keyboard", O_RDONLY | O_NONBLOCK | O_CLOEXEC);
- m_mouse_fd = open("/dev/mouse", O_RDONLY | O_NONBLOCK | O_CLOEXEC);
-
- bool ok = m_server->take_over_from_system_server();
- ASSERT(ok);
-
- m_server->on_ready_to_accept = [this] {
- auto client_socket = m_server->accept();
- if (!client_socket) {
- dbgln("WindowServer: accept failed.");
- return;
- }
- static int s_next_client_id = 0;
- int client_id = ++s_next_client_id;
- IPC::new_client_connection<ClientConnection>(client_socket.release_nonnull(), client_id);
- };
-
- ASSERT(m_keyboard_fd >= 0);
- ASSERT(m_mouse_fd >= 0);
-
- m_keyboard_notifier = Core::Notifier::construct(m_keyboard_fd, Core::Notifier::Read);
- m_keyboard_notifier->on_ready_to_read = [this] { drain_keyboard(); };
-
- m_mouse_notifier = Core::Notifier::construct(m_mouse_fd, Core::Notifier::Read);
- m_mouse_notifier->on_ready_to_read = [this] { drain_mouse(); };
-}
-
-EventLoop::~EventLoop()
-{
-}
-
-void EventLoop::drain_mouse()
-{
- auto& screen = Screen::the();
- MousePacket state;
- state.buttons = screen.mouse_button_state();
- unsigned buttons = state.buttons;
- MousePacket packets[32];
-
- ssize_t nread = read(m_mouse_fd, &packets, sizeof(packets));
- if (nread < 0) {
- perror("EventLoop::drain_mouse read");
- return;
- }
- size_t npackets = nread / sizeof(MousePacket);
- if (!npackets)
- return;
- for (size_t i = 0; i < npackets; ++i) {
- auto& packet = packets[i];
-#ifdef WSMESSAGELOOP_DEBUG
- dbgln("EventLoop: Mouse X {}, Y {}, Z {}, relative={}", packet.x, packet.y, packet.z, packet.is_relative);
-#endif
- buttons = packet.buttons;
-
- state.is_relative = packet.is_relative;
- if (packet.is_relative) {
- state.x += packet.x;
- state.y -= packet.y;
- state.z += packet.z;
- } else {
- state.x = packet.x;
- state.y = packet.y;
- state.z += packet.z;
- }
-
- if (buttons != state.buttons) {
- state.buttons = buttons;
-#ifdef WSMESSAGELOOP_DEBUG
- dbgln("EventLoop: Mouse Button Event");
-#endif
- screen.on_receive_mouse_data(state);
- if (state.is_relative) {
- state.x = 0;
- state.y = 0;
- state.z = 0;
- }
- }
- }
- if (state.is_relative && (state.x || state.y || state.z))
- screen.on_receive_mouse_data(state);
- if (!state.is_relative)
- screen.on_receive_mouse_data(state);
-}
-
-void EventLoop::drain_keyboard()
-{
- auto& screen = Screen::the();
- for (;;) {
- ::KeyEvent event;
- ssize_t nread = read(m_keyboard_fd, (u8*)&event, sizeof(::KeyEvent));
- if (nread == 0)
- break;
- ASSERT(nread == sizeof(::KeyEvent));
- screen.on_receive_keyboard_data(event);
- }
-}
-
-}
diff --git a/Services/WindowServer/EventLoop.h b/Services/WindowServer/EventLoop.h
deleted file mode 100644
index b476b5e639..0000000000
--- a/Services/WindowServer/EventLoop.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <AK/ByteBuffer.h>
-#include <LibCore/EventLoop.h>
-#include <LibCore/LocalServer.h>
-#include <LibCore/Notifier.h>
-
-namespace WindowServer {
-
-class ClientConnection;
-
-class EventLoop {
-public:
- EventLoop();
- virtual ~EventLoop();
-
- int exec() { return m_event_loop.exec(); }
-
-private:
- void drain_mouse();
- void drain_keyboard();
-
- Core::EventLoop m_event_loop;
- int m_keyboard_fd { -1 };
- RefPtr<Core::Notifier> m_keyboard_notifier;
- int m_mouse_fd { -1 };
- RefPtr<Core::Notifier> m_mouse_notifier;
- RefPtr<Core::LocalServer> m_server;
-};
-
-}
diff --git a/Services/WindowServer/Menu.cpp b/Services/WindowServer/Menu.cpp
deleted file mode 100644
index 4d204406c2..0000000000
--- a/Services/WindowServer/Menu.cpp
+++ /dev/null
@@ -1,568 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * Copyright (c) 2020, Shannon Booth <shannon.ml.booth@gmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "Menu.h"
-#include "Event.h"
-#include "MenuItem.h"
-#include "MenuManager.h"
-#include "Screen.h"
-#include "Window.h"
-#include "WindowManager.h"
-#include <LibGfx/Bitmap.h>
-#include <LibGfx/CharacterBitmap.h>
-#include <LibGfx/Font.h>
-#include <LibGfx/Painter.h>
-#include <LibGfx/StylePainter.h>
-#include <LibGfx/Triangle.h>
-#include <WindowServer/ClientConnection.h>
-#include <WindowServer/WindowClientEndpoint.h>
-
-namespace WindowServer {
-
-Menu::Menu(ClientConnection* client, int menu_id, const String& name)
- : Core::Object(client)
- , m_client(client)
- , m_menu_id(menu_id)
- , m_name(move(name))
-{
-}
-
-Menu::~Menu()
-{
-}
-
-void Menu::set_title_font(const Gfx::Font& font)
-{
- m_title_font = &font;
-}
-
-const Gfx::Font& Menu::title_font() const
-{
- return *m_title_font;
-}
-
-const Gfx::Font& Menu::font() const
-{
- return Gfx::FontDatabase::default_font();
-}
-
-static const char* s_checked_bitmap_data = {
- " "
- " # "
- " ## "
- " ### "
- " ## ### "
- " ##### "
- " ### "
- " # "
- " "
-};
-
-static const char* s_submenu_arrow_bitmap_data = {
- " "
- " # "
- " ## "
- " ### "
- " #### "
- " ### "
- " ## "
- " # "
- " "
-};
-
-static Gfx::CharacterBitmap* s_checked_bitmap;
-static const int s_checked_bitmap_width = 9;
-static const int s_checked_bitmap_height = 9;
-static const int s_submenu_arrow_bitmap_width = 9;
-static const int s_submenu_arrow_bitmap_height = 9;
-static const int s_item_icon_width = 16;
-static const int s_stripe_width = 23;
-
-int Menu::content_width() const
-{
- int widest_text = 0;
- int widest_shortcut = 0;
- for (auto& item : m_items) {
- if (item.type() != MenuItem::Text)
- continue;
- auto& use_font = item.is_default() ? Gfx::FontDatabase::default_bold_font() : font();
- int text_width = use_font.width(item.text());
- if (!item.shortcut_text().is_empty()) {
- int shortcut_width = use_font.width(item.shortcut_text());
- widest_shortcut = max(shortcut_width, widest_shortcut);
- }
- widest_text = max(widest_text, text_width);
- }
-
- int widest_item = widest_text + s_stripe_width;
- if (widest_shortcut)
- widest_item += padding_between_text_and_shortcut() + widest_shortcut;
-
- return max(widest_item, rect_in_menubar().width()) + horizontal_padding() + frame_thickness() * 2;
-}
-
-void Menu::redraw()
-{
- if (!menu_window())
- return;
- draw();
- menu_window()->invalidate();
-}
-
-Window& Menu::ensure_menu_window()
-{
- if (m_menu_window)
- return *m_menu_window;
-
- int width = this->content_width();
-
- Gfx::IntPoint next_item_location(frame_thickness(), frame_thickness());
- for (auto& item : m_items) {
- int height = 0;
- if (item.type() == MenuItem::Text)
- height = item_height();
- else if (item.type() == MenuItem::Separator)
- height = 8;
- item.set_rect({ next_item_location, { width - frame_thickness() * 2, height } });
- next_item_location.move_by(0, height);
- }
-
- int window_height_available = Screen::the().height() - MenuManager::the().menubar_rect().height() - frame_thickness() * 2;
- int max_window_height = (window_height_available / item_height()) * item_height() + frame_thickness() * 2;
- int content_height = m_items.is_empty() ? 0 : (m_items.last().rect().bottom() + 1) + frame_thickness();
- int window_height = min(max_window_height, content_height);
- if (window_height < content_height) {
- m_scrollable = true;
- m_max_scroll_offset = item_count() - window_height / item_height() + 2;
- }
-
- auto window = Window::construct(*this, WindowType::Menu);
- window->set_rect(0, 0, width, window_height);
- m_menu_window = move(window);
- draw();
-
- return *m_menu_window;
-}
-
-int Menu::visible_item_count() const
-{
- if (!is_scrollable())
- return m_items.size();
- ASSERT(m_menu_window);
- // Make space for up/down arrow indicators
- return m_menu_window->height() / item_height() - 2;
-}
-
-void Menu::draw()
-{
- auto palette = WindowManager::the().palette();
- m_theme_index_at_last_paint = MenuManager::the().theme_index();
-
- ASSERT(menu_window());
- ASSERT(menu_window()->backing_store());
- Gfx::Painter painter(*menu_window()->backing_store());
-
- Gfx::IntRect rect { {}, menu_window()->size() };
- Gfx::StylePainter::paint_window_frame(painter, rect, palette);
- painter.fill_rect(rect.shrunken(6, 6), palette.menu_base());
- int width = this->content_width();
-
- if (!s_checked_bitmap)
- s_checked_bitmap = &Gfx::CharacterBitmap::create_from_ascii(s_checked_bitmap_data, s_checked_bitmap_width, s_checked_bitmap_height).leak_ref();
-
- bool has_checkable_items = false;
- bool has_items_with_icon = false;
- for (auto& item : m_items) {
- has_checkable_items = has_checkable_items | item.is_checkable();
- has_items_with_icon = has_items_with_icon | !!item.icon();
- }
-
- Gfx::IntRect stripe_rect { frame_thickness(), frame_thickness(), s_stripe_width, menu_window()->height() - frame_thickness() * 2 };
- painter.fill_rect(stripe_rect, palette.menu_stripe());
- painter.draw_line(stripe_rect.top_right(), stripe_rect.bottom_right(), palette.menu_stripe().darkened());
-
- int visible_item_count = this->visible_item_count();
-
- if (is_scrollable()) {
- bool can_go_up = m_scroll_offset > 0;
- bool can_go_down = m_scroll_offset < m_max_scroll_offset;
- Gfx::IntRect up_indicator_rect { frame_thickness(), frame_thickness(), content_width(), item_height() };
- painter.draw_text(up_indicator_rect, "\xE2\xAC\x86", Gfx::TextAlignment::Center, can_go_up ? palette.menu_base_text() : palette.color(ColorRole::DisabledText));
- Gfx::IntRect down_indicator_rect { frame_thickness(), menu_window()->height() - item_height() - frame_thickness(), content_width(), item_height() };
- painter.draw_text(down_indicator_rect, "\xE2\xAC\x87", Gfx::TextAlignment::Center, can_go_down ? palette.menu_base_text() : palette.color(ColorRole::DisabledText));
- }
-
- for (int i = 0; i < visible_item_count; ++i) {
- auto& item = m_items.at(m_scroll_offset + i);
- if (item.type() == MenuItem::Text) {
- Color text_color = palette.menu_base_text();
- if (&item == hovered_item() && item.is_enabled()) {
- painter.fill_rect(item.rect(), palette.menu_selection());
- painter.draw_rect(item.rect(), palette.menu_selection().darkened());
- text_color = palette.menu_selection_text();
- } else if (!item.is_enabled()) {
- text_color = Color::MidGray;
- }
- Gfx::IntRect text_rect = item.rect().translated(stripe_rect.width() + 6, 0);
- if (item.is_checkable()) {
- if (item.is_exclusive()) {
- Gfx::IntRect radio_rect { item.rect().x() + 5, 0, 12, 12 };
- radio_rect.center_vertically_within(text_rect);
- Gfx::StylePainter::paint_radio_button(painter, radio_rect, palette, item.is_checked(), false);
- } else {
- Gfx::IntRect checkmark_rect { item.rect().x() + 7, 0, s_checked_bitmap_width, s_checked_bitmap_height };
- checkmark_rect.center_vertically_within(text_rect);
- Gfx::IntRect checkbox_rect = checkmark_rect.inflated(4, 4);
- painter.fill_rect(checkbox_rect, palette.base());
- Gfx::StylePainter::paint_frame(painter, checkbox_rect, palette, Gfx::FrameShape::Container, Gfx::FrameShadow::Sunken, 2);
- if (item.is_checked()) {
- painter.draw_bitmap(checkmark_rect.location(), *s_checked_bitmap, palette.button_text());
- }
- }
- } else if (item.icon()) {
- Gfx::IntRect icon_rect { item.rect().x() + 3, 0, s_item_icon_width, s_item_icon_width };
- icon_rect.center_vertically_within(text_rect);
-
- if (&item == hovered_item() && item.is_enabled()) {
- auto shadow_color = palette.menu_selection().darkened(0.7f);
- painter.blit_filtered(icon_rect.location().translated(1, 1), *item.icon(), item.icon()->rect(), [&shadow_color](auto) {
- return shadow_color;
- });
- icon_rect.move_by(-1, -1);
- }
- if (item.is_enabled())
- painter.blit(icon_rect.location(), *item.icon(), item.icon()->rect());
- else
- painter.blit_disabled(icon_rect.location(), *item.icon(), item.icon()->rect(), palette);
- }
- auto& previous_font = painter.font();
- if (item.is_default())
- painter.set_font(Gfx::FontDatabase::default_bold_font());
- painter.draw_text(text_rect, item.text(), Gfx::TextAlignment::CenterLeft, text_color);
- if (!item.shortcut_text().is_empty()) {
- painter.draw_text(item.rect().translated(-right_padding(), 0), item.shortcut_text(), Gfx::TextAlignment::CenterRight, text_color);
- }
- painter.set_font(previous_font);
- if (item.is_submenu()) {
- static auto& submenu_arrow_bitmap = Gfx::CharacterBitmap::create_from_ascii(s_submenu_arrow_bitmap_data, s_submenu_arrow_bitmap_width, s_submenu_arrow_bitmap_height).leak_ref();
- Gfx::IntRect submenu_arrow_rect {
- item.rect().right() - s_submenu_arrow_bitmap_width - 2,
- 0,
- s_submenu_arrow_bitmap_width,
- s_submenu_arrow_bitmap_height
- };
- submenu_arrow_rect.center_vertically_within(item.rect());
- painter.draw_bitmap(submenu_arrow_rect.location(), submenu_arrow_bitmap, text_color);
- }
- } else if (item.type() == MenuItem::Separator) {
- Gfx::IntPoint p1(item.rect().translated(stripe_rect.width() + 4, 0).x(), item.rect().center().y() - 1);
- Gfx::IntPoint p2(width - 7, item.rect().center().y() - 1);
- painter.draw_line(p1, p2, palette.threed_shadow1());
- painter.draw_line(p1.translated(0, 1), p2.translated(0, 1), palette.threed_highlight());
- }
- }
-}
-
-MenuItem* Menu::hovered_item() const
-{
- if (m_hovered_item_index == -1)
- return nullptr;
- return const_cast<MenuItem*>(&item(m_hovered_item_index));
-}
-
-void Menu::update_for_new_hovered_item(bool make_input)
-{
- if (hovered_item() && hovered_item()->is_submenu()) {
- ASSERT(menu_window());
- MenuManager::the().close_everyone_not_in_lineage(*hovered_item()->submenu());
- hovered_item()->submenu()->do_popup(hovered_item()->rect().top_right().translated(menu_window()->rect().location()), make_input);
- } else {
- MenuManager::the().close_everyone_not_in_lineage(*this);
- ensure_menu_window().set_visible(true);
- }
- redraw();
-}
-
-void Menu::open_hovered_item()
-{
- ASSERT(menu_window());
- ASSERT(menu_window()->is_visible());
- if (!hovered_item())
- return;
- if (hovered_item()->is_enabled())
- did_activate(*hovered_item());
- clear_hovered_item();
-}
-
-void Menu::descend_into_submenu_at_hovered_item()
-{
- ASSERT(hovered_item());
- auto submenu = hovered_item()->submenu();
- ASSERT(submenu);
- MenuManager::the().open_menu(*submenu, false);
- submenu->set_hovered_item(0);
- ASSERT(submenu->hovered_item()->type() != MenuItem::Separator);
-}
-
-void Menu::handle_mouse_move_event(const MouseEvent& mouse_event)
-{
- ASSERT(menu_window());
- MenuManager::the().set_current_menu(this);
- if (hovered_item() && hovered_item()->is_submenu()) {
-
- auto item = *hovered_item();
- auto submenu_top_left = item.rect().location() + Gfx::IntPoint { item.rect().width(), 0 };
- auto submenu_bottom_left = submenu_top_left + Gfx::IntPoint { 0, item.submenu()->menu_window()->height() };
-
- auto safe_hover_triangle = Gfx::Triangle { m_last_position_in_hover, submenu_top_left, submenu_bottom_left };
- m_last_position_in_hover = mouse_event.position();
-
- // Don't update the hovered item if mouse is moving towards a submenu
- if (safe_hover_triangle.contains(mouse_event.position()))
- return;
- }
-
- int index = item_index_at(mouse_event.position());
- if (m_hovered_item_index == index)
- return;
- m_hovered_item_index = index;
-
- update_for_new_hovered_item();
- return;
-}
-
-void Menu::event(Core::Event& event)
-{
- if (event.type() == Event::MouseMove) {
- handle_mouse_move_event(static_cast<const MouseEvent&>(event));
- return;
- }
-
- if (event.type() == Event::MouseUp) {
- open_hovered_item();
- return;
- }
-
- if (event.type() == Event::MouseWheel && is_scrollable()) {
- ASSERT(menu_window());
- auto& mouse_event = static_cast<const MouseEvent&>(event);
- m_scroll_offset += mouse_event.wheel_delta();
- m_scroll_offset = clamp(m_scroll_offset, 0, m_max_scroll_offset);
-
- int index = item_index_at(mouse_event.position());
- if (m_hovered_item_index == index)
- return;
-
- m_hovered_item_index = index;
- update_for_new_hovered_item();
- return;
- }
-
- if (event.type() == Event::KeyDown) {
- auto key = static_cast<KeyEvent&>(event).key();
-
- if (!(key == Key_Up || key == Key_Down || key == Key_Left || key == Key_Right || key == Key_Return))
- return;
-
- ASSERT(menu_window());
- ASSERT(menu_window()->is_visible());
-
- // Default to the first item on key press if one has not been selected yet
- if (!hovered_item()) {
- m_hovered_item_index = 0;
- update_for_new_hovered_item(key == Key_Right);
- return;
- }
-
- if (key == Key_Up) {
- ASSERT(m_items.at(0).type() != MenuItem::Separator);
-
- if (is_scrollable() && m_hovered_item_index == 0)
- return;
-
- auto original_index = m_hovered_item_index;
- do {
- if (m_hovered_item_index == 0)
- m_hovered_item_index = m_items.size() - 1;
- else
- --m_hovered_item_index;
- if (m_hovered_item_index == original_index)
- return;
- } while (hovered_item()->type() == MenuItem::Separator || !hovered_item()->is_enabled());
-
- ASSERT(m_hovered_item_index >= 0 && m_hovered_item_index <= static_cast<int>(m_items.size()) - 1);
-
- if (is_scrollable() && m_hovered_item_index < m_scroll_offset)
- --m_scroll_offset;
-
- update_for_new_hovered_item();
- return;
- }
-
- if (key == Key_Down) {
- ASSERT(m_items.at(0).type() != MenuItem::Separator);
-
- if (is_scrollable() && m_hovered_item_index == static_cast<int>(m_items.size()) - 1)
- return;
-
- auto original_index = m_hovered_item_index;
- do {
- if (m_hovered_item_index == static_cast<int>(m_items.size()) - 1)
- m_hovered_item_index = 0;
- else
- ++m_hovered_item_index;
- if (m_hovered_item_index == original_index)
- return;
- } while (hovered_item()->type() == MenuItem::Separator || !hovered_item()->is_enabled());
-
- ASSERT(m_hovered_item_index >= 0 && m_hovered_item_index <= static_cast<int>(m_items.size()) - 1);
-
- if (is_scrollable() && m_hovered_item_index >= (m_scroll_offset + visible_item_count()))
- ++m_scroll_offset;
-
- update_for_new_hovered_item();
- return;
- }
- }
- Core::Object::event(event);
-}
-
-void Menu::clear_hovered_item()
-{
- if (!hovered_item())
- return;
- m_hovered_item_index = -1;
- redraw();
-}
-
-void Menu::did_activate(MenuItem& item)
-{
- if (item.type() == MenuItem::Type::Separator)
- return;
-
- if (on_item_activation)
- on_item_activation(item);
-
- MenuManager::the().close_bar();
-
- if (m_client)
- m_client->post_message(Messages::WindowClient::MenuItemActivated(m_menu_id, item.identifier()));
-}
-
-bool Menu::activate_default()
-{
- for (auto& item : m_items) {
- if (item.type() == MenuItem::Type::Separator)
- continue;
- if (item.is_enabled() && item.is_default()) {
- did_activate(item);
- return true;
- }
- }
- return false;
-}
-
-MenuItem* Menu::item_with_identifier(unsigned identifier)
-{
- for (auto& item : m_items) {
- if (item.identifier() == identifier)
- return &item;
- }
- return nullptr;
-}
-
-int Menu::item_index_at(const Gfx::IntPoint& position)
-{
- int i = 0;
- for (auto& item : m_items) {
- if (item.rect().contains(position))
- return i;
- ++i;
- }
- return -1;
-}
-
-void Menu::close()
-{
- MenuManager::the().close_menu_and_descendants(*this);
-}
-
-void Menu::redraw_if_theme_changed()
-{
- if (m_theme_index_at_last_paint != MenuManager::the().theme_index())
- redraw();
-}
-
-void Menu::popup(const Gfx::IntPoint& position)
-{
- do_popup(position, true);
-}
-
-void Menu::do_popup(const Gfx::IntPoint& position, bool make_input)
-{
- if (is_empty()) {
- dbgln("Menu: Empty menu popup");
- return;
- }
-
- auto& window = ensure_menu_window();
- redraw_if_theme_changed();
-
- const int margin = 30;
- Gfx::IntPoint adjusted_pos = position;
-
- if (adjusted_pos.x() + window.width() >= Screen::the().width() - margin) {
- adjusted_pos = adjusted_pos.translated(-window.width(), 0);
- }
- if (adjusted_pos.y() + window.height() >= Screen::the().height() - margin) {
- adjusted_pos = adjusted_pos.translated(0, -window.height());
- }
-
- if (adjusted_pos.y() < MenuManager::the().menubar_rect().height())
- adjusted_pos.set_y(MenuManager::the().menubar_rect().height());
-
- window.move_to(adjusted_pos);
- window.set_visible(true);
- MenuManager::the().open_menu(*this, make_input);
- WindowManager::the().did_popup_a_menu({});
-}
-
-bool Menu::is_menu_ancestor_of(const Menu& other) const
-{
- for (auto& item : m_items) {
- if (!item.is_submenu())
- continue;
- auto& submenu = *item.submenu();
- if (&submenu == &other)
- return true;
- if (submenu.is_menu_ancestor_of(other))
- return true;
- }
- return false;
-}
-
-}
diff --git a/Services/WindowServer/Menu.h b/Services/WindowServer/Menu.h
deleted file mode 100644
index 20fdb201cc..0000000000
--- a/Services/WindowServer/Menu.h
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <AK/NonnullOwnPtrVector.h>
-#include <AK/String.h>
-#include <AK/WeakPtr.h>
-#include <LibCore/Object.h>
-#include <LibGfx/Font.h>
-#include <LibGfx/FontDatabase.h>
-#include <LibGfx/Forward.h>
-#include <LibGfx/Rect.h>
-#include <WindowServer/Cursor.h>
-#include <WindowServer/MenuItem.h>
-#include <WindowServer/Window.h>
-
-namespace WindowServer {
-
-class ClientConnection;
-class MenuBar;
-class Event;
-
-class Menu final : public Core::Object {
- C_OBJECT(Menu)
-public:
- Menu(ClientConnection*, int menu_id, const String& name);
- virtual ~Menu() override;
-
- ClientConnection* client() { return m_client; }
- const ClientConnection* client() const { return m_client; }
- int menu_id() const { return m_menu_id; }
-
- MenuBar* menubar() { return m_menubar; }
- const MenuBar* menubar() const { return m_menubar; }
- void set_menubar(MenuBar* menubar) { m_menubar = menubar; }
-
- bool is_empty() const { return m_items.is_empty(); }
- int item_count() const { return m_items.size(); }
- const MenuItem& item(int index) const { return m_items.at(index); }
- MenuItem& item(int index) { return m_items.at(index); }
-
- void add_item(NonnullOwnPtr<MenuItem>&& item) { m_items.append(move(item)); }
-
- String name() const { return m_name; }
-
- template<typename Callback>
- void for_each_item(Callback callback) const
- {
- for (auto& item : m_items)
- callback(item);
- }
-
- Gfx::IntRect text_rect_in_menubar() const { return m_text_rect_in_menubar; }
- void set_text_rect_in_menubar(const Gfx::IntRect& rect) { m_text_rect_in_menubar = rect; }
-
- Gfx::IntRect rect_in_menubar() const { return m_rect_in_menubar; }
- void set_rect_in_menubar(const Gfx::IntRect& rect) { m_rect_in_menubar = rect; }
-
- Window* menu_window() { return m_menu_window.ptr(); }
- Window& ensure_menu_window();
-
- Window* window_menu_of() { return m_window_menu_of; }
- void set_window_menu_of(Window& window) { m_window_menu_of = window; }
- bool is_window_menu_open() { return m_is_window_menu_open; }
- void set_window_menu_open(bool is_open) { m_is_window_menu_open = is_open; }
-
- bool activate_default();
-
- int content_width() const;
-
- int item_height() const { return 20; }
- int frame_thickness() const { return 3; }
- int horizontal_padding() const { return left_padding() + right_padding(); }
- int left_padding() const { return 14; }
- int right_padding() const { return 14; }
-
- void draw();
- const Gfx::Font& font() const;
- const Gfx::Font& title_font() const;
- void set_title_font(const Gfx::Font& font);
-
- MenuItem* item_with_identifier(unsigned);
- void redraw();
-
- MenuItem* hovered_item() const;
-
- void set_hovered_item(int index)
- {
- m_hovered_item_index = index;
- update_for_new_hovered_item();
- }
-
- void clear_hovered_item();
-
- Function<void(MenuItem&)> on_item_activation;
-
- void close();
-
- void popup(const Gfx::IntPoint&);
- void do_popup(const Gfx::IntPoint&, bool);
-
- bool is_menu_ancestor_of(const Menu&) const;
-
- void redraw_if_theme_changed();
-
- bool is_scrollable() const { return m_scrollable; }
- int scroll_offset() const { return m_scroll_offset; }
-
- void descend_into_submenu_at_hovered_item();
- void open_hovered_item();
-
-private:
- virtual void event(Core::Event&) override;
-
- RefPtr<Gfx::Font> m_title_font { &Gfx::FontDatabase::default_font() };
-
- void handle_mouse_move_event(const MouseEvent&);
- int visible_item_count() const;
-
- int item_index_at(const Gfx::IntPoint&);
- int padding_between_text_and_shortcut() const { return 50; }
- void did_activate(MenuItem&);
- void update_for_new_hovered_item(bool make_input = false);
-
- ClientConnection* m_client { nullptr };
- int m_menu_id { 0 };
- String m_name;
- Gfx::IntRect m_rect_in_menubar;
- Gfx::IntRect m_text_rect_in_menubar;
- MenuBar* m_menubar { nullptr };
- NonnullOwnPtrVector<MenuItem> m_items;
- RefPtr<Window> m_menu_window;
-
- WeakPtr<Window> m_window_menu_of;
- bool m_is_window_menu_open = { false };
- Gfx::IntPoint m_last_position_in_hover;
- int m_theme_index_at_last_paint { -1 };
- int m_hovered_item_index { -1 };
-
- bool m_scrollable { false };
- int m_scroll_offset { 0 };
- int m_max_scroll_offset { 0 };
-};
-
-}
diff --git a/Services/WindowServer/MenuBar.cpp b/Services/WindowServer/MenuBar.cpp
deleted file mode 100644
index 30d739aaf7..0000000000
--- a/Services/WindowServer/MenuBar.cpp
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "MenuBar.h"
-#include "Menu.h"
-#include "MenuItem.h"
-#include <LibGfx/Bitmap.h>
-
-namespace WindowServer {
-
-MenuBar::MenuBar(ClientConnection& client, int menubar_id)
- : m_client(client)
- , m_menubar_id(menubar_id)
-{
-}
-
-MenuBar::~MenuBar()
-{
-}
-
-void MenuBar::add_menu(Menu& menu)
-{
- menu.set_menubar(this);
-
- // NOTE: We assume that the first menu is the App menu, which has a bold font.
- if (m_menus.is_empty())
- menu.set_title_font(Gfx::FontDatabase::default_bold_font());
-
- m_menus.append(&menu);
-}
-
-}
diff --git a/Services/WindowServer/MenuBar.h b/Services/WindowServer/MenuBar.h
deleted file mode 100644
index 31dff9ac0f..0000000000
--- a/Services/WindowServer/MenuBar.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include "Menu.h"
-#include <AK/Vector.h>
-#include <AK/WeakPtr.h>
-#include <AK/Weakable.h>
-
-namespace WindowServer {
-
-class MenuBar : public Weakable<MenuBar> {
-public:
- MenuBar(ClientConnection& client, int menubar_id);
- ~MenuBar();
-
- ClientConnection& client() { return m_client; }
- const ClientConnection& client() const { return m_client; }
- int menubar_id() const { return m_menubar_id; }
- void add_menu(Menu&);
-
- template<typename Callback>
- void for_each_menu(Callback callback)
- {
- for (auto& menu : m_menus) {
- if (callback(*menu) == IterationDecision::Break)
- return;
- }
- }
-
-private:
- ClientConnection& m_client;
- int m_menubar_id { 0 };
- Vector<Menu*> m_menus;
-};
-
-}
diff --git a/Services/WindowServer/MenuItem.cpp b/Services/WindowServer/MenuItem.cpp
deleted file mode 100644
index 324724a893..0000000000
--- a/Services/WindowServer/MenuItem.cpp
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "MenuItem.h"
-#include "ClientConnection.h"
-#include "Menu.h"
-#include "WindowManager.h"
-#include <LibGfx/Bitmap.h>
-
-namespace WindowServer {
-
-MenuItem::MenuItem(Menu& menu, unsigned identifier, const String& text, const String& shortcut_text, bool enabled, bool checkable, bool checked, const Gfx::Bitmap* icon)
- : m_menu(menu)
- , m_type(Text)
- , m_enabled(enabled)
- , m_checkable(checkable)
- , m_checked(checked)
- , m_identifier(identifier)
- , m_text(text)
- , m_shortcut_text(shortcut_text)
- , m_icon(icon)
-{
-}
-
-MenuItem::MenuItem(Menu& menu, Type type)
- : m_menu(menu)
- , m_type(type)
-{
-}
-
-MenuItem::~MenuItem()
-{
-}
-
-void MenuItem::set_enabled(bool enabled)
-{
- if (m_enabled == enabled)
- return;
- m_enabled = enabled;
- m_menu.redraw();
-}
-
-void MenuItem::set_checked(bool checked)
-{
- if (m_checked == checked)
- return;
- m_checked = checked;
- m_menu.redraw();
-}
-
-void MenuItem::set_default(bool is_default)
-{
- if (m_default == is_default)
- return;
- m_default = is_default;
- m_menu.redraw();
-}
-
-Menu* MenuItem::submenu()
-{
- ASSERT(is_submenu());
- ASSERT(m_menu.client());
- return m_menu.client()->find_menu_by_id(m_submenu_id);
-}
-
-const Menu* MenuItem::submenu() const
-{
- ASSERT(is_submenu());
- ASSERT(m_menu.client());
- return m_menu.client()->find_menu_by_id(m_submenu_id);
-}
-
-Gfx::IntRect MenuItem::rect() const
-{
- if (!m_menu.is_scrollable())
- return m_rect;
- return m_rect.translated(0, m_menu.item_height() - (m_menu.scroll_offset() * m_menu.item_height()));
-}
-
-void MenuItem::set_icon(const Gfx::Bitmap* icon)
-{
- if (m_icon == icon)
- return;
- m_icon = icon;
- m_menu.redraw();
-}
-
-}
diff --git a/Services/WindowServer/MenuItem.h b/Services/WindowServer/MenuItem.h
deleted file mode 100644
index 6bb1c203f1..0000000000
--- a/Services/WindowServer/MenuItem.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <AK/Function.h>
-#include <AK/String.h>
-#include <LibGfx/Forward.h>
-#include <LibGfx/Rect.h>
-
-namespace WindowServer {
-
-class Menu;
-
-class MenuItem {
-public:
- enum Type {
- None,
- Text,
- Separator,
- };
-
- MenuItem(Menu&, unsigned identifier, const String& text, const String& shortcut_text = {}, bool enabled = true, bool checkable = false, bool checked = false, const Gfx::Bitmap* icon = nullptr);
- MenuItem(Menu&, Type);
- ~MenuItem();
-
- Type type() const { return m_type; }
-
- bool is_enabled() const { return m_enabled; }
- void set_enabled(bool);
-
- bool is_checkable() const { return m_checkable; }
- void set_checkable(bool checkable) { m_checkable = checkable; }
-
- bool is_checked() const { return m_checked; }
- void set_checked(bool);
-
- bool is_default() const { return m_default; }
- void set_default(bool);
-
- String text() const { return m_text; }
- void set_text(const String& text) { m_text = text; }
-
- String shortcut_text() const { return m_shortcut_text; }
- void set_shortcut_text(const String& text) { m_shortcut_text = text; }
-
- void set_rect(const Gfx::IntRect& rect) { m_rect = rect; }
- Gfx::IntRect rect() const;
-
- unsigned identifier() const { return m_identifier; }
-
- const Gfx::Bitmap* icon() const { return m_icon; }
- void set_icon(const Gfx::Bitmap*);
-
- bool is_submenu() const { return m_submenu_id != -1; }
- int submenu_id() const { return m_submenu_id; }
- void set_submenu_id(int submenu_id) { m_submenu_id = submenu_id; }
-
- Menu* submenu();
- const Menu* submenu() const;
-
- bool is_exclusive() const { return m_exclusive; }
- void set_exclusive(bool exclusive) { m_exclusive = exclusive; }
-
-private:
- Menu& m_menu;
- Type m_type { None };
- bool m_enabled { true };
- bool m_checkable { false };
- bool m_checked { false };
- bool m_default { false };
- unsigned m_identifier { 0 };
- String m_text;
- String m_shortcut_text;
- Gfx::IntRect m_rect;
- RefPtr<Gfx::Bitmap> m_icon;
- int m_submenu_id { -1 };
- bool m_exclusive { false };
-};
-
-}
diff --git a/Services/WindowServer/MenuManager.cpp b/Services/WindowServer/MenuManager.cpp
deleted file mode 100644
index ba2ba789f9..0000000000
--- a/Services/WindowServer/MenuManager.cpp
+++ /dev/null
@@ -1,497 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * Copyright (c) 2020, Shannon Booth <shannon.ml.booth@gmail.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <AK/Badge.h>
-#include <AK/QuickSort.h>
-#include <LibCore/DirIterator.h>
-#include <LibGfx/Font.h>
-#include <LibGfx/Painter.h>
-#include <WindowServer/AppletManager.h>
-#include <WindowServer/MenuManager.h>
-#include <WindowServer/Screen.h>
-#include <WindowServer/WindowManager.h>
-#include <unistd.h>
-
-//#define DEBUG_MENUS
-
-namespace WindowServer {
-
-static MenuManager* s_the;
-static constexpr int s_search_timeout = 3000;
-
-MenuManager& MenuManager::the()
-{
- ASSERT(s_the);
- return *s_the;
-}
-
-MenuManager::MenuManager()
-{
- s_the = this;
- m_needs_window_resize = true;
-
- // NOTE: This ensures that the system menu has the correct dimensions.
- set_current_menubar(nullptr);
-
- m_window = Window::construct(*this, WindowType::Menubar);
- m_window->set_rect(menubar_rect());
-
- m_search_timer = Core::Timer::create_single_shot(0, [this] {
- m_current_search.clear();
- });
-}
-
-MenuManager::~MenuManager()
-{
-}
-
-bool MenuManager::is_open(const Menu& menu) const
-{
- for (size_t i = 0; i < m_open_menu_stack.size(); ++i) {
- if (&menu == m_open_menu_stack[i].ptr())
- return true;
- }
- return false;
-}
-
-void MenuManager::draw()
-{
- auto& wm = WindowManager::the();
- auto palette = wm.palette();
- auto menubar_rect = this->menubar_rect();
-
- if (m_needs_window_resize) {
- m_window->set_rect(menubar_rect);
- AppletManager::the().calculate_applet_rects(window());
- m_needs_window_resize = false;
- }
-
- Gfx::Painter painter(*window().backing_store());
-
- painter.fill_rect(menubar_rect, palette.window());
- painter.draw_line({ 0, menubar_rect.bottom() - 1 }, { menubar_rect.right(), menubar_rect.bottom() - 1 }, palette.threed_shadow1());
- painter.draw_line({ 0, menubar_rect.bottom() }, { menubar_rect.right(), menubar_rect.bottom() }, palette.threed_shadow2());
-
- for_each_active_menubar_menu([&](Menu& menu) {
- Color text_color = palette.window_text();
- if (is_open(menu)) {
- painter.fill_rect(menu.rect_in_menubar(), palette.menu_selection());
- painter.draw_rect(menu.rect_in_menubar(), palette.menu_selection().darkened());
- text_color = palette.menu_selection_text();
- }
- painter.draw_text(
- menu.text_rect_in_menubar(),
- menu.name(),
- menu.title_font(),
- Gfx::TextAlignment::CenterLeft,
- text_color);
- //painter.draw_rect(menu.text_rect_in_menubar(), Color::Magenta);
- return IterationDecision::Continue;
- });
-
- AppletManager::the().draw();
-}
-
-void MenuManager::refresh()
-{
- if (!m_window)
- return;
- draw();
- window().invalidate();
-}
-
-void MenuManager::event(Core::Event& event)
-{
- if (static_cast<Event&>(event).is_mouse_event()) {
- handle_mouse_event(static_cast<MouseEvent&>(event));
- return;
- }
-
- if (static_cast<Event&>(event).is_key_event()) {
- auto& key_event = static_cast<const KeyEvent&>(event);
-
- if (key_event.type() == Event::KeyUp && key_event.key() == Key_Escape) {
- close_everyone();
- return;
- }
-
- if (key_event.key() == Key_Backspace) {
- m_current_search.clear();
- return;
- }
-
- if (m_current_menu && event.type() == Event::KeyDown
- && ((key_event.key() >= Key_A && key_event.key() <= Key_Z)
- || (key_event.key() >= Key_0 && key_event.key() <= Key_9))) {
- m_current_search.append_code_point(key_event.code_point());
- m_search_timer->restart(s_search_timeout);
- for (int i = 0; i < m_current_menu->item_count(); ++i) {
- auto text = m_current_menu->item(i).text();
- if (text.to_lowercase().starts_with(m_current_search.to_string().to_lowercase())) {
- m_current_menu->set_hovered_item(i);
- return;
- }
- }
- return;
- }
-
- if (event.type() == Event::KeyDown) {
-
- if (key_event.key() == Key_Left) {
- auto it = m_open_menu_stack.find_if([&](const auto& other) { return m_current_menu == other.ptr(); });
- ASSERT(!it.is_end());
-
- // Going "back" a menu should be the previous menu in the stack
- if (it.index() > 0)
- set_current_menu(m_open_menu_stack.at(it.index() - 1));
- close_everyone_not_in_lineage(*m_current_menu);
- return;
- }
-
- if (key_event.key() == Key_Right) {
- auto hovered_item = m_current_menu->hovered_item();
- if (hovered_item && hovered_item->is_submenu())
- m_current_menu->descend_into_submenu_at_hovered_item();
- return;
- }
-
- if (key_event.key() == Key_Return) {
- auto hovered_item = m_current_menu->hovered_item();
- if (!hovered_item || !hovered_item->is_enabled())
- return;
- if (hovered_item->is_submenu())
- m_current_menu->descend_into_submenu_at_hovered_item();
- else
- m_current_menu->open_hovered_item();
- return;
- }
- m_current_menu->dispatch_event(event);
- }
- }
-
- return Core::Object::event(event);
-}
-
-void MenuManager::handle_mouse_event(MouseEvent& mouse_event)
-{
- auto* active_window = WindowManager::the().active_window();
- bool handled_menubar_event = false;
- for_each_active_menubar_menu([&](Menu& menu) {
- if (menu.rect_in_menubar().contains(mouse_event.position())) {
- handled_menubar_event = &menu == m_system_menu || !active_window || !active_window->is_modal();
- if (handled_menubar_event)
- handle_menu_mouse_event(menu, mouse_event);
- return IterationDecision::Break;
- }
- return IterationDecision::Continue;
- });
- if (handled_menubar_event)
- return;
-
- if (has_open_menu()) {
- auto* topmost_menu = m_open_menu_stack.last().ptr();
- ASSERT(topmost_menu);
- auto* window = topmost_menu->menu_window();
- if (!window) {
- dbgln("MenuManager::handle_mouse_event: No menu window");
- return;
- }
- ASSERT(window->is_visible());
-
- bool event_is_inside_current_menu = window->rect().contains(mouse_event.position());
- if (event_is_inside_current_menu) {
- WindowManager::the().set_hovered_window(window);
- auto translated_event = mouse_event.translated(-window->position());
- WindowManager::the().deliver_mouse_event(*window, translated_event);
- return;
- }
-
- if (topmost_menu->hovered_item())
- topmost_menu->clear_hovered_item();
- if (mouse_event.type() == Event::MouseDown || mouse_event.type() == Event::MouseUp) {
- auto* window_menu_of = topmost_menu->window_menu_of();
- if (window_menu_of) {
- bool event_is_inside_taskbar_button = window_menu_of->taskbar_rect().contains(mouse_event.position());
- if (event_is_inside_taskbar_button && !topmost_menu->is_window_menu_open()) {
- topmost_menu->set_window_menu_open(true);
- return;
- }
- }
-
- if (mouse_event.type() == Event::MouseDown) {
- close_bar();
- topmost_menu->set_window_menu_open(false);
- }
- }
-
- if (mouse_event.type() == Event::MouseMove) {
- for (auto& menu : m_open_menu_stack) {
- if (!menu)
- continue;
- if (!menu->menu_window()->rect().contains(mouse_event.position()))
- continue;
- WindowManager::the().set_hovered_window(menu->menu_window());
- auto translated_event = mouse_event.translated(-menu->menu_window()->position());
- WindowManager::the().deliver_mouse_event(*menu->menu_window(), translated_event);
- break;
- }
- }
- return;
- }
-
- AppletManager::the().dispatch_event(static_cast<Event&>(mouse_event));
-}
-
-void MenuManager::handle_menu_mouse_event(Menu& menu, const MouseEvent& event)
-{
- bool is_hover_with_any_menu_open = event.type() == MouseEvent::MouseMove
- && has_open_menu()
- && (m_open_menu_stack.first()->menubar() || m_open_menu_stack.first() == m_system_menu.ptr());
- bool is_mousedown_with_left_button = event.type() == MouseEvent::MouseDown && event.button() == MouseButton::Left;
- bool should_open_menu = &menu != m_current_menu && (is_hover_with_any_menu_open || is_mousedown_with_left_button);
-
- if (is_mousedown_with_left_button)
- m_bar_open = !m_bar_open;
-
- if (should_open_menu && m_bar_open) {
- close_everyone();
- open_menu(menu);
- return;
- }
-
- if (!m_bar_open)
- close_everyone();
-}
-
-void MenuManager::set_needs_window_resize()
-{
- m_needs_window_resize = true;
-}
-
-void MenuManager::close_all_menus_from_client(Badge<ClientConnection>, ClientConnection& client)
-{
- if (!has_open_menu())
- return;
- if (m_open_menu_stack.first()->client() != &client)
- return;
- close_everyone();
-}
-
-void MenuManager::close_everyone()
-{
- for (auto& menu : m_open_menu_stack) {
- ASSERT(menu);
- if (menu->menu_window())
- menu->menu_window()->set_visible(false);
- menu->clear_hovered_item();
- }
- m_open_menu_stack.clear();
- m_current_search.clear();
- clear_current_menu();
- refresh();
-}
-
-void MenuManager::close_everyone_not_in_lineage(Menu& menu)
-{
- Vector<Menu*> menus_to_close;
- for (auto& open_menu : m_open_menu_stack) {
- if (!open_menu)
- continue;
- if (&menu == open_menu.ptr() || open_menu->is_menu_ancestor_of(menu))
- continue;
- menus_to_close.append(open_menu);
- }
- close_menus(menus_to_close);
-}
-
-void MenuManager::close_menus(const Vector<Menu*>& menus)
-{
- for (auto& menu : menus) {
- if (menu == m_current_menu)
- clear_current_menu();
- if (menu->menu_window())
- menu->menu_window()->set_visible(false);
- menu->clear_hovered_item();
- m_open_menu_stack.remove_first_matching([&](auto& entry) {
- return entry == menu;
- });
- }
- refresh();
-}
-
-static void collect_menu_subtree(Menu& menu, Vector<Menu*>& menus)
-{
- menus.append(&menu);
- for (int i = 0; i < menu.item_count(); ++i) {
- auto& item = menu.item(i);
- if (!item.is_submenu())
- continue;
- collect_menu_subtree(*item.submenu(), menus);
- }
-}
-
-void MenuManager::close_menu_and_descendants(Menu& menu)
-{
- Vector<Menu*> menus_to_close;
- collect_menu_subtree(menu, menus_to_close);
- close_menus(menus_to_close);
-}
-
-void MenuManager::toggle_menu(Menu& menu)
-{
- if (is_open(menu)) {
- close_menu_and_descendants(menu);
- return;
- }
- open_menu(menu);
-}
-
-void MenuManager::open_menu(Menu& menu, bool as_current_menu)
-{
- if (is_open(menu)) {
- if (as_current_menu || current_menu() != &menu) {
- // This menu is already open. If requested, or if the current
- // window doesn't match this one, then set it to this
- set_current_menu(&menu);
- }
- return;
- }
-
- if (!menu.is_empty()) {
- menu.redraw_if_theme_changed();
- if (!menu.menu_window()) {
- auto& menu_window = menu.ensure_menu_window();
- menu_window.move_to({ menu.rect_in_menubar().x(), menu.rect_in_menubar().bottom() + 2 });
- }
- menu.menu_window()->set_visible(true);
- }
-
- if (m_open_menu_stack.find_if([&menu](auto& other) { return &menu == other.ptr(); }).is_end())
- m_open_menu_stack.append(menu);
-
- if (as_current_menu || !current_menu()) {
- // Only make this menu the current menu if requested, or if no
- // other menu is current
- set_current_menu(&menu);
- }
-
- refresh();
-}
-
-void MenuManager::clear_current_menu()
-{
- Menu* previous_current_menu = m_current_menu;
- m_current_menu = nullptr;
- if (previous_current_menu) {
- // When closing the last menu, restore the previous active input window
- auto& wm = WindowManager::the();
- wm.restore_active_input_window(m_previous_input_window);
- }
-}
-
-void MenuManager::set_current_menu(Menu* menu)
-{
- if (!menu) {
- clear_current_menu();
- return;
- }
-
- ASSERT(is_open(*menu));
- if (menu == m_current_menu) {
- return;
- }
-
- m_current_search.clear();
-
- Menu* previous_current_menu = m_current_menu;
- m_current_menu = menu;
-
- auto& wm = WindowManager::the();
- if (!previous_current_menu) {
- // When opening the first menu, store the current active input window
- if (auto* active_input = wm.active_input_window())
- m_previous_input_window = *active_input;
- else
- m_previous_input_window = nullptr;
- }
-
- wm.set_active_input_window(m_current_menu->menu_window());
-}
-
-void MenuManager::close_bar()
-{
- close_everyone();
- m_bar_open = false;
-}
-
-Gfx::IntRect MenuManager::menubar_rect() const
-{
- return { 0, 0, Screen::the().rect().width(), 19 };
-}
-
-void MenuManager::set_current_menubar(MenuBar* menubar)
-{
- if (menubar)
- m_current_menubar = *menubar;
- else
- m_current_menubar = nullptr;
-#ifdef DEBUG_MENUS
- dbg() << "[WM] Current menubar is now " << menubar;
-#endif
- Gfx::IntPoint next_menu_location { MenuManager::menubar_menu_margin() / 2, 0 };
- for_each_active_menubar_menu([&](Menu& menu) {
- int text_width = menu.title_font().width(menu.name());
- menu.set_rect_in_menubar({ next_menu_location.x() - MenuManager::menubar_menu_margin() / 2, 0, text_width + MenuManager::menubar_menu_margin(), menubar_rect().height() - 1 });
-
- Gfx::IntRect text_rect { next_menu_location.translated(0, 1), { text_width, menubar_rect().height() - 3 } };
-
- menu.set_text_rect_in_menubar(text_rect);
- next_menu_location.move_by(menu.rect_in_menubar().width(), 0);
- return IterationDecision::Continue;
- });
- refresh();
-}
-
-void MenuManager::close_menubar(MenuBar& menubar)
-{
- if (current_menubar() == &menubar)
- set_current_menubar(nullptr);
-}
-
-void MenuManager::set_system_menu(Menu& menu)
-{
- m_system_menu = menu;
- set_current_menubar(m_current_menubar);
-}
-
-void MenuManager::did_change_theme()
-{
- ++m_theme_index;
- refresh();
-}
-
-}
diff --git a/Services/WindowServer/MenuManager.h b/Services/WindowServer/MenuManager.h
deleted file mode 100644
index 0d56f6a8b7..0000000000
--- a/Services/WindowServer/MenuManager.h
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include "Menu.h"
-#include "MenuBar.h"
-#include "Window.h"
-#include <AK/HashMap.h>
-#include <AK/StringBuilder.h>
-#include <LibCore/Object.h>
-#include <LibCore/Timer.h>
-
-namespace WindowServer {
-
-class MenuManager final : public Core::Object {
- C_OBJECT(MenuManager)
-public:
- static MenuManager& the();
-
- MenuManager();
- virtual ~MenuManager() override;
-
- void refresh();
-
- bool is_open(const Menu&) const;
- bool has_open_menu() const { return !m_open_menu_stack.is_empty(); }
-
- Gfx::IntRect menubar_rect() const;
- static int menubar_menu_margin() { return 16; }
-
- void set_needs_window_resize();
-
- Menu* current_menu() { return m_current_menu.ptr(); }
- void set_current_menu(Menu*);
- void clear_current_menu();
- void open_menu(Menu&, bool as_current_menu = true);
- void toggle_menu(Menu&);
-
- MenuBar* current_menubar() { return m_current_menubar.ptr(); }
- void set_current_menubar(MenuBar*);
- void close_menubar(MenuBar&);
-
- void close_bar();
- void close_everyone();
- void close_everyone_not_in_lineage(Menu&);
- void close_menu_and_descendants(Menu&);
-
- void close_all_menus_from_client(Badge<ClientConnection>, ClientConnection&);
-
- Menu* system_menu() { return m_system_menu; }
- void set_system_menu(Menu&);
-
- int theme_index() const { return m_theme_index; }
-
- Window& window() { return *m_window; }
-
- template<typename Callback>
- void for_each_active_menubar_menu(Callback callback)
- {
- if (system_menu()) {
- if (callback(*system_menu()) == IterationDecision::Break)
- return;
- }
- if (m_current_menubar)
- m_current_menubar->for_each_menu(callback);
- }
-
- void did_change_theme();
-
-private:
- void close_menus(const Vector<Menu*>&);
-
- const Window& window() const { return *m_window; }
-
- virtual void event(Core::Event&) override;
- void handle_mouse_event(MouseEvent&);
- void handle_menu_mouse_event(Menu&, const MouseEvent&);
-
- void draw();
-
- RefPtr<Window> m_window;
-
- WeakPtr<Menu> m_current_menu;
- WeakPtr<Window> m_previous_input_window;
- Vector<WeakPtr<Menu>> m_open_menu_stack;
-
- RefPtr<Core::Timer> m_search_timer;
- StringBuilder m_current_search;
- WeakPtr<Menu> m_system_menu;
-
- bool m_needs_window_resize { false };
- bool m_bar_open { false };
-
- int m_theme_index { 0 };
-
- WeakPtr<MenuBar> m_current_menubar;
-};
-
-}
diff --git a/Services/WindowServer/Screen.cpp b/Services/WindowServer/Screen.cpp
deleted file mode 100644
index 4cc9ae809b..0000000000
--- a/Services/WindowServer/Screen.cpp
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "Screen.h"
-#include "Compositor.h"
-#include "Event.h"
-#include "EventLoop.h"
-#include "WindowManager.h"
-#include <Kernel/API/FB.h>
-#include <Kernel/API/MousePacket.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <sys/mman.h>
-#include <unistd.h>
-
-namespace WindowServer {
-
-static Screen* s_the;
-
-Screen& Screen::the()
-{
- ASSERT(s_the);
- return *s_the;
-}
-
-Screen::Screen(unsigned desired_width, unsigned desired_height)
-{
- ASSERT(!s_the);
- s_the = this;
- m_framebuffer_fd = open("/dev/fb0", O_RDWR | O_CLOEXEC);
- if (m_framebuffer_fd < 0) {
- perror("failed to open /dev/fb0");
- ASSERT_NOT_REACHED();
- }
-
- if (fb_set_buffer(m_framebuffer_fd, 0) == 0) {
- m_can_set_buffer = true;
- }
-
- set_resolution(desired_width, desired_height);
- m_cursor_location = rect().center();
-}
-
-Screen::~Screen()
-{
- close(m_framebuffer_fd);
-}
-
-bool Screen::set_resolution(int width, int height)
-{
- FBResolution resolution { 0, (unsigned)width, (unsigned)height };
- int rc = fb_set_resolution(m_framebuffer_fd, &resolution);
-#ifdef WSSCREEN_DEBUG
- dbg() << "fb_set_resolution() - return code " << rc;
-#endif
- if (rc == 0) {
- on_change_resolution(resolution.pitch, resolution.width, resolution.height);
- return true;
- }
- if (rc == -1) {
- dbg() << "Invalid resolution " << width << "x" << height;
- on_change_resolution(resolution.pitch, resolution.width, resolution.height);
- return false;
- }
- ASSERT_NOT_REACHED();
-}
-
-void Screen::on_change_resolution(int pitch, int width, int height)
-{
- if (m_framebuffer) {
- size_t previous_size_in_bytes = m_size_in_bytes;
- int rc = munmap(m_framebuffer, previous_size_in_bytes);
- ASSERT(rc == 0);
- }
-
- int rc = fb_get_size_in_bytes(m_framebuffer_fd, &m_size_in_bytes);
- ASSERT(rc == 0);
-
- m_framebuffer = (Gfx::RGBA32*)mmap(nullptr, m_size_in_bytes, PROT_READ | PROT_WRITE, MAP_SHARED, m_framebuffer_fd, 0);
- ASSERT(m_framebuffer && m_framebuffer != (void*)-1);
-
- m_pitch = pitch;
- m_width = width;
- m_height = height;
-
- m_cursor_location.constrain(rect());
-}
-
-void Screen::set_buffer(int index)
-{
- ASSERT(m_can_set_buffer);
- int rc = fb_set_buffer(m_framebuffer_fd, index);
- ASSERT(rc == 0);
-}
-
-void Screen::set_acceleration_factor(double factor)
-{
- ASSERT(factor >= mouse_accel_min && factor <= mouse_accel_max);
- m_acceleration_factor = factor;
-}
-
-void Screen::set_scroll_step_size(unsigned step_size)
-{
- ASSERT(step_size >= scroll_step_size_min);
- m_scroll_step_size = step_size;
-}
-
-void Screen::on_receive_mouse_data(const MousePacket& packet)
-{
- auto prev_location = m_cursor_location;
- if (packet.is_relative) {
- m_cursor_location.move_by(packet.x * m_acceleration_factor, packet.y * m_acceleration_factor);
-#ifdef WSSCREEN_DEBUG
- dbgln("Screen: New Relative mouse point @ {}", m_cursor_location);
-#endif
- } else {
- m_cursor_location = { packet.x * m_width / 0xffff, packet.y * m_height / 0xffff };
-#ifdef WSSCREEN_DEBUG
- dbgln("Screen: New Absolute mouse point @ {}", m_cursor_location);
-#endif
- }
-
- m_cursor_location.constrain(rect());
-
- unsigned buttons = packet.buttons;
- unsigned prev_buttons = m_mouse_button_state;
- m_mouse_button_state = buttons;
- unsigned changed_buttons = prev_buttons ^ buttons;
- auto post_mousedown_or_mouseup_if_needed = [&](MouseButton button) {
- if (!(changed_buttons & (unsigned)button))
- return;
- auto message = make<MouseEvent>(buttons & (unsigned)button ? Event::MouseDown : Event::MouseUp, m_cursor_location, buttons, button, m_modifiers);
- Core::EventLoop::current().post_event(WindowManager::the(), move(message));
- };
- post_mousedown_or_mouseup_if_needed(MouseButton::Left);
- post_mousedown_or_mouseup_if_needed(MouseButton::Right);
- post_mousedown_or_mouseup_if_needed(MouseButton::Middle);
- post_mousedown_or_mouseup_if_needed(MouseButton::Back);
- post_mousedown_or_mouseup_if_needed(MouseButton::Forward);
- if (m_cursor_location != prev_location) {
- auto message = make<MouseEvent>(Event::MouseMove, m_cursor_location, buttons, MouseButton::None, m_modifiers);
- if (WindowManager::the().dnd_client())
- message->set_mime_data(WindowManager::the().dnd_mime_data());
- Core::EventLoop::current().post_event(WindowManager::the(), move(message));
- }
-
- if (packet.z) {
- auto message = make<MouseEvent>(Event::MouseWheel, m_cursor_location, buttons, MouseButton::None, m_modifiers, packet.z * m_scroll_step_size);
- Core::EventLoop::current().post_event(WindowManager::the(), move(message));
- }
-
- if (m_cursor_location != prev_location)
- Compositor::the().invalidate_cursor();
-}
-
-void Screen::on_receive_keyboard_data(::KeyEvent kernel_event)
-{
- m_modifiers = kernel_event.modifiers();
- auto message = make<KeyEvent>(kernel_event.is_press() ? Event::KeyDown : Event::KeyUp, kernel_event.key, kernel_event.code_point, kernel_event.modifiers(), kernel_event.scancode);
- Core::EventLoop::current().post_event(WindowManager::the(), move(message));
-}
-
-}
diff --git a/Services/WindowServer/Screen.h b/Services/WindowServer/Screen.h
deleted file mode 100644
index c435bc62c9..0000000000
--- a/Services/WindowServer/Screen.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <Kernel/API/KeyCode.h>
-#include <LibGfx/Color.h>
-#include <LibGfx/Rect.h>
-#include <LibGfx/Size.h>
-
-struct MousePacket;
-
-namespace WindowServer {
-
-const double mouse_accel_max = 3.5;
-const double mouse_accel_min = 0.5;
-const unsigned scroll_step_size_min = 1;
-
-class Screen {
-public:
- Screen(unsigned width, unsigned height);
- ~Screen();
-
- bool set_resolution(int width, int height);
- bool can_set_buffer() { return m_can_set_buffer; }
- void set_buffer(int index);
-
- int width() const { return m_width; }
- int height() const { return m_height; }
- size_t pitch() const { return m_pitch; }
- Gfx::RGBA32* scanline(int y);
-
- static Screen& the();
-
- Gfx::IntSize size() const { return { width(), height() }; }
- Gfx::IntRect rect() const { return { 0, 0, width(), height() }; }
-
- Gfx::IntPoint cursor_location() const { return m_cursor_location; }
- unsigned mouse_button_state() const { return m_mouse_button_state; }
-
- double acceleration_factor() const { return m_acceleration_factor; }
- void set_acceleration_factor(double);
-
- unsigned scroll_step_size() const { return m_scroll_step_size; }
- void set_scroll_step_size(unsigned);
-
- void on_receive_mouse_data(const MousePacket&);
- void on_receive_keyboard_data(::KeyEvent);
-
-private:
- void on_change_resolution(int pitch, int width, int height);
-
- size_t m_size_in_bytes;
-
- Gfx::RGBA32* m_framebuffer { nullptr };
- bool m_can_set_buffer { false };
-
- int m_pitch { 0 };
- int m_width { 0 };
- int m_height { 0 };
- int m_framebuffer_fd { -1 };
-
- Gfx::IntPoint m_cursor_location;
- unsigned m_mouse_button_state { 0 };
- unsigned m_modifiers { 0 };
- double m_acceleration_factor { 1.0 };
- unsigned m_scroll_step_size { 1 };
-};
-
-inline Gfx::RGBA32* Screen::scanline(int y)
-{
- return reinterpret_cast<Gfx::RGBA32*>(((u8*)m_framebuffer) + (y * m_pitch));
-}
-
-}
diff --git a/Services/WindowServer/Window.cpp b/Services/WindowServer/Window.cpp
deleted file mode 100644
index 1d0497c1c6..0000000000
--- a/Services/WindowServer/Window.cpp
+++ /dev/null
@@ -1,776 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "Window.h"
-#include "AppletManager.h"
-#include "ClientConnection.h"
-#include "Compositor.h"
-#include "Event.h"
-#include "EventLoop.h"
-#include "Screen.h"
-#include "WindowManager.h"
-#include <AK/Badge.h>
-#include <WindowServer/WindowClientEndpoint.h>
-
-namespace WindowServer {
-
-static String default_window_icon_path()
-{
- return "/res/icons/16x16/window.png";
-}
-
-static Gfx::Bitmap& default_window_icon()
-{
- static Gfx::Bitmap* s_icon;
- if (!s_icon)
- s_icon = Gfx::Bitmap::load_from_file(default_window_icon_path()).leak_ref();
- return *s_icon;
-}
-
-static Gfx::Bitmap& minimize_icon()
-{
- static Gfx::Bitmap* s_icon;
- if (!s_icon)
- s_icon = Gfx::Bitmap::load_from_file("/res/icons/16x16/downward-triangle.png").leak_ref();
- return *s_icon;
-}
-
-static Gfx::Bitmap& maximize_icon()
-{
- static Gfx::Bitmap* s_icon;
- if (!s_icon)
- s_icon = Gfx::Bitmap::load_from_file("/res/icons/16x16/upward-triangle.png").leak_ref();
- return *s_icon;
-}
-
-static Gfx::Bitmap& restore_icon()
-{
- static Gfx::Bitmap* s_icon;
- if (!s_icon)
- s_icon = Gfx::Bitmap::load_from_file("/res/icons/16x16/window-restore.png").leak_ref();
- return *s_icon;
-}
-
-static Gfx::Bitmap& close_icon()
-{
- static Gfx::Bitmap* s_icon;
- if (!s_icon)
- s_icon = Gfx::Bitmap::load_from_file("/res/icons/16x16/window-close.png").leak_ref();
- return *s_icon;
-}
-
-Window::Window(Core::Object& parent, WindowType type)
- : Core::Object(&parent)
- , m_type(type)
- , m_icon(default_window_icon())
- , m_frame(*this)
-{
- WindowManager::the().add_window(*this);
-}
-
-Window::Window(ClientConnection& client, WindowType window_type, int window_id, bool modal, bool minimizable, bool frameless, bool resizable, bool fullscreen, bool accessory, Window* parent_window)
- : Core::Object(&client)
- , m_client(&client)
- , m_type(window_type)
- , m_modal(modal)
- , m_minimizable(minimizable)
- , m_frameless(frameless)
- , m_resizable(resizable)
- , m_fullscreen(fullscreen)
- , m_accessory(accessory)
- , m_window_id(window_id)
- , m_client_id(client.client_id())
- , m_icon(default_window_icon())
- , m_frame(*this)
-{
- // FIXME: This should not be hard-coded here.
- if (m_type == WindowType::Taskbar) {
- m_wm_event_mask = WMEventMask::WindowStateChanges | WMEventMask::WindowRemovals | WMEventMask::WindowIconChanges;
- m_listens_to_wm_events = true;
- }
-
- if (parent_window)
- set_parent_window(*parent_window);
- WindowManager::the().add_window(*this);
-}
-
-Window::~Window()
-{
- // Detach from client at the start of teardown since we don't want
- // to confuse things by trying to send messages to it.
- m_client = nullptr;
-
- WindowManager::the().remove_window(*this);
-}
-
-void Window::destroy()
-{
- m_destroyed = true;
- set_visible(false);
-}
-
-void Window::set_title(const String& title)
-{
- if (m_title == title)
- return;
- m_title = title;
- frame().invalidate_title_bar();
- WindowManager::the().notify_title_changed(*this);
-}
-
-void Window::set_rect(const Gfx::IntRect& rect)
-{
- ASSERT(!rect.is_empty());
- if (m_rect == rect)
- return;
- auto old_rect = m_rect;
- m_rect = rect;
- if (!m_client && (!m_backing_store || old_rect.size() != rect.size())) {
- m_backing_store = Gfx::Bitmap::create(Gfx::BitmapFormat::RGB32, m_rect.size());
- }
-
- invalidate(true);
- m_frame.notify_window_rect_changed(old_rect, rect); // recomputes occlusions
-}
-
-void Window::set_rect_without_repaint(const Gfx::IntRect& rect)
-{
- ASSERT(!rect.is_empty());
- if (m_rect == rect)
- return;
- auto old_rect = m_rect;
- m_rect = rect;
-
- if (old_rect.size() == m_rect.size()) {
- auto delta = m_rect.location() - old_rect.location();
- for (auto& child_window : m_child_windows) {
- if (child_window)
- child_window->move_by(delta);
- }
- }
-
- invalidate(true);
- m_frame.notify_window_rect_changed(old_rect, rect); // recomputes occlusions
-}
-
-void Window::handle_mouse_event(const MouseEvent& event)
-{
- set_automatic_cursor_tracking_enabled(event.buttons() != 0);
-
- switch (event.type()) {
- case Event::MouseMove:
- m_client->post_message(Messages::WindowClient::MouseMove(m_window_id, event.position(), (u32)event.button(), event.buttons(), event.modifiers(), event.wheel_delta(), event.is_drag(), event.mime_types()));
- break;
- case Event::MouseDown:
- m_client->post_message(Messages::WindowClient::MouseDown(m_window_id, event.position(), (u32)event.button(), event.buttons(), event.modifiers(), event.wheel_delta()));
- break;
- case Event::MouseDoubleClick:
- m_client->post_message(Messages::WindowClient::MouseDoubleClick(m_window_id, event.position(), (u32)event.button(), event.buttons(), event.modifiers(), event.wheel_delta()));
- break;
- case Event::MouseUp:
- m_client->post_message(Messages::WindowClient::MouseUp(m_window_id, event.position(), (u32)event.button(), event.buttons(), event.modifiers(), event.wheel_delta()));
- break;
- case Event::MouseWheel:
- m_client->post_message(Messages::WindowClient::MouseWheel(m_window_id, event.position(), (u32)event.button(), event.buttons(), event.modifiers(), event.wheel_delta()));
- break;
- default:
- ASSERT_NOT_REACHED();
- }
-}
-
-void Window::update_menu_item_text(PopupMenuItem item)
-{
- if (m_window_menu) {
- m_window_menu->item((int)item).set_text(item == PopupMenuItem::Minimize ? (m_minimized ? "Unminimize" : "Minimize") : (m_maximized ? "Restore" : "Maximize"));
- m_window_menu->redraw();
- }
-}
-
-void Window::update_menu_item_enabled(PopupMenuItem item)
-{
- if (m_window_menu) {
- m_window_menu->item((int)item).set_enabled(item == PopupMenuItem::Minimize ? m_minimizable : m_resizable);
- m_window_menu->redraw();
- }
-}
-
-void Window::set_minimized(bool minimized)
-{
- if (m_minimized == minimized)
- return;
- if (minimized && !m_minimizable)
- return;
- m_minimized = minimized;
- update_menu_item_text(PopupMenuItem::Minimize);
- Compositor::the().invalidate_occlusions();
- Compositor::the().invalidate_screen(frame().rect());
- if (!blocking_modal_window())
- start_minimize_animation();
- if (!minimized)
- request_update({ {}, size() });
- WindowManager::the().notify_minimization_state_changed(*this);
-}
-
-void Window::set_minimizable(bool minimizable)
-{
- if (m_minimizable == minimizable)
- return;
- m_minimizable = minimizable;
- update_menu_item_enabled(PopupMenuItem::Minimize);
- // TODO: Hide/show (or alternatively change enabled state of) window minimize button dynamically depending on value of m_minimizable
-}
-
-void Window::set_taskbar_rect(const Gfx::IntRect& rect)
-{
- m_taskbar_rect = rect;
- m_have_taskbar_rect = !m_taskbar_rect.is_empty();
-}
-
-void Window::start_minimize_animation()
-{
- if (!m_have_taskbar_rect) {
- // If this is a modal window, it may not have its own taskbar
- // button, so there is no rectangle. In that case, walk the
- // modal stack until we find a window that may have one
- WindowManager::the().for_each_window_in_modal_stack(*this, [&](Window& w, bool) {
- if (w.has_taskbar_rect()) {
- // We purposely do NOT set m_have_taskbar_rect to true here
- // because we want to only copy the rectangle from the
- // window that has it, but since this window wouldn't receive
- // any updates down the road we want to query it again
- // next time we want to start the animation
- m_taskbar_rect = w.taskbar_rect();
-
- ASSERT(!m_have_taskbar_rect); // should remain unset!
- return IterationDecision::Break;
- };
- return IterationDecision::Continue;
- });
- }
- m_minimize_animation_step = 0;
-}
-
-void Window::set_opacity(float opacity)
-{
- if (m_opacity == opacity)
- return;
- bool was_opaque = is_opaque();
- m_opacity = opacity;
- if (was_opaque != is_opaque())
- Compositor::the().invalidate_occlusions();
- Compositor::the().invalidate_screen(frame().rect());
- WindowManager::the().notify_opacity_changed(*this);
-}
-
-void Window::set_occluded(bool occluded)
-{
- if (m_occluded == occluded)
- return;
- m_occluded = occluded;
- WindowManager::the().notify_occlusion_state_changed(*this);
-}
-
-void Window::set_maximized(bool maximized)
-{
- if (m_maximized == maximized)
- return;
- if (maximized && (!is_resizable() || resize_aspect_ratio().has_value()))
- return;
- set_tiled(WindowTileType::None);
- m_maximized = maximized;
- update_menu_item_text(PopupMenuItem::Maximize);
- if (maximized) {
- m_unmaximized_rect = m_rect;
- set_rect(WindowManager::the().maximized_window_rect(*this));
- } else {
- set_rect(m_unmaximized_rect);
- }
- m_frame.did_set_maximized({}, maximized);
- Core::EventLoop::current().post_event(*this, make<ResizeEvent>(m_rect));
- set_default_positioned(false);
-}
-
-void Window::set_resizable(bool resizable)
-{
- if (m_resizable == resizable)
- return;
- m_resizable = resizable;
- update_menu_item_enabled(PopupMenuItem::Maximize);
- // TODO: Hide/show (or alternatively change enabled state of) window maximize button dynamically depending on value of is_resizable()
-}
-
-void Window::event(Core::Event& event)
-{
- if (!m_client) {
- ASSERT(parent());
- event.ignore();
- return;
- }
-
- if (blocking_modal_window()) {
- // We still want to handle the WindowDeactivated event below when a new modal is
- // created to notify its parent window, despite it being "blocked by modal window".
- if (event.type() != Event::WindowDeactivated)
- return;
- }
-
- if (static_cast<Event&>(event).is_mouse_event())
- return handle_mouse_event(static_cast<const MouseEvent&>(event));
-
- switch (event.type()) {
- case Event::WindowEntered:
- m_client->post_message(Messages::WindowClient::WindowEntered(m_window_id));
- break;
- case Event::WindowLeft:
- m_client->post_message(Messages::WindowClient::WindowLeft(m_window_id));
- break;
- case Event::KeyDown:
- m_client->post_message(
- Messages::WindowClient::KeyDown(m_window_id,
- (u32) static_cast<const KeyEvent&>(event).code_point(),
- (u32) static_cast<const KeyEvent&>(event).key(),
- static_cast<const KeyEvent&>(event).modifiers(),
- (u32) static_cast<const KeyEvent&>(event).scancode()));
- break;
- case Event::KeyUp:
- m_client->post_message(
- Messages::WindowClient::KeyUp(m_window_id,
- (u32) static_cast<const KeyEvent&>(event).code_point(),
- (u32) static_cast<const KeyEvent&>(event).key(),
- static_cast<const KeyEvent&>(event).modifiers(),
- (u32) static_cast<const KeyEvent&>(event).scancode()));
- break;
- case Event::WindowActivated:
- m_client->post_message(Messages::WindowClient::WindowActivated(m_window_id));
- break;
- case Event::WindowDeactivated:
- m_client->post_message(Messages::WindowClient::WindowDeactivated(m_window_id));
- break;
- case Event::WindowInputEntered:
- m_client->post_message(Messages::WindowClient::WindowInputEntered(m_window_id));
- break;
- case Event::WindowInputLeft:
- m_client->post_message(Messages::WindowClient::WindowInputLeft(m_window_id));
- break;
- case Event::WindowCloseRequest:
- m_client->post_message(Messages::WindowClient::WindowCloseRequest(m_window_id));
- break;
- case Event::WindowResized:
- m_client->post_message(Messages::WindowClient::WindowResized(m_window_id, static_cast<const ResizeEvent&>(event).rect()));
- break;
- default:
- break;
- }
-}
-
-void Window::set_global_cursor_tracking_enabled(bool enabled)
-{
- m_global_cursor_tracking_enabled = enabled;
-}
-
-void Window::set_visible(bool b)
-{
- if (m_visible == b)
- return;
- m_visible = b;
-
- Compositor::the().invalidate_occlusions();
- if (m_visible)
- invalidate(true);
- else
- Compositor::the().invalidate_screen(frame().rect());
-}
-
-void Window::invalidate(bool invalidate_frame)
-{
- m_invalidated = true;
- m_invalidated_all = true;
- m_invalidated_frame |= invalidate_frame;
- m_dirty_rects.clear();
- Compositor::the().invalidate_window();
-}
-
-void Window::invalidate(const Gfx::IntRect& rect, bool with_frame)
-{
- if (type() == WindowType::MenuApplet) {
- AppletManager::the().invalidate_applet(*this, rect);
- return;
- }
-
- if (invalidate_no_notify(rect, with_frame))
- Compositor::the().invalidate_window();
-}
-
-bool Window::invalidate_no_notify(const Gfx::IntRect& rect, bool with_frame)
-{
- if (rect.is_empty())
- return false;
- if (m_invalidated_all) {
- m_invalidated_frame |= with_frame;
- return false;
- }
-
- auto outer_rect = frame().rect();
- auto inner_rect = rect;
- inner_rect.move_by(position());
- // FIXME: This seems slightly wrong; the inner rect shouldn't intersect the border part of the outer rect.
- inner_rect.intersect(outer_rect);
- if (inner_rect.is_empty())
- return false;
-
- m_invalidated = true;
- m_invalidated_frame |= with_frame;
- m_dirty_rects.add(inner_rect.translated(-outer_rect.location()));
- return true;
-}
-
-void Window::prepare_dirty_rects()
-{
- if (m_invalidated_all) {
- if (m_invalidated_frame)
- m_dirty_rects = frame().rect();
- else
- m_dirty_rects = rect();
- } else {
- m_dirty_rects.move_by(frame().rect().location());
- }
-}
-
-void Window::clear_dirty_rects()
-{
- m_invalidated_all = false;
- m_invalidated_frame = false;
- m_invalidated = false;
- m_dirty_rects.clear_with_capacity();
-}
-
-bool Window::is_active() const
-{
- return WindowManager::the().active_window() == this;
-}
-
-Window* Window::blocking_modal_window()
-{
- // A window is blocked if any immediate child, or any child further
- // down the chain is modal
- for (auto& window : m_child_windows) {
- if (window && !window->is_destroyed()) {
- if (window->is_modal())
- return window;
-
- if (auto* blocking_window = window->blocking_modal_window())
- return blocking_window;
- }
- }
- return nullptr;
-}
-
-void Window::set_default_icon()
-{
- m_icon = default_window_icon();
-}
-
-void Window::request_update(const Gfx::IntRect& rect, bool ignore_occlusion)
-{
- if (rect.is_empty())
- return;
- if (m_pending_paint_rects.is_empty()) {
- deferred_invoke([this, ignore_occlusion](auto&) {
- client()->post_paint_message(*this, ignore_occlusion);
- });
- }
- m_pending_paint_rects.add(rect);
-}
-
-void Window::ensure_window_menu()
-{
- if (!m_window_menu) {
- m_window_menu = Menu::construct(nullptr, -1, "(Window Menu)");
- m_window_menu->set_window_menu_of(*this);
-
- auto minimize_item = make<MenuItem>(*m_window_menu, 1, m_minimized ? "Unminimize" : "Minimize");
- m_window_menu_minimize_item = minimize_item.ptr();
- m_window_menu->add_item(move(minimize_item));
-
- auto maximize_item = make<MenuItem>(*m_window_menu, 2, m_maximized ? "Restore" : "Maximize");
- m_window_menu_maximize_item = maximize_item.ptr();
- m_window_menu->add_item(move(maximize_item));
-
- m_window_menu->add_item(make<MenuItem>(*m_window_menu, MenuItem::Type::Separator));
-
- auto close_item = make<MenuItem>(*m_window_menu, 3, "Close");
- m_window_menu_close_item = close_item.ptr();
- m_window_menu_close_item->set_icon(&close_icon());
- m_window_menu_close_item->set_default(true);
- m_window_menu->add_item(move(close_item));
-
- m_window_menu->item((int)PopupMenuItem::Minimize).set_enabled(m_minimizable);
- m_window_menu->item((int)PopupMenuItem::Maximize).set_enabled(m_resizable);
-
- m_window_menu->on_item_activation = [&](auto& item) {
- switch (item.identifier()) {
- case 1:
- WindowManager::the().minimize_windows(*this, !m_minimized);
- if (!m_minimized)
- WindowManager::the().move_to_front_and_make_active(*this);
- break;
- case 2:
- WindowManager::the().maximize_windows(*this, !m_maximized);
- WindowManager::the().move_to_front_and_make_active(*this);
- break;
- case 3:
- request_close();
- break;
- }
- };
- }
-}
-
-void Window::popup_window_menu(const Gfx::IntPoint& position, WindowMenuDefaultAction default_action)
-{
- ensure_window_menu();
- if (default_action == WindowMenuDefaultAction::BasedOnWindowState) {
- // When clicked on the task bar, determine the default action
- if (!is_active() && !is_minimized())
- default_action = WindowMenuDefaultAction::None;
- else if (is_minimized())
- default_action = WindowMenuDefaultAction::Unminimize;
- else
- default_action = WindowMenuDefaultAction::Minimize;
- }
- m_window_menu_minimize_item->set_default(default_action == WindowMenuDefaultAction::Minimize || default_action == WindowMenuDefaultAction::Unminimize);
- m_window_menu_minimize_item->set_icon(m_minimized ? nullptr : &minimize_icon());
- m_window_menu_maximize_item->set_default(default_action == WindowMenuDefaultAction::Maximize || default_action == WindowMenuDefaultAction::Restore);
- m_window_menu_maximize_item->set_icon(m_maximized ? &restore_icon() : &maximize_icon());
- m_window_menu_close_item->set_default(default_action == WindowMenuDefaultAction::Close);
-
- m_window_menu->popup(position);
-}
-
-void Window::window_menu_activate_default()
-{
- ensure_window_menu();
- m_window_menu->activate_default();
-}
-
-void Window::request_close()
-{
- Event close_request(Event::WindowCloseRequest);
- event(close_request);
-}
-
-void Window::set_fullscreen(bool fullscreen)
-{
- if (m_fullscreen == fullscreen)
- return;
- m_fullscreen = fullscreen;
- Gfx::IntRect new_window_rect = m_rect;
- if (m_fullscreen) {
- m_saved_nonfullscreen_rect = m_rect;
- new_window_rect = Screen::the().rect();
- } else if (!m_saved_nonfullscreen_rect.is_empty()) {
- new_window_rect = m_saved_nonfullscreen_rect;
- }
-
- Core::EventLoop::current().post_event(*this, make<ResizeEvent>(new_window_rect));
- set_rect(new_window_rect);
-}
-
-Gfx::IntRect Window::tiled_rect(WindowTileType tiled) const
-{
- int frame_width = (m_frame.rect().width() - m_rect.width()) / 2;
- int title_bar_height = m_frame.title_bar_rect().height();
- int menu_height = WindowManager::the().maximized_window_rect(*this).y();
- int max_height = WindowManager::the().maximized_window_rect(*this).height();
-
- switch (tiled) {
- case WindowTileType::None:
- return m_untiled_rect;
- case WindowTileType::Left:
- return Gfx::IntRect(0,
- menu_height,
- Screen::the().width() / 2 - frame_width,
- max_height);
- case WindowTileType::Right:
- return Gfx::IntRect(Screen::the().width() / 2 + frame_width,
- menu_height,
- Screen::the().width() / 2 - frame_width,
- max_height);
- case WindowTileType::Top:
- return Gfx::IntRect(0,
- menu_height,
- Screen::the().width() - frame_width,
- (max_height - title_bar_height) / 2 - frame_width);
- case WindowTileType::Bottom:
- return Gfx::IntRect(0,
- menu_height + (title_bar_height + max_height) / 2 + frame_width,
- Screen::the().width() - frame_width,
- (max_height - title_bar_height) / 2 - frame_width);
- case WindowTileType::TopLeft:
- return Gfx::IntRect(0,
- menu_height,
- Screen::the().width() / 2 - frame_width,
- (max_height - title_bar_height) / 2 - frame_width);
- case WindowTileType::TopRight:
- return Gfx::IntRect(Screen::the().width() / 2 + frame_width,
- menu_height,
- Screen::the().width() / 2 - frame_width,
- (max_height - title_bar_height) / 2 - frame_width);
- case WindowTileType::BottomLeft:
- return Gfx::IntRect(0,
- menu_height + (title_bar_height + max_height) / 2 + frame_width,
- Screen::the().width() / 2 - frame_width,
- (max_height - title_bar_height) / 2);
- case WindowTileType::BottomRight:
- return Gfx::IntRect(Screen::the().width() / 2 + frame_width,
- menu_height + (title_bar_height + max_height) / 2 + frame_width,
- Screen::the().width() / 2 - frame_width,
- (max_height - title_bar_height) / 2);
- default:
- ASSERT_NOT_REACHED();
- }
-}
-
-void Window::set_tiled(WindowTileType tiled)
-{
- if (m_tiled == tiled)
- return;
-
- if (resize_aspect_ratio().has_value())
- return;
-
- m_tiled = tiled;
- if (tiled != WindowTileType::None)
- m_untiled_rect = m_rect;
- set_rect(tiled_rect(tiled));
- Core::EventLoop::current().post_event(*this, make<ResizeEvent>(m_rect));
-}
-
-void Window::detach_client(Badge<ClientConnection>)
-{
- m_client = nullptr;
-}
-
-void Window::recalculate_rect()
-{
- if (!is_resizable())
- return;
-
- bool send_event = true;
- if (m_tiled != WindowTileType::None) {
- set_rect(tiled_rect(m_tiled));
- } else if (is_maximized()) {
- set_rect(WindowManager::the().maximized_window_rect(*this));
- } else if (type() == WindowType::Desktop) {
- set_rect(WindowManager::the().desktop_rect());
- } else {
- send_event = false;
- }
-
- if (send_event) {
- Core::EventLoop::current().post_event(*this, make<ResizeEvent>(m_rect));
- }
-}
-
-void Window::add_child_window(Window& child_window)
-{
- m_child_windows.append(child_window);
-}
-
-void Window::add_accessory_window(Window& accessory_window)
-{
- m_accessory_windows.append(accessory_window);
-}
-
-void Window::set_parent_window(Window& parent_window)
-{
- ASSERT(!m_parent_window);
- m_parent_window = parent_window;
- if (m_accessory)
- parent_window.add_accessory_window(*this);
- else
- parent_window.add_child_window(*this);
-}
-
-bool Window::is_accessory() const
-{
- if (!m_accessory)
- return false;
- if (parent_window() != nullptr)
- return true;
-
- // If accessory window was unparented, convert to a regular window
- const_cast<Window*>(this)->set_accessory(false);
- return false;
-}
-
-bool Window::is_accessory_of(Window& window) const
-{
- if (!is_accessory())
- return false;
- return parent_window() == &window;
-}
-
-void Window::modal_unparented()
-{
- m_modal = false;
- WindowManager::the().notify_modal_unparented(*this);
-}
-
-bool Window::is_modal() const
-{
- if (!m_modal)
- return false;
- if (!m_parent_window) {
- const_cast<Window*>(this)->modal_unparented();
- return false;
- }
- return true;
-}
-
-void Window::set_progress(int progress)
-{
- if (m_progress == progress)
- return;
-
- m_progress = progress;
- WindowManager::the().notify_progress_changed(*this);
-}
-
-bool Window::is_descendant_of(Window& window) const
-{
- for (auto* parent = parent_window(); parent; parent = parent->parent_window()) {
- if (parent == &window)
- return true;
- for (auto& accessory : parent->accessory_windows()) {
- if (accessory == &window)
- return true;
- }
- }
- return false;
-}
-
-}
diff --git a/Services/WindowServer/Window.h b/Services/WindowServer/Window.h
deleted file mode 100644
index 286d543cc4..0000000000
--- a/Services/WindowServer/Window.h
+++ /dev/null
@@ -1,363 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <AK/InlineLinkedList.h>
-#include <AK/String.h>
-#include <AK/WeakPtr.h>
-#include <LibCore/Object.h>
-#include <LibGfx/Bitmap.h>
-#include <LibGfx/DisjointRectSet.h>
-#include <LibGfx/Rect.h>
-#include <WindowServer/WindowFrame.h>
-#include <WindowServer/WindowType.h>
-
-namespace WindowServer {
-
-class ClientConnection;
-class Cursor;
-class Menu;
-class MenuItem;
-class MouseEvent;
-
-enum WMEventMask {
- WindowRectChanges = 1 << 0,
- WindowStateChanges = 1 << 1,
- WindowIconChanges = 1 << 2,
- WindowRemovals = 1 << 3,
-};
-
-enum class WindowTileType {
- None = 0,
- Left,
- Right,
- Top,
- Bottom,
- TopLeft,
- TopRight,
- BottomLeft,
- BottomRight
-};
-
-enum class PopupMenuItem {
- Minimize = 0,
- Maximize,
-};
-
-enum class WindowMenuDefaultAction {
- None = 0,
- BasedOnWindowState,
- Close,
- Minimize,
- Unminimize,
- Maximize,
- Restore
-};
-
-class Window final : public Core::Object
- , public InlineLinkedListNode<Window> {
- C_OBJECT(Window)
-public:
- Window(ClientConnection&, WindowType, int window_id, bool modal, bool minimizable, bool frameless, bool resizable, bool fullscreen, bool accessory, Window* parent_window = nullptr);
- Window(Core::Object&, WindowType);
- virtual ~Window() override;
-
- void popup_window_menu(const Gfx::IntPoint&, WindowMenuDefaultAction);
- void window_menu_activate_default();
- void request_close();
-
- unsigned wm_event_mask() const { return m_wm_event_mask; }
- void set_wm_event_mask(unsigned mask) { m_wm_event_mask = mask; }
-
- bool is_minimized() const { return m_minimized; }
- void set_minimized(bool);
-
- bool is_minimizable() const { return m_minimizable; }
- void set_minimizable(bool);
-
- bool is_resizable() const { return m_resizable && !m_fullscreen; }
- void set_resizable(bool);
-
- bool is_maximized() const { return m_maximized; }
- void set_maximized(bool);
-
- bool is_fullscreen() const { return m_fullscreen; }
- void set_fullscreen(bool);
-
- WindowTileType tiled() const { return m_tiled; }
- void set_tiled(WindowTileType);
-
- bool is_occluded() const { return m_occluded; }
- void set_occluded(bool);
-
- bool is_movable() const
- {
- return m_type == WindowType::Normal;
- }
-
- WindowFrame& frame() { return m_frame; }
- const WindowFrame& frame() const { return m_frame; }
-
- Window* blocking_modal_window();
-
- bool listens_to_wm_events() const { return m_listens_to_wm_events; }
-
- ClientConnection* client() { return m_client; }
- const ClientConnection* client() const { return m_client; }
-
- WindowType type() const { return m_type; }
- int window_id() const { return m_window_id; }
-
- bool is_internal() const { return m_client_id == -1; }
- i32 client_id() const { return m_client_id; }
-
- String title() const { return m_title; }
- void set_title(const String&);
-
- float opacity() const { return m_opacity; }
- void set_opacity(float);
-
- int x() const { return m_rect.x(); }
- int y() const { return m_rect.y(); }
- int width() const { return m_rect.width(); }
- int height() const { return m_rect.height(); }
-
- bool is_active() const;
-
- bool is_visible() const { return m_visible; }
- void set_visible(bool);
-
- bool is_modal() const;
- bool is_modal_dont_unparent() const { return m_modal && m_parent_window; }
-
- Gfx::IntRect rect() const { return m_rect; }
- void set_rect(const Gfx::IntRect&);
- void set_rect(int x, int y, int width, int height) { set_rect({ x, y, width, height }); }
- void set_rect_without_repaint(const Gfx::IntRect&);
-
- void set_taskbar_rect(const Gfx::IntRect&);
- const Gfx::IntRect& taskbar_rect() const { return m_taskbar_rect; }
-
- void move_to(const Gfx::IntPoint& position) { set_rect({ position, size() }); }
- void move_to(int x, int y) { move_to({ x, y }); }
-
- void move_by(const Gfx::IntPoint& delta) { set_position_without_repaint(position().translated(delta)); }
-
- Gfx::IntPoint position() const { return m_rect.location(); }
- void set_position(const Gfx::IntPoint& position) { set_rect({ position.x(), position.y(), width(), height() }); }
- void set_position_without_repaint(const Gfx::IntPoint& position) { set_rect_without_repaint({ position.x(), position.y(), width(), height() }); }
-
- Gfx::IntSize size() const { return m_rect.size(); }
-
- void invalidate(bool with_frame = true);
- void invalidate(const Gfx::IntRect&, bool with_frame = false);
- bool invalidate_no_notify(const Gfx::IntRect& rect, bool with_frame = false);
-
- void prepare_dirty_rects();
- void clear_dirty_rects();
- Gfx::DisjointRectSet& dirty_rects() { return m_dirty_rects; }
-
- virtual void event(Core::Event&) override;
-
- // Only used by WindowType::MenuApplet. Perhaps it could be a Window subclass? I don't know.
- void set_rect_in_menubar(const Gfx::IntRect& rect) { m_rect_in_menubar = rect; }
- const Gfx::IntRect& rect_in_menubar() const { return m_rect_in_menubar; }
-
- const Gfx::Bitmap* backing_store() const { return m_backing_store.ptr(); }
- Gfx::Bitmap* backing_store() { return m_backing_store.ptr(); }
-
- void set_backing_store(RefPtr<Gfx::Bitmap>&& backing_store)
- {
- m_last_backing_store = move(m_backing_store);
- m_backing_store = move(backing_store);
- }
-
- void swap_backing_stores()
- {
- swap(m_backing_store, m_last_backing_store);
- }
-
- Gfx::Bitmap* last_backing_store() { return m_last_backing_store.ptr(); }
-
- void set_global_cursor_tracking_enabled(bool);
- void set_automatic_cursor_tracking_enabled(bool enabled) { m_automatic_cursor_tracking_enabled = enabled; }
- bool global_cursor_tracking() const { return m_global_cursor_tracking_enabled || m_automatic_cursor_tracking_enabled; }
-
- bool has_alpha_channel() const { return m_has_alpha_channel; }
- void set_has_alpha_channel(bool value) { m_has_alpha_channel = value; }
-
- Gfx::IntSize size_increment() const { return m_size_increment; }
- void set_size_increment(const Gfx::IntSize& increment) { m_size_increment = increment; }
-
- const Optional<Gfx::IntSize>& resize_aspect_ratio() const { return m_resize_aspect_ratio; }
- void set_resize_aspect_ratio(const Optional<Gfx::IntSize>& ratio) { m_resize_aspect_ratio = ratio; }
-
- Gfx::IntSize base_size() const { return m_base_size; }
- void set_base_size(const Gfx::IntSize& size) { m_base_size = size; }
-
- const Gfx::Bitmap& icon() const { return *m_icon; }
- void set_icon(NonnullRefPtr<Gfx::Bitmap>&& icon) { m_icon = move(icon); }
-
- void set_default_icon();
-
- const Cursor* cursor() const { return m_cursor.ptr(); }
- void set_cursor(RefPtr<Cursor> cursor) { m_cursor = move(cursor); }
-
- void request_update(const Gfx::IntRect&, bool ignore_occlusion = false);
- Gfx::DisjointRectSet take_pending_paint_rects() { return move(m_pending_paint_rects); }
-
- bool has_taskbar_rect() const { return m_have_taskbar_rect; };
- bool in_minimize_animation() const { return m_minimize_animation_step != -1; }
- int minimize_animation_index() const { return m_minimize_animation_step; }
- void step_minimize_animation() { m_minimize_animation_step += 1; }
- void start_minimize_animation();
- void end_minimize_animation() { m_minimize_animation_step = -1; }
-
- Gfx::IntRect tiled_rect(WindowTileType) const;
- void recalculate_rect();
-
- // For InlineLinkedList.
- // FIXME: Maybe make a ListHashSet and then WindowManager can just use that.
- Window* m_next { nullptr };
- Window* m_prev { nullptr };
-
- void detach_client(Badge<ClientConnection>);
-
- Window* parent_window() { return m_parent_window; }
- const Window* parent_window() const { return m_parent_window; }
-
- void set_parent_window(Window&);
-
- Vector<WeakPtr<Window>>& child_windows() { return m_child_windows; }
- const Vector<WeakPtr<Window>>& child_windows() const { return m_child_windows; }
-
- Vector<WeakPtr<Window>>& accessory_windows() { return m_accessory_windows; }
- const Vector<WeakPtr<Window>>& accessory_windows() const { return m_accessory_windows; }
-
- bool is_descendant_of(Window&) const;
-
- void set_accessory(bool accessory) { m_accessory = accessory; }
- bool is_accessory() const;
- bool is_accessory_of(Window&) const;
-
- void set_frameless(bool frameless) { m_frameless = frameless; }
- bool is_frameless() const { return m_frameless; }
-
- int progress() const { return m_progress; }
- void set_progress(int);
-
- bool is_destroyed() const { return m_destroyed; }
- void destroy();
-
- bool default_positioned() const { return m_default_positioned; }
- void set_default_positioned(bool p) { m_default_positioned = p; }
-
- bool is_invalidated() const { return m_invalidated; }
-
- bool is_opaque() const
- {
- if (opacity() < 1.0f)
- return false;
- if (has_alpha_channel())
- return false;
- return true;
- }
-
- Gfx::DisjointRectSet& opaque_rects() { return m_opaque_rects; }
- Gfx::DisjointRectSet& transparency_rects() { return m_transparency_rects; }
- Gfx::DisjointRectSet& transparency_wallpaper_rects() { return m_transparency_wallpaper_rects; }
-
-private:
- void handle_mouse_event(const MouseEvent&);
- void update_menu_item_text(PopupMenuItem item);
- void update_menu_item_enabled(PopupMenuItem item);
- void add_child_window(Window&);
- void add_accessory_window(Window&);
- void ensure_window_menu();
- void modal_unparented();
-
- ClientConnection* m_client { nullptr };
-
- WeakPtr<Window> m_parent_window;
- Vector<WeakPtr<Window>> m_child_windows;
- Vector<WeakPtr<Window>> m_accessory_windows;
-
- String m_title;
- Gfx::IntRect m_rect;
- Gfx::IntRect m_saved_nonfullscreen_rect;
- Gfx::IntRect m_taskbar_rect;
- Gfx::DisjointRectSet m_dirty_rects;
- Gfx::DisjointRectSet m_opaque_rects;
- Gfx::DisjointRectSet m_transparency_rects;
- Gfx::DisjointRectSet m_transparency_wallpaper_rects;
- WindowType m_type { WindowType::Normal };
- bool m_global_cursor_tracking_enabled { false };
- bool m_automatic_cursor_tracking_enabled { false };
- bool m_visible { true };
- bool m_has_alpha_channel { false };
- bool m_modal { false };
- bool m_minimizable { false };
- bool m_frameless { false };
- bool m_resizable { false };
- Optional<Gfx::IntSize> m_resize_aspect_ratio {};
- bool m_listens_to_wm_events { false };
- bool m_minimized { false };
- bool m_maximized { false };
- bool m_fullscreen { false };
- bool m_accessory { false };
- bool m_destroyed { false };
- bool m_default_positioned { false };
- bool m_have_taskbar_rect { false };
- bool m_invalidated { true };
- bool m_invalidated_all { true };
- bool m_invalidated_frame { true };
- WindowTileType m_tiled { WindowTileType::None };
- Gfx::IntRect m_untiled_rect;
- bool m_occluded { false };
- RefPtr<Gfx::Bitmap> m_backing_store;
- RefPtr<Gfx::Bitmap> m_last_backing_store;
- int m_window_id { -1 };
- i32 m_client_id { -1 };
- float m_opacity { 1 };
- Gfx::IntSize m_size_increment;
- Gfx::IntSize m_base_size;
- NonnullRefPtr<Gfx::Bitmap> m_icon;
- RefPtr<Cursor> m_cursor;
- WindowFrame m_frame;
- unsigned m_wm_event_mask { 0 };
- Gfx::DisjointRectSet m_pending_paint_rects;
- Gfx::IntRect m_unmaximized_rect;
- Gfx::IntRect m_rect_in_menubar;
- RefPtr<Menu> m_window_menu;
- MenuItem* m_window_menu_minimize_item { nullptr };
- MenuItem* m_window_menu_maximize_item { nullptr };
- MenuItem* m_window_menu_close_item { nullptr };
- int m_minimize_animation_step { -1 };
- int m_progress { -1 };
-};
-
-}
diff --git a/Services/WindowServer/WindowClient.ipc b/Services/WindowServer/WindowClient.ipc
deleted file mode 100644
index c6ac17b022..0000000000
--- a/Services/WindowServer/WindowClient.ipc
+++ /dev/null
@@ -1,42 +0,0 @@
-endpoint WindowClient = 4
-{
- Paint(i32 window_id, Gfx::IntSize window_size, Vector<Gfx::IntRect> rects) =|
- MouseMove(i32 window_id, Gfx::IntPoint mouse_position, u32 button, u32 buttons, u32 modifiers, i32 wheel_delta, bool is_drag, Vector<String> mime_types) =|
- MouseDown(i32 window_id, Gfx::IntPoint mouse_position, u32 button, u32 buttons, u32 modifiers, i32 wheel_delta) =|
- MouseDoubleClick(i32 window_id, Gfx::IntPoint mouse_position, u32 button, u32 buttons, u32 modifiers, i32 wheel_delta) =|
- MouseUp(i32 window_id, Gfx::IntPoint mouse_position, u32 button, u32 buttons, u32 modifiers, i32 wheel_delta) =|
- MouseWheel(i32 window_id, Gfx::IntPoint mouse_position, u32 button, u32 buttons, u32 modifiers, i32 wheel_delta) =|
- WindowEntered(i32 window_id) =|
- WindowLeft(i32 window_id) =|
- WindowInputEntered(i32 window_id) =|
- WindowInputLeft(i32 window_id) =|
- KeyDown(i32 window_id, u32 code_point, u32 key, u32 modifiers, u32 scancode) =|
- KeyUp(i32 window_id, u32 code_point, u32 key, u32 modifiers, u32 scancode) =|
- WindowActivated(i32 window_id) =|
- WindowDeactivated(i32 window_id) =|
- WindowStateChanged(i32 window_id, bool minimized, bool occluded) =|
- WindowCloseRequest(i32 window_id) =|
- WindowResized(i32 window_id, Gfx::IntRect new_rect) =|
-
- MenuItemActivated(i32 menu_id, i32 identifier) =|
-
- ScreenRectChanged(Gfx::IntRect rect) =|
-
- WM_WindowRemoved(i32 wm_id, i32 client_id, i32 window_id) =|
- WM_WindowStateChanged(i32 wm_id, i32 client_id, i32 window_id, i32 parent_client_id, i32 parent_window_id, bool is_active, bool is_minimized, bool is_modal, bool is_frameless, i32 window_type, [UTF8] String title, Gfx::IntRect rect, i32 progress) =|
- WM_WindowIconBitmapChanged(i32 wm_id, i32 client_id, i32 window_id, i32 icon_buffer_id, Gfx::IntSize icon_size) =|
- WM_WindowRectChanged(i32 wm_id, i32 client_id, i32 window_id, Gfx::IntRect rect) =|
-
- AsyncSetWallpaperFinished(bool success) =|
-
- DragAccepted() =|
- DragCancelled() =|
-
- DragDropped(i32 window_id, Gfx::IntPoint mouse_position, [UTF8] String text, HashMap<String,ByteBuffer> mime_data) =|
-
- UpdateSystemTheme(i32 system_theme_buffer_id) =|
-
- DisplayLinkNotification() =|
-
- Ping() =|
-}
diff --git a/Services/WindowServer/WindowFrame.cpp b/Services/WindowServer/WindowFrame.cpp
deleted file mode 100644
index fee0e2a939..0000000000
--- a/Services/WindowServer/WindowFrame.cpp
+++ /dev/null
@@ -1,382 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "ClientConnection.h"
-#include <AK/Badge.h>
-#include <LibGfx/Font.h>
-#include <LibGfx/Painter.h>
-#include <LibGfx/StylePainter.h>
-#include <LibGfx/WindowTheme.h>
-#include <WindowServer/Button.h>
-#include <WindowServer/Compositor.h>
-#include <WindowServer/Event.h>
-#include <WindowServer/Window.h>
-#include <WindowServer/WindowFrame.h>
-#include <WindowServer/WindowManager.h>
-
-namespace WindowServer {
-
-static Gfx::WindowTheme::WindowType to_theme_window_type(WindowType type)
-{
- switch (type) {
- case WindowType::Normal:
- return Gfx::WindowTheme::WindowType::Normal;
- case WindowType::Notification:
- return Gfx::WindowTheme::WindowType::Notification;
- default:
- return Gfx::WindowTheme::WindowType::Other;
- }
-}
-
-static Gfx::Bitmap* s_minimize_icon;
-static Gfx::Bitmap* s_maximize_icon;
-static Gfx::Bitmap* s_restore_icon;
-static Gfx::Bitmap* s_close_icon;
-
-static String s_last_title_button_icons_path;
-
-WindowFrame::WindowFrame(Window& window)
- : m_window(window)
-{
- auto button = make<Button>(*this, [this](auto&) {
- m_window.request_close();
- });
- m_close_button = button.ptr();
- m_buttons.append(move(button));
-
- if (window.is_resizable()) {
- auto button = make<Button>(*this, [this](auto&) {
- WindowManager::the().maximize_windows(m_window, !m_window.is_maximized());
- });
- m_maximize_button = button.ptr();
- m_buttons.append(move(button));
- }
-
- if (window.is_minimizable()) {
- auto button = make<Button>(*this, [this](auto&) {
- WindowManager::the().minimize_windows(m_window, true);
- });
- m_minimize_button = button.ptr();
- m_buttons.append(move(button));
- }
-
- set_button_icons();
-}
-
-WindowFrame::~WindowFrame()
-{
-}
-
-void WindowFrame::set_button_icons()
-{
- if (m_window.is_frameless())
- return;
-
- String icons_path = WindowManager::the().palette().title_button_icons_path();
-
- StringBuilder full_path;
- if (!s_minimize_icon || s_last_title_button_icons_path != icons_path) {
- full_path.append(icons_path);
- full_path.append("window-minimize.png");
- if (!(s_minimize_icon = Gfx::Bitmap::load_from_file(full_path.to_string()).leak_ref()))
- s_minimize_icon = Gfx::Bitmap::load_from_file("/res/icons/16x16/downward-triangle.png").leak_ref();
- full_path.clear();
- }
- if (!s_maximize_icon || s_last_title_button_icons_path != icons_path) {
- full_path.append(icons_path);
- full_path.append("window-maximize.png");
- if (!(s_maximize_icon = Gfx::Bitmap::load_from_file(full_path.to_string()).leak_ref()))
- s_maximize_icon = Gfx::Bitmap::load_from_file("/res/icons/16x16/upward-triangle.png").leak_ref();
- full_path.clear();
- }
- if (!s_restore_icon || s_last_title_button_icons_path != icons_path) {
- full_path.append(icons_path);
- full_path.append("window-restore.png");
- if (!(s_restore_icon = Gfx::Bitmap::load_from_file(full_path.to_string()).leak_ref()))
- s_restore_icon = Gfx::Bitmap::load_from_file("/res/icons/16x16/window-restore.png").leak_ref();
- full_path.clear();
- }
- if (!s_close_icon || s_last_title_button_icons_path != icons_path) {
- full_path.append(icons_path);
- full_path.append("window-close.png");
- if (!(s_close_icon = Gfx::Bitmap::load_from_file(full_path.to_string()).leak_ref()))
- s_close_icon = Gfx::Bitmap::load_from_file("/res/icons/16x16/window-close.png").leak_ref();
- full_path.clear();
- }
-
- m_close_button->set_icon(*s_close_icon);
- if (m_window.is_minimizable())
- m_minimize_button->set_icon(*s_minimize_icon);
- if (m_window.is_resizable())
- m_maximize_button->set_icon(m_window.is_maximized() ? *s_restore_icon : *s_maximize_icon);
-
- s_last_title_button_icons_path = icons_path;
-}
-
-void WindowFrame::did_set_maximized(Badge<Window>, bool maximized)
-{
- ASSERT(m_maximize_button);
- m_maximize_button->set_icon(maximized ? *s_restore_icon : *s_maximize_icon);
-}
-
-Gfx::IntRect WindowFrame::title_bar_rect() const
-{
- return Gfx::WindowTheme::current().title_bar_rect(to_theme_window_type(m_window.type()), m_window.rect(), WindowManager::the().palette());
-}
-
-Gfx::IntRect WindowFrame::title_bar_icon_rect() const
-{
- return Gfx::WindowTheme::current().title_bar_icon_rect(to_theme_window_type(m_window.type()), m_window.rect(), WindowManager::the().palette());
-}
-
-Gfx::IntRect WindowFrame::title_bar_text_rect() const
-{
- return Gfx::WindowTheme::current().title_bar_text_rect(to_theme_window_type(m_window.type()), m_window.rect(), WindowManager::the().palette());
-}
-
-Gfx::WindowTheme::WindowState WindowFrame::window_state_for_theme() const
-{
- auto& wm = WindowManager::the();
-
- if (m_flash_timer && m_flash_timer->is_active())
- return m_flash_counter & 1 ? Gfx::WindowTheme::WindowState::Active : Gfx::WindowTheme::WindowState::Inactive;
-
- if (&m_window == wm.m_highlight_window)
- return Gfx::WindowTheme::WindowState::Highlighted;
- if (&m_window == wm.m_move_window)
- return Gfx::WindowTheme::WindowState::Moving;
- if (wm.is_active_window_or_accessory(m_window))
- return Gfx::WindowTheme::WindowState::Active;
- return Gfx::WindowTheme::WindowState::Inactive;
-}
-
-void WindowFrame::paint_notification_frame(Gfx::Painter& painter)
-{
- auto palette = WindowManager::the().palette();
- Gfx::WindowTheme::current().paint_notification_frame(painter, m_window.rect(), palette, m_buttons.last().relative_rect());
-}
-
-void WindowFrame::paint_normal_frame(Gfx::Painter& painter)
-{
- auto palette = WindowManager::the().palette();
- auto& window = m_window;
- String title_text;
- if (window.client() && window.client()->is_unresponsive()) {
- StringBuilder builder;
- builder.append(window.title());
- builder.append(" (Not responding)");
- title_text = builder.to_string();
- } else {
- title_text = window.title();
- }
-
- auto leftmost_button_rect = m_buttons.is_empty() ? Gfx::IntRect() : m_buttons.last().relative_rect();
- Gfx::WindowTheme::current().paint_normal_frame(painter, window_state_for_theme(), m_window.rect(), title_text, m_window.icon(), palette, leftmost_button_rect);
-}
-
-void WindowFrame::paint(Gfx::Painter& painter)
-{
- if (m_window.is_frameless())
- return;
-
- Gfx::PainterStateSaver saver(painter);
- painter.translate(rect().location());
-
- if (m_window.type() == WindowType::Notification)
- paint_notification_frame(painter);
- else if (m_window.type() == WindowType::Normal)
- paint_normal_frame(painter);
- else
- return;
-
- for (auto& button : m_buttons) {
- button.paint(painter);
- }
-}
-
-static Gfx::IntRect frame_rect_for_window(Window& window, const Gfx::IntRect& rect)
-{
- if (window.is_frameless())
- return rect;
- return Gfx::WindowTheme::current().frame_rect_for_window(to_theme_window_type(window.type()), rect, WindowManager::the().palette());
-}
-
-static Gfx::IntRect frame_rect_for_window(Window& window)
-{
- return frame_rect_for_window(window, window.rect());
-}
-
-Gfx::IntRect WindowFrame::rect() const
-{
- return frame_rect_for_window(m_window);
-}
-
-void WindowFrame::invalidate_title_bar()
-{
- invalidate(title_bar_rect());
-}
-
-void WindowFrame::invalidate(Gfx::IntRect relative_rect)
-{
- auto frame_rect = rect();
- auto window_rect = m_window.rect();
- relative_rect.move_by(frame_rect.x() - window_rect.x(), frame_rect.y() - window_rect.y());
- m_window.invalidate(relative_rect, true);
-}
-
-void WindowFrame::notify_window_rect_changed(const Gfx::IntRect& old_rect, const Gfx::IntRect& new_rect)
-{
- layout_buttons();
-
- auto old_frame_rect = frame_rect_for_window(m_window, old_rect);
- auto& compositor = Compositor::the();
- for (auto& dirty : old_frame_rect.shatter(rect()))
- compositor.invalidate_screen(dirty);
- if (!m_window.is_opaque())
- compositor.invalidate_screen(rect());
-
- compositor.invalidate_occlusions();
-
- WindowManager::the().notify_rect_changed(m_window, old_rect, new_rect);
-}
-
-void WindowFrame::layout_buttons()
-{
- auto button_rects = Gfx::WindowTheme::current().layout_buttons(to_theme_window_type(m_window.type()), m_window.rect(), WindowManager::the().palette(), m_buttons.size());
- for (size_t i = 0; i < m_buttons.size(); i++)
- m_buttons[i].set_relative_rect(button_rects[i]);
-}
-
-void WindowFrame::on_mouse_event(const MouseEvent& event)
-{
- ASSERT(!m_window.is_fullscreen());
-
- auto& wm = WindowManager::the();
- if (m_window.type() != WindowType::Normal && m_window.type() != WindowType::Notification)
- return;
-
- if (m_window.type() == WindowType::Normal) {
- if (event.type() == Event::MouseDown)
- wm.move_to_front_and_make_active(m_window);
-
- if (m_window.blocking_modal_window())
- return;
-
- if (title_bar_icon_rect().contains(event.position())) {
- if (event.type() == Event::MouseDown && (event.button() == MouseButton::Left || event.button() == MouseButton::Right)) {
- // Manually start a potential double click. Since we're opening
- // a menu, we will only receive the MouseDown event, so we
- // need to record that fact. If the user subsequently clicks
- // on the same area, the menu will get closed, and we will
- // receive a MouseUp event, but because windows have changed
- // we don't get a MouseDoubleClick event. We can however record
- // this click, and when we receive the MouseUp event check if
- // it would have been considered a double click, if it weren't
- // for the fact that we opened and closed a window in the meanwhile
- auto& wm = WindowManager::the();
- wm.start_menu_doubleclick(m_window, event);
-
- m_window.popup_window_menu(title_bar_rect().bottom_left().translated(rect().location()), WindowMenuDefaultAction::Close);
- return;
- } else if (event.type() == Event::MouseUp && event.button() == MouseButton::Left) {
- // Since the MouseDown event opened a menu, another MouseUp
- // from the second click outside the menu wouldn't be considered
- // a double click, so let's manually check if it would otherwise
- // have been be considered to be one
- auto& wm = WindowManager::the();
- if (wm.is_menu_doubleclick(m_window, event)) {
- // It is a double click, so perform activate the default item
- m_window.window_menu_activate_default();
- }
- return;
- }
- }
- }
-
- // This is slightly hackish, but expand the title bar rect by two pixels downwards,
- // so that mouse events between the title bar and window contents don't act like
- // mouse events on the border.
- auto adjusted_title_bar_rect = title_bar_rect();
- adjusted_title_bar_rect.set_height(adjusted_title_bar_rect.height() + 2);
-
- if (adjusted_title_bar_rect.contains(event.position())) {
- wm.clear_resize_candidate();
-
- if (event.type() == Event::MouseDown)
- wm.move_to_front_and_make_active(m_window);
-
- for (auto& button : m_buttons) {
- if (button.relative_rect().contains(event.position()))
- return button.on_mouse_event(event.translated(-button.relative_rect().location()));
- }
- if (event.type() == Event::MouseDown) {
- if (m_window.type() == WindowType::Normal && event.button() == MouseButton::Right) {
- auto default_action = m_window.is_maximized() ? WindowMenuDefaultAction::Restore : WindowMenuDefaultAction::Maximize;
- m_window.popup_window_menu(event.position().translated(rect().location()), default_action);
- return;
- }
- if (m_window.is_movable() && event.button() == MouseButton::Left)
- wm.start_window_move(m_window, event.translated(rect().location()));
- }
- return;
- }
-
- if (m_window.is_resizable() && event.type() == Event::MouseMove && event.buttons() == 0) {
- constexpr ResizeDirection direction_for_hot_area[3][3] = {
- { ResizeDirection::UpLeft, ResizeDirection::Up, ResizeDirection::UpRight },
- { ResizeDirection::Left, ResizeDirection::None, ResizeDirection::Right },
- { ResizeDirection::DownLeft, ResizeDirection::Down, ResizeDirection::DownRight },
- };
- Gfx::IntRect outer_rect = { {}, rect().size() };
- ASSERT(outer_rect.contains(event.position()));
- int window_relative_x = event.x() - outer_rect.x();
- int window_relative_y = event.y() - outer_rect.y();
- int hot_area_row = min(2, window_relative_y / (outer_rect.height() / 3));
- int hot_area_column = min(2, window_relative_x / (outer_rect.width() / 3));
- wm.set_resize_candidate(m_window, direction_for_hot_area[hot_area_row][hot_area_column]);
- Compositor::the().invalidate_cursor();
- return;
- }
-
- if (m_window.is_resizable() && event.type() == Event::MouseDown && event.button() == MouseButton::Left)
- wm.start_window_resize(m_window, event.translated(rect().location()));
-}
-
-void WindowFrame::start_flash_animation()
-{
- if (!m_flash_timer) {
- m_flash_timer = Core::Timer::construct(100, [this] {
- ASSERT(m_flash_counter);
- invalidate_title_bar();
- if (!--m_flash_counter)
- m_flash_timer->stop();
- });
- }
- m_flash_counter = 8;
- m_flash_timer->start();
-}
-
-}
diff --git a/Services/WindowServer/WindowFrame.h b/Services/WindowServer/WindowFrame.h
deleted file mode 100644
index ace32b8c7c..0000000000
--- a/Services/WindowServer/WindowFrame.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <AK/Forward.h>
-#include <AK/NonnullOwnPtrVector.h>
-#include <AK/RefPtr.h>
-#include <LibCore/Forward.h>
-#include <LibGfx/Forward.h>
-#include <LibGfx/WindowTheme.h>
-
-namespace WindowServer {
-
-class Button;
-class MouseEvent;
-class Window;
-
-class WindowFrame {
-public:
- WindowFrame(Window&);
- ~WindowFrame();
-
- Gfx::IntRect rect() const;
- void paint(Gfx::Painter&);
- void on_mouse_event(const MouseEvent&);
- void notify_window_rect_changed(const Gfx::IntRect& old_rect, const Gfx::IntRect& new_rect);
- void invalidate_title_bar();
- void invalidate(Gfx::IntRect relative_rect);
-
- Gfx::IntRect title_bar_rect() const;
- Gfx::IntRect title_bar_icon_rect() const;
- Gfx::IntRect title_bar_text_rect() const;
-
- void did_set_maximized(Badge<Window>, bool);
-
- void layout_buttons();
- void set_button_icons();
-
- void start_flash_animation();
-
-private:
- void paint_notification_frame(Gfx::Painter&);
- void paint_normal_frame(Gfx::Painter&);
-
- Gfx::WindowTheme::WindowState window_state_for_theme() const;
-
- Window& m_window;
- NonnullOwnPtrVector<Button> m_buttons;
- Button* m_close_button { nullptr };
- Button* m_maximize_button { nullptr };
- Button* m_minimize_button { nullptr };
-
- RefPtr<Core::Timer> m_flash_timer;
- size_t m_flash_counter { 0 };
-};
-
-}
diff --git a/Services/WindowServer/WindowManager.cpp b/Services/WindowServer/WindowManager.cpp
deleted file mode 100644
index aa072fb0b6..0000000000
--- a/Services/WindowServer/WindowManager.cpp
+++ /dev/null
@@ -1,1509 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "WindowManager.h"
-#include "Compositor.h"
-#include "EventLoop.h"
-#include "Menu.h"
-#include "MenuBar.h"
-#include "MenuItem.h"
-#include "Screen.h"
-#include "Window.h"
-#include <AK/LogStream.h>
-#include <AK/SharedBuffer.h>
-#include <AK/StdLibExtras.h>
-#include <AK/Vector.h>
-#include <LibGfx/CharacterBitmap.h>
-#include <LibGfx/Font.h>
-#include <LibGfx/Painter.h>
-#include <LibGfx/StylePainter.h>
-#include <LibGfx/SystemTheme.h>
-#include <WindowServer/AppletManager.h>
-#include <WindowServer/Button.h>
-#include <WindowServer/ClientConnection.h>
-#include <WindowServer/Cursor.h>
-#include <WindowServer/WindowClientEndpoint.h>
-#include <errno.h>
-#include <serenity.h>
-#include <stdio.h>
-#include <time.h>
-#include <unistd.h>
-
-//#define WINDOWMANAGER_DEBUG
-//#define RESIZE_DEBUG
-//#define MOVE_DEBUG
-//#define DOUBLECLICK_DEBUG
-
-namespace WindowServer {
-
-static WindowManager* s_the;
-
-WindowManager& WindowManager::the()
-{
- ASSERT(s_the);
- return *s_the;
-}
-
-WindowManager::WindowManager(const Gfx::PaletteImpl& palette)
- : m_palette(palette)
-{
- s_the = this;
-
- reload_config(false);
-
- Compositor::the().did_construct_window_manager({});
-}
-
-WindowManager::~WindowManager()
-{
-}
-
-NonnullRefPtr<Cursor> WindowManager::get_cursor(const String& name)
-{
- static const auto s_default_cursor_path = "/res/cursors/arrow.x2y2.png";
- auto path = m_config->read_entry("Cursor", name, s_default_cursor_path);
- auto gb = Gfx::Bitmap::load_from_file(path);
- if (gb)
- return Cursor::create(*gb, path);
- return Cursor::create(*Gfx::Bitmap::load_from_file(s_default_cursor_path), s_default_cursor_path);
-}
-
-void WindowManager::reload_config(bool set_screen)
-{
- m_config = Core::ConfigFile::open("/etc/WindowServer/WindowServer.ini");
-
- m_double_click_speed = m_config->read_num_entry("Input", "DoubleClickSpeed", 250);
-
- if (set_screen) {
- set_resolution(m_config->read_num_entry("Screen", "Width", 1920), m_config->read_num_entry("Screen", "Height", 1080));
- }
-
- m_hidden_cursor = get_cursor("Hidden");
- m_arrow_cursor = get_cursor("Arrow");
- m_hand_cursor = get_cursor("Hand");
- m_help_cursor = get_cursor("Help");
- m_resize_horizontally_cursor = get_cursor("ResizeH");
- m_resize_vertically_cursor = get_cursor("ResizeV");
- m_resize_diagonally_tlbr_cursor = get_cursor("ResizeDTLBR");
- m_resize_diagonally_bltr_cursor = get_cursor("ResizeDBLTR");
- m_resize_column_cursor = get_cursor("ResizeColumn");
- m_resize_row_cursor = get_cursor("ResizeRow");
- m_i_beam_cursor = get_cursor("IBeam");
- m_disallowed_cursor = get_cursor("Disallowed");
- m_move_cursor = get_cursor("Move");
- m_drag_cursor = get_cursor("Drag");
- m_wait_cursor = get_cursor("Wait");
- m_crosshair_cursor = get_cursor("Crosshair");
-}
-
-const Gfx::Font& WindowManager::font() const
-{
- return Gfx::FontDatabase::default_font();
-}
-
-const Gfx::Font& WindowManager::window_title_font() const
-{
- return Gfx::FontDatabase::default_bold_font();
-}
-
-bool WindowManager::set_resolution(int width, int height)
-{
- bool success = Compositor::the().set_resolution(width, height);
- MenuManager::the().set_needs_window_resize();
- ClientConnection::for_each_client([&](ClientConnection& client) {
- client.notify_about_new_screen_rect(Screen::the().rect());
- });
- if (success) {
- for_each_window([](Window& window) {
- window.recalculate_rect();
- return IterationDecision::Continue;
- });
- }
- if (m_config) {
- if (success) {
- dbg() << "Saving resolution: " << Gfx::IntSize(width, height) << " to config file at " << m_config->file_name();
- m_config->write_num_entry("Screen", "Width", width);
- m_config->write_num_entry("Screen", "Height", height);
- m_config->sync();
- } else {
- dbg() << "Saving fallback resolution: " << resolution() << " to config file at " << m_config->file_name();
- m_config->write_num_entry("Screen", "Width", resolution().width());
- m_config->write_num_entry("Screen", "Height", resolution().height());
- m_config->sync();
- }
- }
- return success;
-}
-
-Gfx::IntSize WindowManager::resolution() const
-{
- return Screen::the().size();
-}
-
-void WindowManager::set_acceleration_factor(double factor)
-{
- Screen::the().set_acceleration_factor(factor);
- dbgln("Saving acceleration factor {} to config file at {}", factor, m_config->file_name());
- m_config->write_entry("Mouse", "AccelerationFactor", String::formatted("{}", factor));
- m_config->sync();
-}
-
-void WindowManager::set_scroll_step_size(unsigned step_size)
-{
- Screen::the().set_scroll_step_size(step_size);
- dbgln("Saving scroll step size {} to config file at {}", step_size, m_config->file_name());
- m_config->write_entry("Mouse", "ScrollStepSize", String::number(step_size));
- m_config->sync();
-}
-
-void WindowManager::add_window(Window& window)
-{
- bool is_first_window = m_windows_in_order.is_empty();
-
- m_windows_in_order.append(&window);
-
- if (window.is_fullscreen()) {
- Core::EventLoop::current().post_event(window, make<ResizeEvent>(Screen::the().rect()));
- window.set_rect(Screen::the().rect());
- }
-
- if (window.type() != WindowType::Desktop || is_first_window)
- set_active_window(&window);
-
- if (m_switcher.is_visible() && window.type() != WindowType::WindowSwitcher)
- m_switcher.refresh();
-
- Compositor::the().invalidate_occlusions();
-
- if (window.listens_to_wm_events()) {
- for_each_window([&](Window& other_window) {
- if (&window != &other_window) {
- tell_wm_listener_about_window(window, other_window);
- tell_wm_listener_about_window_icon(window, other_window);
- }
- return IterationDecision::Continue;
- });
- }
-
- tell_wm_listeners_window_state_changed(window);
-}
-
-void WindowManager::move_to_front_and_make_active(Window& window)
-{
- auto move_window_to_front = [&](Window& wnd, bool make_active, bool make_input) {
- if (wnd.is_accessory()) {
- auto* parent = wnd.parent_window();
- do_move_to_front(*parent, true, false);
- make_active = false;
-
- for (auto& accessory_window : parent->accessory_windows()) {
- if (accessory_window && accessory_window.ptr() != &wnd)
- do_move_to_front(*accessory_window, false, false);
- }
- }
-
- do_move_to_front(wnd, make_active, make_input);
- };
-
- // If a window that is currently blocked by a modal child is being
- // brought to the front, bring the entire stack of modal windows
- // to the front and activate the modal window. Also set the
- // active input window to that same window (which would pull
- // active input from any accessory window)
- for_each_window_in_modal_stack(window, [&](auto& w, bool is_stack_top) {
- move_window_to_front(w, is_stack_top, is_stack_top);
- return IterationDecision::Continue;
- });
-
- Compositor::the().invalidate_occlusions();
-}
-
-void WindowManager::do_move_to_front(Window& window, bool make_active, bool make_input)
-{
- if (m_windows_in_order.tail() != &window)
- window.invalidate();
- m_windows_in_order.remove(&window);
- m_windows_in_order.append(&window);
-
- if (make_active)
- set_active_window(&window, make_input);
-
- if (m_switcher.is_visible()) {
- m_switcher.refresh();
- if (!window.is_accessory()) {
- m_switcher.select_window(window);
- set_highlight_window(&window);
- }
- }
-
- for (auto& child_window : window.child_windows()) {
- if (child_window)
- do_move_to_front(*child_window, make_active, make_input);
- }
-}
-
-void WindowManager::remove_window(Window& window)
-{
- m_windows_in_order.remove(&window);
- auto* active = active_window();
- auto* active_input = active_input_window();
- if (active == &window || active_input == &window || (active && window.is_descendant_of(*active)) || (active_input && active_input != active && window.is_descendant_of(*active_input)))
- pick_new_active_window(&window);
-
- Compositor::the().invalidate_screen(window.frame().rect());
-
- if (m_switcher.is_visible() && window.type() != WindowType::WindowSwitcher)
- m_switcher.refresh();
-
- Compositor::the().invalidate_occlusions();
-
- for_each_window_listening_to_wm_events([&window](Window& listener) {
- if (!(listener.wm_event_mask() & WMEventMask::WindowRemovals))
- return IterationDecision::Continue;
- if (!window.is_internal() && !window.is_modal())
- listener.client()->post_message(Messages::WindowClient::WM_WindowRemoved(listener.window_id(), window.client_id(), window.window_id()));
- return IterationDecision::Continue;
- });
-}
-
-void WindowManager::tell_wm_listener_about_window(Window& listener, Window& window)
-{
- if (!(listener.wm_event_mask() & WMEventMask::WindowStateChanges))
- return;
- if (window.is_internal())
- return;
- auto* parent = window.parent_window();
- listener.client()->post_message(Messages::WindowClient::WM_WindowStateChanged(listener.window_id(), window.client_id(), window.window_id(), parent ? parent->client_id() : -1, parent ? parent->window_id() : -1, window.is_active(), window.is_minimized(), window.is_modal_dont_unparent(), window.is_frameless(), (i32)window.type(), window.title(), window.rect(), window.progress()));
-}
-
-void WindowManager::tell_wm_listener_about_window_rect(Window& listener, Window& window)
-{
- if (!(listener.wm_event_mask() & WMEventMask::WindowRectChanges))
- return;
- if (window.is_internal())
- return;
- listener.client()->post_message(Messages::WindowClient::WM_WindowRectChanged(listener.window_id(), window.client_id(), window.window_id(), window.rect()));
-}
-
-void WindowManager::tell_wm_listener_about_window_icon(Window& listener, Window& window)
-{
- if (!(listener.wm_event_mask() & WMEventMask::WindowIconChanges))
- return;
- if (window.is_internal())
- return;
- if (window.icon().shbuf_id() == -1)
- return;
-#ifdef WINDOWMANAGER_DEBUG
- dbg() << "WindowServer: Sharing icon buffer " << window.icon().shbuf_id() << " with PID " << listener.client()->client_pid();
-#endif
- if (shbuf_allow_pid(window.icon().shbuf_id(), listener.client()->client_pid()) < 0) {
- ASSERT_NOT_REACHED();
- }
- listener.client()->post_message(Messages::WindowClient::WM_WindowIconBitmapChanged(listener.window_id(), window.client_id(), window.window_id(), window.icon().shbuf_id(), window.icon().size()));
-}
-
-void WindowManager::tell_wm_listeners_window_state_changed(Window& window)
-{
- for_each_window_listening_to_wm_events([&](Window& listener) {
- tell_wm_listener_about_window(listener, window);
- return IterationDecision::Continue;
- });
-}
-
-void WindowManager::tell_wm_listeners_window_icon_changed(Window& window)
-{
- for_each_window_listening_to_wm_events([&](Window& listener) {
- tell_wm_listener_about_window_icon(listener, window);
- return IterationDecision::Continue;
- });
-}
-
-void WindowManager::tell_wm_listeners_window_rect_changed(Window& window)
-{
- for_each_window_listening_to_wm_events([&](Window& listener) {
- tell_wm_listener_about_window_rect(listener, window);
- return IterationDecision::Continue;
- });
-}
-
-void WindowManager::notify_title_changed(Window& window)
-{
- if (window.type() != WindowType::Normal)
- return;
-#ifdef WINDOWMANAGER_DEBUG
- dbg() << "[WM] Window{" << &window << "} title set to \"" << window.title() << '"';
-#endif
- if (m_switcher.is_visible())
- m_switcher.refresh();
-
- tell_wm_listeners_window_state_changed(window);
-}
-
-void WindowManager::notify_modal_unparented(Window& window)
-{
- if (window.type() != WindowType::Normal)
- return;
-#ifdef WINDOWMANAGER_DEBUG
- dbg() << "[WM] Modal Window{" << &window << "} was unparented";
-#endif
- if (m_switcher.is_visible())
- m_switcher.refresh();
-
- tell_wm_listeners_window_state_changed(window);
-}
-
-void WindowManager::notify_rect_changed(Window& window, [[maybe_unused]] const Gfx::IntRect& old_rect, [[maybe_unused]] const Gfx::IntRect& new_rect)
-{
-#ifdef RESIZE_DEBUG
- dbg() << "[WM] Window " << &window << " rect changed " << old_rect << " -> " << new_rect;
-#endif
- if (m_switcher.is_visible() && window.type() != WindowType::WindowSwitcher)
- m_switcher.refresh();
-
- tell_wm_listeners_window_rect_changed(window);
-
- if (window.type() == WindowType::MenuApplet)
- AppletManager::the().calculate_applet_rects(MenuManager::the().window());
-
- MenuManager::the().refresh();
-}
-
-void WindowManager::notify_opacity_changed(Window&)
-{
- Compositor::the().invalidate_occlusions();
-}
-
-void WindowManager::notify_minimization_state_changed(Window& window)
-{
- tell_wm_listeners_window_state_changed(window);
-
- if (window.client())
- window.client()->post_message(Messages::WindowClient::WindowStateChanged(window.window_id(), window.is_minimized(), window.is_occluded()));
-
- if (window.is_active() && window.is_minimized())
- pick_new_active_window(&window);
-}
-
-void WindowManager::notify_occlusion_state_changed(Window& window)
-{
- if (window.client())
- window.client()->post_message(Messages::WindowClient::WindowStateChanged(window.window_id(), window.is_minimized(), window.is_occluded()));
-}
-
-void WindowManager::notify_progress_changed(Window& window)
-{
- tell_wm_listeners_window_state_changed(window);
-}
-
-bool WindowManager::pick_new_active_window(Window* previous_active)
-{
- bool new_window_picked = false;
- Window* first_candidate = nullptr;
- for_each_visible_window_of_type_from_front_to_back(WindowType::Normal, [&](Window& candidate) {
- if (candidate.is_destroyed())
- return IterationDecision::Continue;
- if (previous_active != first_candidate)
- first_candidate = &candidate;
- if ((!previous_active && !candidate.is_accessory()) || (previous_active && !candidate.is_accessory_of(*previous_active))) {
- set_active_window(&candidate);
- new_window_picked = true;
- return IterationDecision::Break;
- }
- return IterationDecision::Continue;
- });
- if (!new_window_picked) {
- set_active_window(first_candidate);
- new_window_picked = first_candidate != nullptr;
- }
- return new_window_picked;
-}
-
-void WindowManager::start_window_move(Window& window, const MouseEvent& event)
-{
-#ifdef MOVE_DEBUG
- dbg() << "[WM] Begin moving Window{" << &window << "}";
-#endif
- move_to_front_and_make_active(window);
- m_move_window = window;
- m_move_window->set_default_positioned(false);
- m_move_origin = event.position();
- m_move_window_origin = window.position();
- window.invalidate();
-}
-
-void WindowManager::start_window_resize(Window& window, const Gfx::IntPoint& position, MouseButton button)
-{
- move_to_front_and_make_active(window);
- constexpr ResizeDirection direction_for_hot_area[3][3] = {
- { ResizeDirection::UpLeft, ResizeDirection::Up, ResizeDirection::UpRight },
- { ResizeDirection::Left, ResizeDirection::None, ResizeDirection::Right },
- { ResizeDirection::DownLeft, ResizeDirection::Down, ResizeDirection::DownRight },
- };
- Gfx::IntRect outer_rect = window.frame().rect();
- if (!outer_rect.contains(position)) {
- // FIXME: This used to be an ASSERT but crashing WindowServer over this seems silly.
- dbg() << "FIXME: !outer_rect.contains(position): outer_rect=" << outer_rect << ", position=" << position;
- }
- int window_relative_x = position.x() - outer_rect.x();
- int window_relative_y = position.y() - outer_rect.y();
- int hot_area_row = min(2, window_relative_y / (outer_rect.height() / 3));
- int hot_area_column = min(2, window_relative_x / (outer_rect.width() / 3));
- m_resize_direction = direction_for_hot_area[hot_area_row][hot_area_column];
- if (m_resize_direction == ResizeDirection::None) {
- ASSERT(!m_resize_window);
- return;
- }
-
-#ifdef RESIZE_DEBUG
- dbg() << "[WM] Begin resizing Window{" << &window << "}";
-#endif
- m_resizing_mouse_button = button;
- m_resize_window = window;
- m_resize_origin = position;
- m_resize_window_original_rect = window.rect();
-
- m_active_input_tracking_window = nullptr;
-
- window.invalidate();
-
- if (hot_area_row == 0 || hot_area_column == 0) {
- m_resize_window->set_default_positioned(false);
- }
-}
-
-void WindowManager::start_window_resize(Window& window, const MouseEvent& event)
-{
- start_window_resize(window, event.position(), event.button());
-}
-
-bool WindowManager::process_ongoing_window_move(MouseEvent& event, Window*& hovered_window)
-{
- if (!m_move_window)
- return false;
- if (event.type() == Event::MouseUp && event.button() == MouseButton::Left) {
-#ifdef MOVE_DEBUG
- dbg() << "[WM] Finish moving Window{" << m_move_window << "}";
-#endif
-
- m_move_window->invalidate();
- if (m_move_window->rect().contains(event.position()))
- hovered_window = m_move_window;
- if (m_move_window->is_resizable()) {
- process_event_for_doubleclick(*m_move_window, event);
- if (event.type() == Event::MouseDoubleClick) {
-#if defined(DOUBLECLICK_DEBUG)
- dbgln("[WM] Click up became doubleclick!");
-#endif
- m_move_window->set_maximized(!m_move_window->is_maximized());
- }
- }
- m_move_window = nullptr;
- return true;
- }
- if (event.type() == Event::MouseMove) {
-
-#ifdef MOVE_DEBUG
- dbg() << "[WM] Moving, origin: " << m_move_origin << ", now: " << event.position();
- if (m_move_window->is_maximized()) {
- dbgln(" [!] The window is still maximized. Not moving yet.");
- }
-
-#endif
-
- const int tiling_deadzone = 10;
- const int secondary_deadzone = 2;
-
- if (m_move_window->is_maximized()) {
- auto pixels_moved_from_start = event.position().pixels_moved(m_move_origin);
- // dbg() << "[WM] " << pixels_moved_from_start << " moved since start of window move";
- if (pixels_moved_from_start > 5) {
- // dbgln("[WM] de-maximizing window");
- m_move_origin = event.position();
- if (m_move_origin.y() <= secondary_deadzone)
- return true;
- auto width_before_resize = m_move_window->width();
- m_move_window->set_maximized(false);
- m_move_window->move_to(m_move_origin.x() - (m_move_window->width() * ((float)m_move_origin.x() / width_before_resize)), m_move_origin.y());
- m_move_window_origin = m_move_window->position();
- }
- } else {
- bool is_resizable = m_move_window->is_resizable();
- auto pixels_moved_from_start = event.position().pixels_moved(m_move_origin);
- auto desktop = desktop_rect();
-
- if (is_resizable && event.x() <= tiling_deadzone) {
- if (event.y() <= tiling_deadzone + desktop.top())
- m_move_window->set_tiled(WindowTileType::TopLeft);
- else if (event.y() >= desktop.height() - tiling_deadzone)
- m_move_window->set_tiled(WindowTileType::BottomLeft);
- else
- m_move_window->set_tiled(WindowTileType::Left);
- } else if (is_resizable && event.x() >= Screen::the().width() - tiling_deadzone) {
- if (event.y() <= tiling_deadzone + desktop.top())
- m_move_window->set_tiled(WindowTileType::TopRight);
- else if (event.y() >= desktop.height() - tiling_deadzone)
- m_move_window->set_tiled(WindowTileType::BottomRight);
- else
- m_move_window->set_tiled(WindowTileType::Right);
- } else if (is_resizable && event.y() <= secondary_deadzone + desktop.top()) {
- m_move_window->set_tiled(WindowTileType::Top);
- } else if (is_resizable && event.y() >= desktop.bottom() - secondary_deadzone) {
- m_move_window->set_tiled(WindowTileType::Bottom);
- } else if (pixels_moved_from_start > 5 || m_move_window->tiled() == WindowTileType::None) {
- m_move_window->set_tiled(WindowTileType::None);
- Gfx::IntPoint pos = m_move_window_origin.translated(event.position() - m_move_origin);
- m_move_window->set_position_without_repaint(pos);
- if (m_move_window->rect().contains(event.position()))
- hovered_window = m_move_window;
- }
- return true;
- }
- }
- return false;
-}
-
-bool WindowManager::process_ongoing_window_resize(const MouseEvent& event, Window*& hovered_window)
-{
- if (!m_resize_window)
- return false;
-
- if (event.type() == Event::MouseUp && event.button() == m_resizing_mouse_button) {
-#ifdef RESIZE_DEBUG
- dbg() << "[WM] Finish resizing Window{" << m_resize_window << "}";
-#endif
- Core::EventLoop::current().post_event(*m_resize_window, make<ResizeEvent>(m_resize_window->rect()));
- m_resize_window->invalidate();
- if (m_resize_window->rect().contains(event.position()))
- hovered_window = m_resize_window;
- m_resize_window = nullptr;
- m_resizing_mouse_button = MouseButton::None;
- return true;
- }
-
- if (event.type() != Event::MouseMove)
- return false;
-
- int diff_x = event.x() - m_resize_origin.x();
- int diff_y = event.y() - m_resize_origin.y();
-
- int change_w = 0;
- int change_h = 0;
-
- switch (m_resize_direction) {
- case ResizeDirection::DownRight:
- change_w = diff_x;
- change_h = diff_y;
- break;
- case ResizeDirection::Right:
- change_w = diff_x;
- break;
- case ResizeDirection::UpRight:
- change_w = diff_x;
- change_h = -diff_y;
- break;
- case ResizeDirection::Up:
- change_h = -diff_y;
- break;
- case ResizeDirection::UpLeft:
- change_w = -diff_x;
- change_h = -diff_y;
- break;
- case ResizeDirection::Left:
- change_w = -diff_x;
- break;
- case ResizeDirection::DownLeft:
- change_w = -diff_x;
- change_h = diff_y;
- break;
- case ResizeDirection::Down:
- change_h = diff_y;
- break;
- default:
- ASSERT_NOT_REACHED();
- }
-
- auto new_rect = m_resize_window_original_rect;
-
- // First, size the new rect.
- Gfx::IntSize minimum_size { 50, 50 };
-
- new_rect.set_width(max(minimum_size.width(), new_rect.width() + change_w));
- new_rect.set_height(max(minimum_size.height(), new_rect.height() + change_h));
-
- if (!m_resize_window->size_increment().is_null()) {
- int horizontal_incs = (new_rect.width() - m_resize_window->base_size().width()) / m_resize_window->size_increment().width();
- new_rect.set_width(m_resize_window->base_size().width() + horizontal_incs * m_resize_window->size_increment().width());
- int vertical_incs = (new_rect.height() - m_resize_window->base_size().height()) / m_resize_window->size_increment().height();
- new_rect.set_height(m_resize_window->base_size().height() + vertical_incs * m_resize_window->size_increment().height());
- }
-
- if (m_resize_window->resize_aspect_ratio().has_value()) {
- auto& ratio = m_resize_window->resize_aspect_ratio().value();
- if (abs(change_w) > abs(change_h)) {
- new_rect.set_height(new_rect.width() * ratio.height() / ratio.width());
- } else {
- new_rect.set_width(new_rect.height() * ratio.width() / ratio.height());
- }
- }
-
- // Second, set its position so that the sides of the window
- // that end up moving are the same ones as the user is dragging,
- // no matter which part of the logic above caused us to decide
- // to resize by this much.
- switch (m_resize_direction) {
- case ResizeDirection::DownRight:
- case ResizeDirection::Right:
- case ResizeDirection::Down:
- break;
- case ResizeDirection::Left:
- case ResizeDirection::Up:
- case ResizeDirection::UpLeft:
- new_rect.set_right_without_resize(m_resize_window_original_rect.right());
- new_rect.set_bottom_without_resize(m_resize_window_original_rect.bottom());
- break;
- case ResizeDirection::UpRight:
- new_rect.set_bottom_without_resize(m_resize_window_original_rect.bottom());
- break;
- case ResizeDirection::DownLeft:
- new_rect.set_right_without_resize(m_resize_window_original_rect.right());
- break;
- default:
- ASSERT_NOT_REACHED();
- }
-
- if (new_rect.contains(event.position()))
- hovered_window = m_resize_window;
-
- if (m_resize_window->rect() == new_rect)
- return true;
-#ifdef RESIZE_DEBUG
- dbg() << "[WM] Resizing, original: " << m_resize_window_original_rect << ", now: " << new_rect;
-#endif
- m_resize_window->set_rect(new_rect);
- Core::EventLoop::current().post_event(*m_resize_window, make<ResizeEvent>(new_rect));
- return true;
-}
-
-bool WindowManager::process_ongoing_drag(MouseEvent& event, Window*& hovered_window)
-{
- if (!m_dnd_client)
- return false;
-
- if (event.type() == Event::MouseMove) {
- // We didn't let go of the drag yet, see if we should send some drag move events..
- for_each_visible_window_from_front_to_back([&](Window& window) {
- if (!window.rect().contains(event.position()))
- return IterationDecision::Continue;
- hovered_window = &window;
- auto translated_event = event.translated(-window.position());
- translated_event.set_drag(true);
- translated_event.set_mime_data(*m_dnd_mime_data);
- deliver_mouse_event(window, translated_event);
- return IterationDecision::Break;
- });
- }
-
- if (!(event.type() == Event::MouseUp && event.button() == MouseButton::Left))
- return true;
-
- hovered_window = nullptr;
- for_each_visible_window_from_front_to_back([&](auto& window) {
- if (window.frame().rect().contains(event.position())) {
- hovered_window = &window;
- return IterationDecision::Break;
- }
- return IterationDecision::Continue;
- });
-
- if (hovered_window) {
- m_dnd_client->post_message(Messages::WindowClient::DragAccepted());
- if (hovered_window->client()) {
- auto translated_event = event.translated(-hovered_window->position());
- hovered_window->client()->post_message(Messages::WindowClient::DragDropped(hovered_window->window_id(), translated_event.position(), m_dnd_text, m_dnd_mime_data->all_data()));
- }
- } else {
- m_dnd_client->post_message(Messages::WindowClient::DragCancelled());
- }
-
- end_dnd_drag();
- return true;
-}
-
-void WindowManager::set_cursor_tracking_button(Button* button)
-{
- m_cursor_tracking_button = button;
-}
-
-auto WindowManager::DoubleClickInfo::metadata_for_button(MouseButton button) const -> const ClickMetadata&
-{
- switch (button) {
- case MouseButton::Left:
- return m_left;
- case MouseButton::Right:
- return m_right;
- case MouseButton::Middle:
- return m_middle;
- case MouseButton::Back:
- return m_back;
- case MouseButton::Forward:
- return m_forward;
- default:
- ASSERT_NOT_REACHED();
- }
-}
-
-auto WindowManager::DoubleClickInfo::metadata_for_button(MouseButton button) -> ClickMetadata&
-{
- switch (button) {
- case MouseButton::Left:
- return m_left;
- case MouseButton::Right:
- return m_right;
- case MouseButton::Middle:
- return m_middle;
- case MouseButton::Back:
- return m_back;
- case MouseButton::Forward:
- return m_forward;
- default:
- ASSERT_NOT_REACHED();
- }
-}
-
-// #define DOUBLECLICK_DEBUG
-
-bool WindowManager::is_considered_doubleclick(const MouseEvent& event, const DoubleClickInfo::ClickMetadata& metadata) const
-{
- int elapsed_since_last_click = metadata.clock.elapsed();
- if (elapsed_since_last_click < m_double_click_speed) {
- auto diff = event.position() - metadata.last_position;
- auto distance_travelled_squared = diff.x() * diff.x() + diff.y() * diff.y();
- if (distance_travelled_squared <= (m_max_distance_for_double_click * m_max_distance_for_double_click))
- return true;
- }
- return false;
-}
-
-void WindowManager::start_menu_doubleclick(Window& window, const MouseEvent& event)
-{
- // This is a special case. Basically, we're trying to determine whether
- // double clicking on the window menu icon happened. In this case, the
- // WindowFrame only receives a MouseDown event, and since the window
- // menu popus up, it does not see the MouseUp event. But, if they subsequently
- // click there again, the menu is closed and we receive a MouseUp event.
- // So, in order to be able to detect a double click when a menu is being
- // opened by the MouseDown event, we need to consider the MouseDown event
- // as a potential double-click trigger
- ASSERT(event.type() == Event::MouseDown);
-
- auto& metadata = m_double_click_info.metadata_for_button(event.button());
- if (&window != m_double_click_info.m_clicked_window) {
- // we either haven't clicked anywhere, or we haven't clicked on this
- // window. set the current click window, and reset the timers.
-#if defined(DOUBLECLICK_DEBUG)
- dbg() << "Initial mousedown on window " << &window << " for menu (previous was " << m_double_click_info.m_clicked_window << ')';
-#endif
- m_double_click_info.m_clicked_window = window;
- m_double_click_info.reset();
- }
-
- metadata.last_position = event.position();
- metadata.clock.start();
-}
-
-bool WindowManager::is_menu_doubleclick(Window& window, const MouseEvent& event) const
-{
- ASSERT(event.type() == Event::MouseUp);
-
- if (&window != m_double_click_info.m_clicked_window)
- return false;
-
- auto& metadata = m_double_click_info.metadata_for_button(event.button());
- if (!metadata.clock.is_valid())
- return false;
-
- return is_considered_doubleclick(event, metadata);
-}
-
-void WindowManager::process_event_for_doubleclick(Window& window, MouseEvent& event)
-{
- // We only care about button presses (because otherwise it's not a doubleclick, duh!)
- ASSERT(event.type() == Event::MouseUp);
-
- if (&window != m_double_click_info.m_clicked_window) {
- // we either haven't clicked anywhere, or we haven't clicked on this
- // window. set the current click window, and reset the timers.
-#if defined(DOUBLECLICK_DEBUG)
- dbg() << "Initial mouseup on window " << &window << " (previous was " << m_double_click_info.m_clicked_window << ')';
-#endif
- m_double_click_info.m_clicked_window = window;
- m_double_click_info.reset();
- }
-
- auto& metadata = m_double_click_info.metadata_for_button(event.button());
-
- if (!metadata.clock.is_valid() || !is_considered_doubleclick(event, metadata)) {
- // either the clock is invalid because we haven't clicked on this
- // button on this window yet, so there's nothing to do, or this
- // isn't considered to be a double click. either way, restart the
- // clock
- metadata.clock.start();
- } else {
-#if defined(DOUBLECLICK_DEBUG)
- dbg() << "Transforming MouseUp to MouseDoubleClick (" << metadata.clock.elapsed() << " < " << m_double_click_speed << ")!";
-#endif
- event = MouseEvent(Event::MouseDoubleClick, event.position(), event.buttons(), event.button(), event.modifiers(), event.wheel_delta());
- // invalidate this now we've delivered a doubleclick, otherwise
- // tripleclick will deliver two doubleclick events (incorrectly).
- metadata.clock = {};
- }
-
- metadata.last_position = event.position();
-}
-
-void WindowManager::deliver_mouse_event(Window& window, MouseEvent& event)
-{
- window.dispatch_event(event);
- if (event.type() == Event::MouseUp) {
- process_event_for_doubleclick(window, event);
- if (event.type() == Event::MouseDoubleClick)
- window.dispatch_event(event);
- }
-}
-
-void WindowManager::process_mouse_event(MouseEvent& event, Window*& hovered_window)
-{
- HashTable<Window*> windows_who_received_mouse_event_due_to_cursor_tracking;
-
- // We need to process ongoing drag events first. Otherwise, global tracking
- // and dnd collides, leading to duplicate GUI::DragOperation instances
- if (process_ongoing_drag(event, hovered_window))
- return;
-
- for (auto* window = m_windows_in_order.tail(); window; window = window->prev()) {
- if (!window->global_cursor_tracking() || !window->is_visible() || window->is_minimized() || window->blocking_modal_window())
- continue;
- windows_who_received_mouse_event_due_to_cursor_tracking.set(window);
- auto translated_event = event.translated(-window->position());
- deliver_mouse_event(*window, translated_event);
- }
-
- hovered_window = nullptr;
-
- if (process_ongoing_window_move(event, hovered_window))
- return;
-
- if (process_ongoing_window_resize(event, hovered_window))
- return;
-
- if (m_cursor_tracking_button)
- return m_cursor_tracking_button->on_mouse_event(event.translated(-m_cursor_tracking_button->screen_rect().location()));
-
- // This is quite hackish, but it's how the Button hover effect is implemented.
- if (m_hovered_button && event.type() == Event::MouseMove)
- m_hovered_button->on_mouse_event(event.translated(-m_hovered_button->screen_rect().location()));
-
- // FIXME: Now that the menubar has a dedicated window, is this special-casing really necessary?
- if (MenuManager::the().has_open_menu() || menubar_rect().contains(event.position())) {
- for_each_visible_window_of_type_from_front_to_back(WindowType::MenuApplet, [&](auto& window) {
- if (!window.rect_in_menubar().contains(event.position()))
- return IterationDecision::Continue;
- hovered_window = &window;
- return IterationDecision::Break;
- });
- clear_resize_candidate();
- MenuManager::the().dispatch_event(event);
- return;
- }
-
- Window* event_window_with_frame = nullptr;
-
- if (m_active_input_tracking_window) {
- // At this point, we have delivered the start of an input sequence to a
- // client application. We must keep delivering to that client
- // application until the input sequence is done.
- //
- // This prevents e.g. moving on one window out of the bounds starting
- // a move in that other unrelated window, and other silly shenanigans.
- if (!windows_who_received_mouse_event_due_to_cursor_tracking.contains(m_active_input_tracking_window)) {
- auto translated_event = event.translated(-m_active_input_tracking_window->position());
- deliver_mouse_event(*m_active_input_tracking_window, translated_event);
- windows_who_received_mouse_event_due_to_cursor_tracking.set(m_active_input_tracking_window.ptr());
- }
- if (event.type() == Event::MouseUp && event.buttons() == 0) {
- m_active_input_tracking_window = nullptr;
- }
-
- for_each_visible_window_from_front_to_back([&](auto& window) {
- if (window.frame().rect().contains(event.position())) {
- hovered_window = &window;
- return IterationDecision::Break;
- }
- return IterationDecision::Continue;
- });
- } else {
- auto process_mouse_event_for_window = [&](Window& window) {
- if (&window != m_resize_candidate.ptr())
- clear_resize_candidate();
-
- // First check if we should initiate a move or resize (Logo+LMB or Logo+RMB).
- // In those cases, the event is swallowed by the window manager.
- if (window.is_movable()) {
- if (!window.is_fullscreen() && m_keyboard_modifiers == Mod_Logo && event.type() == Event::MouseDown && event.button() == MouseButton::Left) {
- hovered_window = &window;
- start_window_move(window, event);
- return;
- }
- if (window.is_resizable() && m_keyboard_modifiers == Mod_Logo && event.type() == Event::MouseDown && event.button() == MouseButton::Right && !window.blocking_modal_window()) {
- hovered_window = &window;
- start_window_resize(window, event);
- return;
- }
- }
-
- if (m_keyboard_modifiers == Mod_Logo && event.type() == Event::MouseWheel) {
- float opacity_change = -event.wheel_delta() * 0.05f;
- float new_opacity = window.opacity() + opacity_change;
- if (new_opacity < 0.05f)
- new_opacity = 0.05f;
- if (new_opacity > 1.0f)
- new_opacity = 1.0f;
- window.set_opacity(new_opacity);
- return;
- }
-
- ASSERT(window.frame().rect().contains(event.position()));
- if (event.type() == Event::MouseDown) {
- // We're clicking on something that's blocked by a modal window.
- // Flash the modal window to let the user know about it.
- if (auto* blocking_modal_window = window.blocking_modal_window())
- blocking_modal_window->frame().start_flash_animation();
-
- if (window.type() == WindowType::Normal)
- move_to_front_and_make_active(window);
- else if (window.type() == WindowType::Desktop)
- set_active_window(&window);
- }
-
- // Well okay, let's see if we're hitting the frame or the window inside the frame.
- if (window.rect().contains(event.position())) {
- hovered_window = &window;
- if (!window.global_cursor_tracking() && !windows_who_received_mouse_event_due_to_cursor_tracking.contains(&window) && !window.blocking_modal_window()) {
- auto translated_event = event.translated(-window.position());
- deliver_mouse_event(window, translated_event);
- if (event.type() == Event::MouseDown) {
- m_active_input_tracking_window = window;
- }
- }
- return;
- }
-
- // We are hitting the frame, pass the event along to WindowFrame.
- window.frame().on_mouse_event(event.translated(-window.frame().rect().location()));
- event_window_with_frame = &window;
- };
-
- if (auto* fullscreen_window = active_fullscreen_window()) {
- process_mouse_event_for_window(*fullscreen_window);
- } else {
- for_each_visible_window_from_front_to_back([&](Window& window) {
- auto window_frame_rect = window.frame().rect();
- if (!window_frame_rect.contains(event.position()))
- return IterationDecision::Continue;
- process_mouse_event_for_window(window);
- return IterationDecision::Break;
- });
- }
-
- // Clicked outside of any window
- if (!hovered_window && !event_window_with_frame && event.type() == Event::MouseDown)
- set_active_window(nullptr);
- }
-
- if (event_window_with_frame != m_resize_candidate.ptr())
- clear_resize_candidate();
-}
-
-void WindowManager::clear_resize_candidate()
-{
- if (m_resize_candidate)
- Compositor::the().invalidate_cursor();
- m_resize_candidate = nullptr;
-}
-
-Gfx::IntRect WindowManager::menubar_rect() const
-{
- if (active_fullscreen_window())
- return {};
- return MenuManager::the().menubar_rect();
-}
-
-Gfx::IntRect WindowManager::desktop_rect() const
-{
- if (active_fullscreen_window())
- return {};
- return {
- 0,
- menubar_rect().bottom() + 1,
- Screen::the().width(),
- Screen::the().height() - menubar_rect().height() - 28
- };
-}
-
-void WindowManager::event(Core::Event& event)
-{
- if (static_cast<Event&>(event).is_mouse_event()) {
- Window* hovered_window = nullptr;
- process_mouse_event(static_cast<MouseEvent&>(event), hovered_window);
- set_hovered_window(hovered_window);
- return;
- }
-
- if (static_cast<Event&>(event).is_key_event()) {
- auto& key_event = static_cast<const KeyEvent&>(event);
- m_keyboard_modifiers = key_event.modifiers();
-
- // Escape key cancels an ongoing drag.
- if (key_event.type() == Event::KeyDown && key_event.key() == Key_Escape && m_dnd_client) {
- // Notify the drag-n-drop client that the drag was cancelled.
- m_dnd_client->post_message(Messages::WindowClient::DragCancelled());
-
- // Also notify the currently hovered window (if any) that the ongoing drag was cancelled.
- if (m_hovered_window && m_hovered_window->client() && m_hovered_window->client() != m_dnd_client)
- m_hovered_window->client()->post_message(Messages::WindowClient::DragCancelled());
-
- end_dnd_drag();
- return;
- }
-
- if (MenuManager::the().current_menu()) {
- MenuManager::the().dispatch_event(event);
- return;
- }
-
- if (key_event.type() == Event::KeyDown && ((key_event.modifiers() == Mod_Logo && key_event.key() == Key_Tab) || (key_event.modifiers() == (Mod_Logo | Mod_Shift) && key_event.key() == Key_Tab)))
- m_switcher.show();
- if (m_switcher.is_visible()) {
- m_switcher.on_key_event(key_event);
- return;
- }
-
- if (m_active_input_window) {
- if (key_event.type() == Event::KeyDown && key_event.modifiers() == Mod_Logo) {
- if (key_event.key() == Key_Down) {
- if (m_active_input_window->is_resizable() && m_active_input_window->is_maximized()) {
- maximize_windows(*m_active_input_window, false);
- return;
- }
- if (m_active_input_window->is_minimizable())
- minimize_windows(*m_active_input_window, true);
- return;
- }
- if (m_active_input_window->is_resizable()) {
- if (key_event.key() == Key_Up) {
- maximize_windows(*m_active_input_window, !m_active_input_window->is_maximized());
- return;
- }
- if (key_event.key() == Key_Left) {
- if (m_active_input_window->tiled() != WindowTileType::None) {
- m_active_input_window->set_tiled(WindowTileType::None);
- return;
- }
- if (m_active_input_window->is_maximized())
- maximize_windows(*m_active_input_window, false);
- m_active_input_window->set_tiled(WindowTileType::Left);
- return;
- }
- if (key_event.key() == Key_Right) {
- if (m_active_input_window->tiled() != WindowTileType::None) {
- m_active_input_window->set_tiled(WindowTileType::None);
- return;
- }
- if (m_active_input_window->is_maximized())
- maximize_windows(*m_active_input_window, false);
- m_active_input_window->set_tiled(WindowTileType::Right);
- return;
- }
- }
- }
- m_active_input_window->dispatch_event(event);
- return;
- }
- }
-
- Core::Object::event(event);
-}
-
-void WindowManager::set_highlight_window(Window* window)
-{
- if (window == m_highlight_window)
- return;
- if (auto* previous_highlight_window = m_highlight_window.ptr())
- previous_highlight_window->invalidate();
- m_highlight_window = window;
- if (m_highlight_window)
- m_highlight_window->invalidate();
-}
-
-bool WindowManager::is_active_window_or_accessory(Window& window) const
-{
- if (m_active_window == &window)
- return true;
-
- if (!window.is_accessory())
- return false;
-
- return m_active_window == window.parent_window();
-}
-
-static bool window_type_can_become_active(WindowType type)
-{
- return type == WindowType::Normal || type == WindowType::Desktop;
-}
-
-void WindowManager::restore_active_input_window(Window* window)
-{
- // If the previous active input window is gone, fall back to the
- // current active window
- if (!window)
- window = active_window();
- // If the current active window is also gone, pick some other window
- if (!window && pick_new_active_window(nullptr))
- return;
-
- set_active_input_window(window);
-}
-
-Window* WindowManager::set_active_input_window(Window* window)
-{
- if (window == m_active_input_window)
- return window;
-
- Window* previous_input_window = m_active_input_window;
- if (previous_input_window)
- Core::EventLoop::current().post_event(*previous_input_window, make<Event>(Event::WindowInputLeft));
-
- if (window) {
- m_active_input_window = *window;
- Core::EventLoop::current().post_event(*window, make<Event>(Event::WindowInputEntered));
- } else {
- m_active_input_window = nullptr;
- }
-
- return previous_input_window;
-}
-
-void WindowManager::set_active_window(Window* window, bool make_input)
-{
- if (window) {
- if (auto* modal_window = window->blocking_modal_window()) {
- ASSERT(modal_window->is_modal());
- ASSERT(modal_window != window);
- window = modal_window;
- make_input = true;
- }
-
- if (!window_type_can_become_active(window->type()))
- return;
- }
-
- auto* new_active_input_window = window;
- if (window && window->is_accessory()) {
- // The parent of an accessory window is always the active
- // window, but input is routed to the accessory window
- window = window->parent_window();
- }
-
- if (make_input)
- set_active_input_window(new_active_input_window);
-
- if (window == m_active_window)
- return;
-
- auto* previously_active_window = m_active_window.ptr();
-
- ClientConnection* previously_active_client = nullptr;
- ClientConnection* active_client = nullptr;
-
- if (previously_active_window) {
- previously_active_client = previously_active_window->client();
- Core::EventLoop::current().post_event(*previously_active_window, make<Event>(Event::WindowDeactivated));
- previously_active_window->invalidate();
- m_active_window = nullptr;
- m_active_input_tracking_window = nullptr;
- tell_wm_listeners_window_state_changed(*previously_active_window);
- }
-
- if (window) {
- m_active_window = *window;
- active_client = m_active_window->client();
- Core::EventLoop::current().post_event(*m_active_window, make<Event>(Event::WindowActivated));
- m_active_window->invalidate();
- if (auto* client = window->client()) {
- MenuManager::the().set_current_menubar(client->app_menubar());
- } else {
- MenuManager::the().set_current_menubar(nullptr);
- }
- tell_wm_listeners_window_state_changed(*m_active_window);
- } else {
- MenuManager::the().set_current_menubar(nullptr);
- }
-
- if (active_client != previously_active_client) {
- if (previously_active_client)
- previously_active_client->deboost();
- if (active_client)
- active_client->boost();
- }
-}
-
-void WindowManager::set_hovered_window(Window* window)
-{
- if (m_hovered_window == window)
- return;
-
- if (m_hovered_window)
- Core::EventLoop::current().post_event(*m_hovered_window, make<Event>(Event::WindowLeft));
-
- m_hovered_window = window;
-
- if (m_hovered_window)
- Core::EventLoop::current().post_event(*m_hovered_window, make<Event>(Event::WindowEntered));
-}
-
-const ClientConnection* WindowManager::active_client() const
-{
- if (m_active_window)
- return m_active_window->client();
- return nullptr;
-}
-
-void WindowManager::notify_client_changed_app_menubar(ClientConnection& client)
-{
- if (active_client() == &client)
- MenuManager::the().set_current_menubar(client.app_menubar());
-}
-
-const Cursor& WindowManager::active_cursor() const
-{
- if (m_dnd_client)
- return *m_drag_cursor;
-
- if (m_move_window)
- return *m_move_cursor;
-
- if (m_resize_window || m_resize_candidate) {
- switch (m_resize_direction) {
- case ResizeDirection::Up:
- case ResizeDirection::Down:
- return *m_resize_vertically_cursor;
- case ResizeDirection::Left:
- case ResizeDirection::Right:
- return *m_resize_horizontally_cursor;
- case ResizeDirection::UpLeft:
- case ResizeDirection::DownRight:
- return *m_resize_diagonally_tlbr_cursor;
- case ResizeDirection::UpRight:
- case ResizeDirection::DownLeft:
- return *m_resize_diagonally_bltr_cursor;
- case ResizeDirection::None:
- break;
- }
- }
-
- if (m_hovered_window) {
- if (auto* modal_window = const_cast<Window&>(*m_hovered_window).blocking_modal_window()) {
- if (modal_window->cursor())
- return *modal_window->cursor();
- } else if (m_hovered_window->cursor()) {
- return *m_hovered_window->cursor();
- }
- }
-
- return *m_arrow_cursor;
-}
-
-void WindowManager::set_hovered_button(Button* button)
-{
- m_hovered_button = button;
-}
-
-void WindowManager::set_resize_candidate(Window& window, ResizeDirection direction)
-{
- m_resize_candidate = window;
- m_resize_direction = direction;
-}
-
-ResizeDirection WindowManager::resize_direction_of_window(const Window& window)
-{
- if (&window != m_resize_window)
- return ResizeDirection::None;
- return m_resize_direction;
-}
-
-Gfx::IntRect WindowManager::maximized_window_rect(const Window& window) const
-{
- Gfx::IntRect rect = Screen::the().rect();
-
- // Subtract window title bar (leaving the border)
- rect.set_y(rect.y() + window.frame().title_bar_rect().height());
- rect.set_height(rect.height() - window.frame().title_bar_rect().height());
-
- // Subtract menu bar
- rect.set_y(rect.y() + menubar_rect().height());
- rect.set_height(rect.height() - menubar_rect().height());
-
- // Subtract taskbar window height if present
- const_cast<WindowManager*>(this)->for_each_visible_window_of_type_from_back_to_front(WindowType::Taskbar, [&rect](Window& taskbar_window) {
- rect.set_height(rect.height() - taskbar_window.height());
- return IterationDecision::Break;
- });
-
- constexpr int tasteful_space_above_maximized_window = 2;
- rect.set_y(rect.y() + tasteful_space_above_maximized_window);
- rect.set_height(rect.height() - tasteful_space_above_maximized_window);
-
- return rect;
-}
-
-void WindowManager::start_dnd_drag(ClientConnection& client, const String& text, Gfx::Bitmap* bitmap, const Core::MimeData& mime_data)
-{
- ASSERT(!m_dnd_client);
- m_dnd_client = client;
- m_dnd_text = text;
- m_dnd_bitmap = bitmap;
- m_dnd_mime_data = mime_data;
- Compositor::the().invalidate_cursor();
- m_active_input_tracking_window = nullptr;
-}
-
-void WindowManager::end_dnd_drag()
-{
- ASSERT(m_dnd_client);
- Compositor::the().invalidate_cursor();
- m_dnd_client = nullptr;
- m_dnd_text = {};
- m_dnd_bitmap = nullptr;
-}
-
-Gfx::IntRect WindowManager::dnd_rect() const
-{
- int bitmap_width = m_dnd_bitmap ? m_dnd_bitmap->width() : 0;
- int bitmap_height = m_dnd_bitmap ? m_dnd_bitmap->height() : 0;
- int width = font().width(m_dnd_text) + bitmap_width;
- int height = max((int)font().glyph_height(), bitmap_height);
- auto location = Compositor::the().current_cursor_rect().center().translated(8, 8);
- return Gfx::IntRect(location, { width, height }).inflated(16, 8);
-}
-
-bool WindowManager::update_theme(String theme_path, String theme_name)
-{
- auto new_theme = Gfx::load_system_theme(theme_path);
- if (!new_theme)
- return false;
- ASSERT(new_theme);
- Gfx::set_system_theme(*new_theme);
- m_palette = Gfx::PaletteImpl::create_with_shared_buffer(*new_theme);
- Compositor::the().set_background_color(palette().desktop_background().to_string());
- HashTable<ClientConnection*> notified_clients;
- for_each_window([&](Window& window) {
- if (window.client()) {
- if (!notified_clients.contains(window.client())) {
- window.client()->post_message(Messages::WindowClient::UpdateSystemTheme(Gfx::current_system_theme_buffer_id()));
- notified_clients.set(window.client());
- }
- }
- window.frame().layout_buttons();
- window.frame().set_button_icons();
- return IterationDecision::Continue;
- });
- MenuManager::the().did_change_theme();
- auto wm_config = Core::ConfigFile::open("/etc/WindowServer/WindowServer.ini");
- wm_config->write_entry("Theme", "Name", theme_name);
- wm_config->sync();
- Compositor::the().invalidate_screen();
- return true;
-}
-
-void WindowManager::did_popup_a_menu(Badge<Menu>)
-{
- // Clear any ongoing input gesture
- if (!m_active_input_tracking_window)
- return;
- m_active_input_tracking_window->set_automatic_cursor_tracking_enabled(false);
- m_active_input_tracking_window = nullptr;
-}
-
-void WindowManager::minimize_windows(Window& window, bool minimized)
-{
- for_each_window_in_modal_stack(window, [&](auto& w, bool) {
- w.set_minimized(minimized);
- return IterationDecision::Continue;
- });
-}
-
-void WindowManager::maximize_windows(Window& window, bool maximized)
-{
- for_each_window_in_modal_stack(window, [&](auto& w, bool stack_top) {
- if (stack_top)
- w.set_maximized(maximized);
- if (w.is_minimized())
- w.set_minimized(false);
- return IterationDecision::Continue;
- });
-}
-
-Gfx::IntPoint WindowManager::get_recommended_window_position(const Gfx::IntPoint& desired)
-{
- // FIXME: Find a better source for the width and height to shift by.
- Gfx::IntPoint shift(8, Gfx::WindowTheme::current().title_bar_height(palette()) + 10);
-
- // FIXME: Find a better source for this.
- int taskbar_height = 28;
- int menubar_height = MenuManager::the().menubar_rect().height();
-
- const Window* overlap_window = nullptr;
- for_each_visible_window_of_type_from_front_to_back(WindowType::Normal, [&](Window& window) {
- if (window.default_positioned() && (!overlap_window || overlap_window->window_id() < window.window_id())) {
- overlap_window = &window;
- }
- return IterationDecision::Continue;
- });
-
- Gfx::IntPoint point;
- if (overlap_window) {
- point = overlap_window->position() + shift;
- point = { point.x() % Screen::the().width(),
- (point.y() >= (Screen::the().height() - taskbar_height))
- ? menubar_height + Gfx::WindowTheme::current().title_bar_height(palette())
- : point.y() };
- } else {
- point = desired;
- }
-
- return point;
-}
-}
diff --git a/Services/WindowServer/WindowManager.h b/Services/WindowServer/WindowManager.h
deleted file mode 100644
index 94e1f212d7..0000000000
--- a/Services/WindowServer/WindowManager.h
+++ /dev/null
@@ -1,479 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <AK/HashMap.h>
-#include <AK/HashTable.h>
-#include <AK/InlineLinkedList.h>
-#include <AK/WeakPtr.h>
-#include <LibCore/ConfigFile.h>
-#include <LibCore/ElapsedTimer.h>
-#include <LibGfx/Color.h>
-#include <LibGfx/DisjointRectSet.h>
-#include <LibGfx/Painter.h>
-#include <LibGfx/Palette.h>
-#include <LibGfx/Rect.h>
-#include <WindowServer/Cursor.h>
-#include <WindowServer/Event.h>
-#include <WindowServer/MenuBar.h>
-#include <WindowServer/MenuManager.h>
-#include <WindowServer/Window.h>
-#include <WindowServer/WindowSwitcher.h>
-#include <WindowServer/WindowType.h>
-
-namespace WindowServer {
-
-class Screen;
-class MouseEvent;
-class Window;
-class ClientConnection;
-class WindowSwitcher;
-class Button;
-
-enum class ResizeDirection {
- None,
- Left,
- UpLeft,
- Up,
- UpRight,
- Right,
- DownRight,
- Down,
- DownLeft
-};
-
-class WindowManager : public Core::Object {
- C_OBJECT(WindowManager)
-
- friend class Compositor;
- friend class WindowFrame;
- friend class WindowSwitcher;
-
-public:
- static WindowManager& the();
-
- explicit WindowManager(const Gfx::PaletteImpl&);
- virtual ~WindowManager() override;
-
- Palette palette() const { return Palette(*m_palette); }
-
- RefPtr<Core::ConfigFile> config() const { return m_config; }
- void reload_config(bool);
-
- void add_window(Window&);
- void remove_window(Window&);
-
- void notify_title_changed(Window&);
- void notify_modal_unparented(Window&);
- void notify_rect_changed(Window&, const Gfx::IntRect& oldRect, const Gfx::IntRect& newRect);
- void notify_minimization_state_changed(Window&);
- void notify_opacity_changed(Window&);
- void notify_occlusion_state_changed(Window&);
- void notify_progress_changed(Window&);
- void notify_client_changed_app_menubar(ClientConnection&);
-
- Gfx::IntRect maximized_window_rect(const Window&) const;
-
- const ClientConnection* dnd_client() const { return m_dnd_client.ptr(); }
- const String& dnd_text() const { return m_dnd_text; }
- const Core::MimeData& dnd_mime_data() const { return *m_dnd_mime_data; }
- const Gfx::Bitmap* dnd_bitmap() const { return m_dnd_bitmap; }
- Gfx::IntRect dnd_rect() const;
-
- void start_dnd_drag(ClientConnection&, const String& text, Gfx::Bitmap*, const Core::MimeData&);
- void end_dnd_drag();
-
- Window* active_window() { return m_active_window.ptr(); }
- const Window* active_window() const { return m_active_window.ptr(); }
- Window* active_input_window() { return m_active_input_window.ptr(); }
- const Window* active_input_window() const { return m_active_input_window.ptr(); }
- const ClientConnection* active_client() const;
-
- const Window* highlight_window() const { return m_highlight_window.ptr(); }
- void set_highlight_window(Window*);
-
- void move_to_front_and_make_active(Window&);
-
- Gfx::IntRect menubar_rect() const;
- Gfx::IntRect desktop_rect() const;
-
- const Cursor& active_cursor() const;
- const Cursor& hidden_cursor() const { return *m_hidden_cursor; }
- const Cursor& arrow_cursor() const { return *m_arrow_cursor; }
- const Cursor& crosshair_cursor() const { return *m_crosshair_cursor; }
- const Cursor& hand_cursor() const { return *m_hand_cursor; }
- const Cursor& help_cursor() const { return *m_help_cursor; }
- const Cursor& resize_horizontally_cursor() const { return *m_resize_horizontally_cursor; }
- const Cursor& resize_vertically_cursor() const { return *m_resize_vertically_cursor; }
- const Cursor& resize_diagonally_tlbr_cursor() const { return *m_resize_diagonally_tlbr_cursor; }
- const Cursor& resize_diagonally_bltr_cursor() const { return *m_resize_diagonally_bltr_cursor; }
- const Cursor& resize_column_cursor() const { return *m_resize_column_cursor; }
- const Cursor& resize_row_cursor() const { return *m_resize_row_cursor; }
- const Cursor& i_beam_cursor() const { return *m_i_beam_cursor; }
- const Cursor& disallowed_cursor() const { return *m_disallowed_cursor; }
- const Cursor& move_cursor() const { return *m_move_cursor; }
- const Cursor& drag_cursor() const { return *m_drag_cursor; }
- const Cursor& wait_cursor() const { return *m_wait_cursor; }
-
- const Gfx::Font& font() const;
- const Gfx::Font& window_title_font() const;
-
- bool set_resolution(int width, int height);
- Gfx::IntSize resolution() const;
-
- void set_acceleration_factor(double);
- void set_scroll_step_size(unsigned);
-
- Window* set_active_input_window(Window*);
- void restore_active_input_window(Window*);
- void set_active_window(Window*, bool make_input = true);
- void set_hovered_button(Button*);
-
- const Button* cursor_tracking_button() const { return m_cursor_tracking_button.ptr(); }
- void set_cursor_tracking_button(Button*);
-
- void set_resize_candidate(Window&, ResizeDirection);
- void clear_resize_candidate();
- ResizeDirection resize_direction_of_window(const Window&);
-
- void tell_wm_listeners_window_state_changed(Window&);
- void tell_wm_listeners_window_icon_changed(Window&);
- void tell_wm_listeners_window_rect_changed(Window&);
-
- bool is_active_window_or_accessory(Window&) const;
-
- void start_window_resize(Window&, const Gfx::IntPoint&, MouseButton);
- void start_window_resize(Window&, const MouseEvent&);
-
- const Window* active_fullscreen_window() const
- {
- if (m_active_window && m_active_window->is_fullscreen()) {
- return m_active_window;
- }
- return nullptr;
- };
-
- Window* active_fullscreen_window()
- {
- if (m_active_window && m_active_window->is_fullscreen()) {
- return m_active_window;
- }
- return nullptr;
- }
-
- bool update_theme(String theme_path, String theme_name);
-
- void set_hovered_window(Window*);
- void deliver_mouse_event(Window& window, MouseEvent& event);
-
- void did_popup_a_menu(Badge<Menu>);
-
- void start_menu_doubleclick(Window& window, const MouseEvent& event);
- bool is_menu_doubleclick(Window& window, const MouseEvent& event) const;
-
- void minimize_windows(Window&, bool);
- void maximize_windows(Window&, bool);
-
- template<typename Function>
- IterationDecision for_each_window_in_modal_stack(Window& window, Function f)
- {
- auto* blocking_modal_window = window.blocking_modal_window();
- if (blocking_modal_window || window.is_modal()) {
- Vector<Window*> modal_stack;
- auto* modal_stack_top = blocking_modal_window ? blocking_modal_window : &window;
- for (auto* parent = modal_stack_top->parent_window(); parent; parent = parent->parent_window()) {
- auto* blocked_by = parent->blocking_modal_window();
- if (!blocked_by || (blocked_by != modal_stack_top && !modal_stack_top->is_descendant_of(*blocked_by)))
- break;
- modal_stack.append(parent);
- if (!parent->is_modal())
- break;
- }
- if (!modal_stack.is_empty()) {
- for (size_t i = modal_stack.size(); i > 0; i--) {
- IterationDecision decision = f(*modal_stack[i - 1], false);
- if (decision != IterationDecision::Continue)
- return decision;
- }
- }
- return f(*modal_stack_top, true);
- } else {
- // Not a modal window stack, just "iterate" over this window
- return f(window, true);
- }
- }
-
- Gfx::IntPoint get_recommended_window_position(const Gfx::IntPoint& desired);
-
-private:
- NonnullRefPtr<Cursor> get_cursor(const String& name);
-
- void process_mouse_event(MouseEvent&, Window*& hovered_window);
- void process_event_for_doubleclick(Window& window, MouseEvent& event);
- bool process_ongoing_window_resize(const MouseEvent&, Window*& hovered_window);
- bool process_ongoing_window_move(MouseEvent&, Window*& hovered_window);
- bool process_ongoing_drag(MouseEvent&, Window*& hovered_window);
- void start_window_move(Window&, const MouseEvent&);
- template<typename Callback>
- IterationDecision for_each_visible_window_of_type_from_back_to_front(WindowType, Callback, bool ignore_highlight = false);
- template<typename Callback>
- IterationDecision for_each_visible_window_of_type_from_front_to_back(WindowType, Callback, bool ignore_highlight = false);
- template<typename Callback>
- IterationDecision for_each_visible_window_from_front_to_back(Callback);
- template<typename Callback>
- IterationDecision for_each_visible_window_from_back_to_front(Callback);
- template<typename Callback>
- void for_each_window_listening_to_wm_events(Callback);
- template<typename Callback>
- void for_each_window(Callback);
- template<typename Callback>
- IterationDecision for_each_window_of_type_from_front_to_back(WindowType, Callback, bool ignore_highlight = false);
-
- virtual void event(Core::Event&) override;
- void paint_window_frame(const Window&);
- void tell_wm_listener_about_window(Window& listener, Window&);
- void tell_wm_listener_about_window_icon(Window& listener, Window&);
- void tell_wm_listener_about_window_rect(Window& listener, Window&);
- bool pick_new_active_window(Window*);
-
- void do_move_to_front(Window&, bool, bool);
-
- RefPtr<Cursor> m_hidden_cursor;
- RefPtr<Cursor> m_arrow_cursor;
- RefPtr<Cursor> m_hand_cursor;
- RefPtr<Cursor> m_help_cursor;
- RefPtr<Cursor> m_resize_horizontally_cursor;
- RefPtr<Cursor> m_resize_vertically_cursor;
- RefPtr<Cursor> m_resize_diagonally_tlbr_cursor;
- RefPtr<Cursor> m_resize_diagonally_bltr_cursor;
- RefPtr<Cursor> m_resize_column_cursor;
- RefPtr<Cursor> m_resize_row_cursor;
- RefPtr<Cursor> m_i_beam_cursor;
- RefPtr<Cursor> m_disallowed_cursor;
- RefPtr<Cursor> m_move_cursor;
- RefPtr<Cursor> m_drag_cursor;
- RefPtr<Cursor> m_wait_cursor;
- RefPtr<Cursor> m_crosshair_cursor;
-
- InlineLinkedList<Window> m_windows_in_order;
-
- struct DoubleClickInfo {
- struct ClickMetadata {
- Core::ElapsedTimer clock;
- Gfx::IntPoint last_position;
- };
-
- const ClickMetadata& metadata_for_button(MouseButton) const;
- ClickMetadata& metadata_for_button(MouseButton);
-
- void reset()
- {
- m_left = {};
- m_right = {};
- m_middle = {};
- m_back = {};
- m_forward = {};
- }
-
- WeakPtr<Window> m_clicked_window;
-
- private:
- ClickMetadata m_left;
- ClickMetadata m_right;
- ClickMetadata m_middle;
- ClickMetadata m_back;
- ClickMetadata m_forward;
- };
-
- bool is_considered_doubleclick(const MouseEvent& event, const DoubleClickInfo::ClickMetadata& metadata) const;
-
- DoubleClickInfo m_double_click_info;
- int m_double_click_speed { 0 };
- int m_max_distance_for_double_click { 4 };
-
- WeakPtr<Window> m_active_window;
- WeakPtr<Window> m_hovered_window;
- WeakPtr<Window> m_highlight_window;
- WeakPtr<Window> m_active_input_window;
- WeakPtr<Window> m_active_input_tracking_window;
-
- WeakPtr<Window> m_move_window;
- Gfx::IntPoint m_move_origin;
- Gfx::IntPoint m_move_window_origin;
-
- WeakPtr<Window> m_resize_window;
- WeakPtr<Window> m_resize_candidate;
- MouseButton m_resizing_mouse_button { MouseButton::None };
- Gfx::IntRect m_resize_window_original_rect;
- Gfx::IntPoint m_resize_origin;
- ResizeDirection m_resize_direction { ResizeDirection::None };
-
- u8 m_keyboard_modifiers { 0 };
-
- WindowSwitcher m_switcher;
-
- WeakPtr<Button> m_cursor_tracking_button;
- WeakPtr<Button> m_hovered_button;
-
- NonnullRefPtr<Gfx::PaletteImpl> m_palette;
-
- RefPtr<Core::ConfigFile> m_config;
-
- WeakPtr<ClientConnection> m_dnd_client;
- String m_dnd_text;
- RefPtr<Core::MimeData> m_dnd_mime_data;
- RefPtr<Gfx::Bitmap> m_dnd_bitmap;
-};
-
-template<typename Callback>
-IterationDecision WindowManager::for_each_visible_window_of_type_from_back_to_front(WindowType type, Callback callback, bool ignore_highlight)
-{
- bool do_highlight_window_at_end = false;
- for (auto& window : m_windows_in_order) {
- if (!window.is_visible())
- continue;
- if (window.is_minimized())
- continue;
- if (window.type() != type)
- continue;
- if (!ignore_highlight && m_highlight_window == &window) {
- do_highlight_window_at_end = true;
- continue;
- }
- if (callback(window) == IterationDecision::Break)
- return IterationDecision::Break;
- }
- if (do_highlight_window_at_end) {
- if (callback(*m_highlight_window) == IterationDecision::Break)
- return IterationDecision::Break;
- }
- return IterationDecision::Continue;
-}
-
-template<typename Callback>
-IterationDecision WindowManager::for_each_visible_window_from_back_to_front(Callback callback)
-{
- if (for_each_visible_window_of_type_from_back_to_front(WindowType::Desktop, callback) == IterationDecision::Break)
- return IterationDecision::Break;
- if (for_each_visible_window_of_type_from_back_to_front(WindowType::Normal, callback) == IterationDecision::Break)
- return IterationDecision::Break;
- if (for_each_visible_window_of_type_from_back_to_front(WindowType::Taskbar, callback) == IterationDecision::Break)
- return IterationDecision::Break;
- if (for_each_visible_window_of_type_from_back_to_front(WindowType::Notification, callback) == IterationDecision::Break)
- return IterationDecision::Break;
- if (for_each_visible_window_of_type_from_back_to_front(WindowType::Tooltip, callback) == IterationDecision::Break)
- return IterationDecision::Break;
- if (for_each_visible_window_of_type_from_back_to_front(WindowType::Menubar, callback) == IterationDecision::Break)
- return IterationDecision::Break;
- if (for_each_visible_window_of_type_from_back_to_front(WindowType::Menu, callback) == IterationDecision::Break)
- return IterationDecision::Break;
- return for_each_visible_window_of_type_from_back_to_front(WindowType::WindowSwitcher, callback);
-}
-
-template<typename Callback>
-IterationDecision WindowManager::for_each_visible_window_of_type_from_front_to_back(WindowType type, Callback callback, bool ignore_highlight)
-{
- if (!ignore_highlight && m_highlight_window && m_highlight_window->type() == type && m_highlight_window->is_visible()) {
- if (callback(*m_highlight_window) == IterationDecision::Break)
- return IterationDecision::Break;
- }
-
- for (auto* window = m_windows_in_order.tail(); window; window = window->prev()) {
- if (!window->is_visible())
- continue;
- if (window->is_minimized())
- continue;
- if (window->type() != type)
- continue;
- if (!ignore_highlight && window == m_highlight_window)
- continue;
- if (callback(*window) == IterationDecision::Break)
- return IterationDecision::Break;
- }
- return IterationDecision::Continue;
-}
-
-template<typename Callback>
-IterationDecision WindowManager::for_each_visible_window_from_front_to_back(Callback callback)
-{
- if (for_each_visible_window_of_type_from_front_to_back(WindowType::WindowSwitcher, callback) == IterationDecision::Break)
- return IterationDecision::Break;
- if (for_each_visible_window_of_type_from_front_to_back(WindowType::Menu, callback) == IterationDecision::Break)
- return IterationDecision::Break;
- if (for_each_visible_window_of_type_from_front_to_back(WindowType::Menubar, callback) == IterationDecision::Break)
- return IterationDecision::Break;
- if (for_each_visible_window_of_type_from_front_to_back(WindowType::Tooltip, callback) == IterationDecision::Break)
- return IterationDecision::Break;
- if (for_each_visible_window_of_type_from_front_to_back(WindowType::Notification, callback) == IterationDecision::Break)
- return IterationDecision::Break;
- if (for_each_visible_window_of_type_from_front_to_back(WindowType::Taskbar, callback) == IterationDecision::Break)
- return IterationDecision::Break;
- if (for_each_visible_window_of_type_from_front_to_back(WindowType::Normal, callback) == IterationDecision::Break)
- return IterationDecision::Break;
- return for_each_visible_window_of_type_from_front_to_back(WindowType::Desktop, callback);
-}
-
-template<typename Callback>
-void WindowManager::for_each_window_listening_to_wm_events(Callback callback)
-{
- for (auto* window = m_windows_in_order.tail(); window; window = window->prev()) {
- if (!window->listens_to_wm_events())
- continue;
- if (callback(*window) == IterationDecision::Break)
- return;
- }
-}
-
-template<typename Callback>
-void WindowManager::for_each_window(Callback callback)
-{
- for (auto* window = m_windows_in_order.tail(); window; window = window->prev()) {
- if (callback(*window) == IterationDecision::Break)
- return;
- }
-}
-
-template<typename Callback>
-IterationDecision WindowManager::for_each_window_of_type_from_front_to_back(WindowType type, Callback callback, bool ignore_highlight)
-{
- if (!ignore_highlight && m_highlight_window && m_highlight_window->type() == type && m_highlight_window->is_visible()) {
- if (callback(*m_highlight_window) == IterationDecision::Break)
- return IterationDecision::Break;
- }
-
- for (auto* window = m_windows_in_order.tail(); window; window = window->prev()) {
- if (window->type() != type)
- continue;
- if (!ignore_highlight && window == m_highlight_window)
- continue;
- if (callback(*window) == IterationDecision::Break)
- return IterationDecision::Break;
- }
- return IterationDecision::Continue;
-}
-
-}
diff --git a/Services/WindowServer/WindowServer.ipc b/Services/WindowServer/WindowServer.ipc
deleted file mode 100644
index 72399de1db..0000000000
--- a/Services/WindowServer/WindowServer.ipc
+++ /dev/null
@@ -1,117 +0,0 @@
-endpoint WindowServer = 2
-{
- Greet() => (i32 client_id, Gfx::IntRect screen_rect, i32 system_theme_buffer_id)
-
- CreateMenubar() => (i32 menubar_id)
- DestroyMenubar(i32 menubar_id) => ()
-
- CreateMenu([UTF8] String menu_title) => (i32 menu_id)
- DestroyMenu(i32 menu_id) => ()
-
- AddMenuToMenubar(i32 menubar_id, i32 menu_id) => ()
- SetApplicationMenubar(i32 menubar_id) => ()
-
- SetSystemMenu(i32 menu_id) => ()
-
- AddMenuItem(
- i32 menu_id,
- i32 identifier,
- i32 submenu_id,
- [UTF8] String text,
- bool enabled,
- bool checkable,
- bool checked,
- bool is_default,
- [UTF8] String shortcut,
- i32 icon_buffer_id,
- bool exclusive) => ()
-
- AddMenuSeparator(i32 menu_id) => ()
-
- UpdateMenuItem(i32 menu_id, i32 identifier, i32 submenu_id, [UTF8] String text, bool enabled, bool checkable, bool checked, bool is_default, [UTF8] String shortcut) => ()
-
- CreateWindow(
- Gfx::IntRect rect,
- bool auto_position,
- bool has_alpha_channel,
- bool modal,
- bool minimizable,
- bool resizable,
- bool fullscreen,
- bool frameless,
- bool accessory,
- float opacity,
- Gfx::IntSize base_size,
- Gfx::IntSize size_increment,
- Optional<Gfx::IntSize> resize_aspect_ratio,
- i32 type,
- [UTF8] String title,
- i32 parent_window_id) => (i32 window_id)
-
- DestroyWindow(i32 window_id) => (Vector<i32> destroyed_window_ids)
-
- SetWindowTitle(i32 window_id, [UTF8] String title) => ()
- GetWindowTitle(i32 window_id) => ([UTF8] String title)
-
- SetWindowProgress(i32 window_id, i32 progress) =|
-
- SetWindowRect(i32 window_id, Gfx::IntRect rect) => (Gfx::IntRect rect)
- GetWindowRect(i32 window_id) => (Gfx::IntRect rect)
-
- GetWindowRectInMenubar(i32 window_id) => (Gfx::IntRect rect)
-
- IsMaximized(i32 window_id) => (bool maximized)
-
- InvalidateRect(i32 window_id, Vector<Gfx::IntRect> rects, bool ignore_occlusion) =|
- DidFinishPainting(i32 window_id, Vector<Gfx::IntRect> rects) =|
-
- SetGlobalCursorTracking(i32 window_id, bool enabled) => ()
- SetWindowOpacity(i32 window_id, float opacity) => ()
-
- SetWindowBackingStore(i32 window_id, i32 bpp, i32 pitch, i32 shbuf_id, bool has_alpha_channel, Gfx::IntSize size, bool flush_immediately) => ()
-
- WM_SetActiveWindow(i32 client_id, i32 window_id) =|
- WM_SetWindowMinimized(i32 client_id, i32 window_id, bool minimized) =|
- WM_StartWindowResize(i32 client_id, i32 window_id) =|
- WM_PopupWindowMenu(i32 client_id, i32 window_id, Gfx::IntPoint screen_position) =|
- WM_SetWindowTaskbarRect(i32 client_id, i32 window_id, Gfx::IntRect rect) =|
-
- SetWindowHasAlphaChannel(i32 window_id, bool has_alpha_channel) => ()
- MoveWindowToFront(i32 window_id) => ()
- SetFullscreen(i32 window_id, bool fullscreen) => ()
- PopupMenu(i32 menu_id, Gfx::IntPoint screen_position) => ()
- DismissMenu(i32 menu_id) => ()
-
- AsyncSetWallpaper(String path) =|
-
- SetBackgroundColor(String background_color) => ()
- SetWallpaperMode(String mode) => ()
-
- SetResolution(Gfx::IntSize resolution) => (bool success, Gfx::IntSize resolution)
- SetWindowIconBitmap(i32 window_id, Gfx::ShareableBitmap icon) => ()
-
- GetWallpaper() => (String path)
- SetWindowCursor(i32 window_id, i32 cursor_type) => ()
- SetWindowCustomCursor(i32 window_id, Gfx::ShareableBitmap cursor) => ()
-
- StartDrag([UTF8] String text, HashMap<String,ByteBuffer> mime_data, i32 bitmap_id, Gfx::IntSize bitmap_size) => (bool started)
-
- SetSystemTheme(String theme_path, [UTF8] String theme_name) => (bool success)
- GetSystemTheme() => ([UTF8] String theme_name)
-
- SetWindowBaseSizeAndSizeIncrement(i32 window_id, Gfx::IntSize base_size, Gfx::IntSize size_increment) => ()
- SetWindowResizeAspectRatio(i32 window_id, Optional<Gfx::IntSize> resize_aspect_ratio) => ()
-
- EnableDisplayLink() =|
- DisableDisplayLink() =|
-
- GetGlobalCursorPosition() => (Gfx::IntPoint position)
-
- SetMouseAcceleration(float factor) => ()
- GetMouseAcceleration() => (float factor)
-
- SetScrollStepSize(u32 step_size) => ()
- GetScrollStepSize() => (u32 step_size)
-
- Pong() =|
-}
diff --git a/Services/WindowServer/WindowSwitcher.cpp b/Services/WindowServer/WindowSwitcher.cpp
deleted file mode 100644
index 803887c657..0000000000
--- a/Services/WindowServer/WindowSwitcher.cpp
+++ /dev/null
@@ -1,257 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <LibGfx/Bitmap.h>
-#include <LibGfx/Font.h>
-#include <LibGfx/StylePainter.h>
-#include <WindowServer/Compositor.h>
-#include <WindowServer/Event.h>
-#include <WindowServer/Screen.h>
-#include <WindowServer/WindowManager.h>
-#include <WindowServer/WindowSwitcher.h>
-
-namespace WindowServer {
-
-static WindowSwitcher* s_the;
-
-WindowSwitcher& WindowSwitcher::the()
-{
- ASSERT(s_the);
- return *s_the;
-}
-
-WindowSwitcher::WindowSwitcher()
-{
- s_the = this;
-}
-
-WindowSwitcher::~WindowSwitcher()
-{
-}
-
-void WindowSwitcher::set_visible(bool visible)
-{
- if (m_visible == visible)
- return;
- m_visible = visible;
- Compositor::the().invalidate_occlusions();
- if (m_switcher_window)
- m_switcher_window->set_visible(visible);
- if (!m_visible)
- return;
- refresh();
-}
-
-Window* WindowSwitcher::selected_window()
-{
- if (m_selected_index < 0 || m_selected_index >= static_cast<int>(m_windows.size()))
- return nullptr;
- return m_windows[m_selected_index].ptr();
-}
-
-void WindowSwitcher::event(Core::Event& event)
-{
- if (!static_cast<Event&>(event).is_mouse_event())
- return;
-
- auto& mouse_event = static_cast<MouseEvent&>(event);
- int new_hovered_index = -1;
- for (size_t i = 0; i < m_windows.size(); ++i) {
- auto item_rect = this->item_rect(i);
- if (item_rect.contains(mouse_event.position())) {
- new_hovered_index = i;
- break;
- }
- }
-
- if (mouse_event.type() == Event::MouseMove) {
- if (m_hovered_index != new_hovered_index) {
- m_hovered_index = new_hovered_index;
- redraw();
- }
- }
-
- if (new_hovered_index == -1)
- return;
-
- if (mouse_event.type() == Event::MouseDown)
- select_window_at_index(new_hovered_index);
-
- event.accept();
-}
-
-void WindowSwitcher::on_key_event(const KeyEvent& event)
-{
- if (event.type() == Event::KeyUp) {
- if (event.key() == Key_Logo) {
- if (auto* window = selected_window()) {
- window->set_minimized(false);
- WindowManager::the().move_to_front_and_make_active(*window);
- }
- WindowManager::the().set_highlight_window(nullptr);
- hide();
- }
- return;
- }
-
- if (event.key() == Key_LeftShift || event.key() == Key_RightShift)
- return;
- if (event.key() != Key_Tab) {
- WindowManager::the().set_highlight_window(nullptr);
- hide();
- return;
- }
- ASSERT(!m_windows.is_empty());
-
- int new_selected_index;
-
- if (!event.shift()) {
- new_selected_index = (m_selected_index + 1) % static_cast<int>(m_windows.size());
- } else {
- new_selected_index = (m_selected_index - 1) % static_cast<int>(m_windows.size());
- if (new_selected_index < 0)
- new_selected_index = static_cast<int>(m_windows.size()) - 1;
- }
- ASSERT(new_selected_index < static_cast<int>(m_windows.size()));
-
- select_window_at_index(new_selected_index);
-}
-
-void WindowSwitcher::select_window(Window& window)
-{
- for (size_t i = 0; i < m_windows.size(); ++i) {
- if (m_windows.at(i) == &window) {
- select_window_at_index(i);
- return;
- }
- }
-}
-
-void WindowSwitcher::select_window_at_index(int index)
-{
- m_selected_index = index;
- auto* highlight_window = m_windows.at(index).ptr();
- ASSERT(highlight_window);
- WindowManager::the().set_highlight_window(highlight_window);
- redraw();
-}
-
-void WindowSwitcher::redraw()
-{
- draw();
- Compositor::the().invalidate_screen(m_rect);
-}
-
-Gfx::IntRect WindowSwitcher::item_rect(int index) const
-{
- return {
- padding(),
- padding() + index * item_height(),
- m_rect.width() - padding() * 2,
- item_height()
- };
-}
-
-void WindowSwitcher::draw()
-{
- auto palette = WindowManager::the().palette();
- Gfx::Painter painter(*m_switcher_window->backing_store());
- painter.fill_rect({ {}, m_rect.size() }, palette.window());
- painter.draw_rect({ {}, m_rect.size() }, palette.threed_shadow2());
- for (size_t index = 0; index < m_windows.size(); ++index) {
- auto& window = *m_windows.at(index);
- auto item_rect = this->item_rect(index);
- Color text_color;
- Color rect_text_color;
- if (static_cast<int>(index) == m_selected_index) {
- painter.fill_rect(item_rect, palette.selection());
- text_color = palette.selection_text();
- rect_text_color = palette.threed_shadow1();
- } else {
- if (static_cast<int>(index) == m_hovered_index)
- Gfx::StylePainter::paint_button(painter, item_rect, palette, Gfx::ButtonStyle::CoolBar, false, true);
- text_color = palette.window_text();
- rect_text_color = palette.threed_shadow2();
- }
- item_rect.shrink(item_padding(), 0);
- Gfx::IntRect thumbnail_rect = { item_rect.location().translated(0, 5), { thumbnail_width(), thumbnail_height() } };
- if (window.backing_store()) {
- painter.draw_scaled_bitmap(thumbnail_rect, *window.backing_store(), window.backing_store()->rect());
- Gfx::StylePainter::paint_frame(painter, thumbnail_rect.inflated(4, 4), palette, Gfx::FrameShape::Container, Gfx::FrameShadow::Sunken, 2);
- }
- Gfx::IntRect icon_rect = { thumbnail_rect.bottom_right().translated(-window.icon().width(), -window.icon().height()), { window.icon().width(), window.icon().height() } };
- painter.fill_rect(icon_rect, palette.window());
- painter.blit(icon_rect.location(), window.icon(), window.icon().rect());
- painter.draw_text(item_rect.translated(thumbnail_width() + 12, 0), window.title(), WindowManager::the().window_title_font(), Gfx::TextAlignment::CenterLeft, text_color);
- painter.draw_text(item_rect, window.rect().to_string(), Gfx::TextAlignment::CenterRight, rect_text_color);
- }
-}
-
-void WindowSwitcher::refresh()
-{
- auto& wm = WindowManager::the();
- const Window* selected_window = nullptr;
- if (m_selected_index > 0 && m_windows[m_selected_index])
- selected_window = m_windows[m_selected_index].ptr();
- if (!selected_window)
- selected_window = wm.highlight_window() ? wm.highlight_window() : wm.active_window();
- m_windows.clear();
- m_selected_index = 0;
- int window_count = 0;
- int longest_title_width = 0;
- wm.for_each_window_of_type_from_front_to_back(
- WindowType::Normal, [&](Window& window) {
- if (window.is_frameless())
- return IterationDecision::Continue;
- ++window_count;
- longest_title_width = max(longest_title_width, wm.font().width(window.title()));
- if (selected_window == &window)
- m_selected_index = m_windows.size();
- m_windows.append(window);
- return IterationDecision::Continue;
- },
- true);
- if (m_windows.is_empty()) {
- hide();
- return;
- }
- int space_for_window_rect = 180;
- m_rect.set_width(thumbnail_width() + longest_title_width + space_for_window_rect + padding() * 2 + item_padding() * 2);
- m_rect.set_height(window_count * item_height() + padding() * 2);
- m_rect.center_within(Screen::the().rect());
- if (!m_switcher_window)
- m_switcher_window = Window::construct(*this, WindowType::WindowSwitcher);
- m_switcher_window->set_rect(m_rect);
- redraw();
-}
-
-void WindowSwitcher::refresh_if_needed()
-{
- if (m_visible)
- refresh();
-}
-
-}
diff --git a/Services/WindowServer/WindowSwitcher.h b/Services/WindowServer/WindowSwitcher.h
deleted file mode 100644
index 8b52eea372..0000000000
--- a/Services/WindowServer/WindowSwitcher.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <AK/Vector.h>
-#include <AK/WeakPtr.h>
-#include <LibCore/Object.h>
-#include <LibGfx/Forward.h>
-#include <LibGfx/Rect.h>
-
-namespace WindowServer {
-
-class KeyEvent;
-class Window;
-
-class WindowSwitcher final : public Core::Object {
- C_OBJECT(WindowSwitcher)
-public:
- static WindowSwitcher& the();
-
- WindowSwitcher();
- virtual ~WindowSwitcher() override;
-
- bool is_visible() const { return m_visible; }
- void set_visible(bool);
-
- void show() { set_visible(true); }
- void hide() { set_visible(false); }
-
- void on_key_event(const KeyEvent&);
-
- void refresh();
- void refresh_if_needed();
-
- void select_window(Window&);
-
-private:
- int thumbnail_width() const { return 40; }
- int thumbnail_height() const { return 40; }
- int item_height() const { return 10 + thumbnail_height(); }
- int padding() const { return 8; }
- int item_padding() const { return 8; }
-
- void draw();
- void redraw();
- void select_window_at_index(int index);
- Gfx::IntRect item_rect(int index) const;
- Window* selected_window();
-
- virtual void event(Core::Event&) override;
-
- RefPtr<Window> m_switcher_window;
- Gfx::IntRect m_rect;
- bool m_visible { false };
- Vector<WeakPtr<Window>> m_windows;
- int m_selected_index { 0 };
- int m_hovered_index { -1 };
-};
-
-}
diff --git a/Services/WindowServer/WindowType.h b/Services/WindowServer/WindowType.h
deleted file mode 100644
index a3c53007a1..0000000000
--- a/Services/WindowServer/WindowType.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-// Keep this in sync with GUI::WindowType.
-enum class WindowType {
- Invalid = 0,
- Normal,
- Menu,
- WindowSwitcher,
- Taskbar,
- Tooltip,
- Menubar,
- MenuApplet,
- Notification,
- Desktop,
-};
diff --git a/Services/WindowServer/main.cpp b/Services/WindowServer/main.cpp
deleted file mode 100644
index ca8d997f0d..0000000000
--- a/Services/WindowServer/main.cpp
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "AppletManager.h"
-#include "Compositor.h"
-#include "EventLoop.h"
-#include "Screen.h"
-#include "WindowManager.h"
-#include <AK/SharedBuffer.h>
-#include <LibCore/ConfigFile.h>
-#include <LibGfx/Palette.h>
-#include <LibGfx/SystemTheme.h>
-#include <signal.h>
-#include <stdio.h>
-#include <string.h>
-
-int main(int, char**)
-{
- if (pledge("stdio video thread shared_buffer accept rpath wpath cpath unix proc fattr sigaction", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- if (unveil("/res", "r") < 0) {
- perror("unveil /res");
- return 1;
- }
-
- if (unveil("/tmp", "cw") < 0) {
- perror("unveil /tmp cw");
- return 1;
- }
-
- if (unveil("/etc/WindowServer/WindowServer.ini", "rwc") < 0) {
- perror("unveil /etc/WindowServer/WindowServer.ini");
- return 1;
- }
-
- if (unveil("/dev", "rw") < 0) {
- perror("unveil /dev rw");
- return 1;
- }
-
- struct sigaction act;
- memset(&act, 0, sizeof(act));
- act.sa_flags = SA_NOCLDWAIT;
- act.sa_handler = SIG_IGN;
- int rc = sigaction(SIGCHLD, &act, nullptr);
- if (rc < 0) {
- perror("sigaction");
- return 1;
- }
-
- auto wm_config = Core::ConfigFile::open("/etc/WindowServer/WindowServer.ini");
- auto theme_name = wm_config->read_entry("Theme", "Name", "Default");
-
- auto theme = Gfx::load_system_theme(String::format("/res/themes/%s.ini", theme_name.characters()));
- ASSERT(theme);
- Gfx::set_system_theme(*theme);
- auto palette = Gfx::PaletteImpl::create_with_shared_buffer(*theme);
-
- WindowServer::EventLoop loop;
-
- if (pledge("stdio video thread shared_buffer accept rpath wpath cpath proc", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- WindowServer::Screen screen(wm_config->read_num_entry("Screen", "Width", 1024),
- wm_config->read_num_entry("Screen", "Height", 768));
- screen.set_acceleration_factor(atof(wm_config->read_entry("Mouse", "AccelerationFactor", "1.0").characters()));
- screen.set_scroll_step_size(wm_config->read_num_entry("Mouse", "ScrollStepSize", 4));
- WindowServer::Compositor::the();
- auto wm = WindowServer::WindowManager::construct(*palette);
- auto am = WindowServer::AppletManager::construct();
- auto mm = WindowServer::MenuManager::construct();
-
- if (unveil("/tmp", "") < 0) {
- perror("unveil /tmp");
- return 1;
- }
-
- if (unveil("/dev", "") < 0) {
- perror("unveil /dev");
- return 1;
- }
-
- if (unveil(nullptr, nullptr) < 0) {
- perror("unveil");
- return 1;
- }
-
- dbgln("Entering WindowServer main loop");
- loop.exec();
- ASSERT_NOT_REACHED();
-}