summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Base/res/apps/Browser.af4
-rw-r--r--Base/res/apps/TextEditor.af3
-rw-r--r--Libraries/LibDesktop/Launcher.cpp6
-rw-r--r--Libraries/LibDesktop/Launcher.h2
-rw-r--r--Services/LaunchServer/ClientConnection.cpp2
-rw-r--r--Services/LaunchServer/LaunchServer.ipc2
-rw-r--r--Services/LaunchServer/Launcher.cpp92
-rw-r--r--Services/LaunchServer/Launcher.h16
-rw-r--r--Services/LaunchServer/main.cpp1
9 files changed, 111 insertions, 17 deletions
diff --git a/Base/res/apps/Browser.af b/Base/res/apps/Browser.af
index acd6b59817..895d570f00 100644
--- a/Base/res/apps/Browser.af
+++ b/Base/res/apps/Browser.af
@@ -6,3 +6,7 @@ Category=Internet
[Icons]
16x16=/res/icons/16x16/app-browser.png
32x32=/res/icons/32x32/app-browser.png
+
+[Launcher]
+FileTypes=html,md
+Protocols=http,https
diff --git a/Base/res/apps/TextEditor.af b/Base/res/apps/TextEditor.af
index e66c69cc5c..4916d03e26 100644
--- a/Base/res/apps/TextEditor.af
+++ b/Base/res/apps/TextEditor.af
@@ -6,3 +6,6 @@ Category=Utilities
[Icons]
16x16=/res/icons/TextEditor16.png
32x32=/res/icons/32x32/app-texteditor.png
+
+[Launcher]
+FileTypes=txt,md,html
diff --git a/Libraries/LibDesktop/Launcher.cpp b/Libraries/LibDesktop/Launcher.cpp
index 43fd5a7c3b..0d35c0c618 100644
--- a/Libraries/LibDesktop/Launcher.cpp
+++ b/Libraries/LibDesktop/Launcher.cpp
@@ -48,13 +48,13 @@ private:
: IPC::ServerConnection<LaunchClientEndpoint, LaunchServerEndpoint>(*this, "/tmp/portal/launch")
{
}
- virtual void handle(const Messages::LaunchClient::Dummy&) override { }
+ virtual void handle(const Messages::LaunchClient::Dummy&) override {}
};
-bool Launcher::open(const URL& url)
+bool Launcher::open(const URL& url, const String& handler_name)
{
auto connection = LaunchServerConnection::construct();
- return connection->send_sync<Messages::LaunchServer::OpenUrl>(url.to_string())->response();
+ return connection->send_sync<Messages::LaunchServer::OpenUrl>(url.to_string(), handler_name)->response();
}
Vector<String> Launcher::get_handlers_for_url(const URL& url)
diff --git a/Libraries/LibDesktop/Launcher.h b/Libraries/LibDesktop/Launcher.h
index 7acf2cc5b8..b8c792a01b 100644
--- a/Libraries/LibDesktop/Launcher.h
+++ b/Libraries/LibDesktop/Launcher.h
@@ -32,7 +32,7 @@ namespace Desktop {
class Launcher {
public:
- static bool open(const URL&);
+ static bool open(const URL&, const String& handler_name = {});
static Vector<String> get_handlers_for_url(const URL&);
};
diff --git a/Services/LaunchServer/ClientConnection.cpp b/Services/LaunchServer/ClientConnection.cpp
index 35bc944b09..e69d6fce86 100644
--- a/Services/LaunchServer/ClientConnection.cpp
+++ b/Services/LaunchServer/ClientConnection.cpp
@@ -56,7 +56,7 @@ OwnPtr<Messages::LaunchServer::GreetResponse> ClientConnection::handle(const Mes
OwnPtr<Messages::LaunchServer::OpenUrlResponse> ClientConnection::handle(const Messages::LaunchServer::OpenUrl& request)
{
URL url(request.url());
- auto result = Launcher::the().open_url(url);
+ auto result = Launcher::the().open_url(url, request.handler_name());
return make<Messages::LaunchServer::OpenUrlResponse>(result);
}
diff --git a/Services/LaunchServer/LaunchServer.ipc b/Services/LaunchServer/LaunchServer.ipc
index f2bb3bbd1d..a4d31a00ed 100644
--- a/Services/LaunchServer/LaunchServer.ipc
+++ b/Services/LaunchServer/LaunchServer.ipc
@@ -1,6 +1,6 @@
endpoint LaunchServer = 101
{
Greet() => (i32 client_id)
- OpenUrl(String url) => (bool response)
+ OpenUrl(String url, String handler_name) => (bool response)
GetHandlersForURL(String url) => (Vector<String> handlers)
}
diff --git a/Services/LaunchServer/Launcher.cpp b/Services/LaunchServer/Launcher.cpp
index bda5ad70a0..62145eb17f 100644
--- a/Services/LaunchServer/Launcher.cpp
+++ b/Services/LaunchServer/Launcher.cpp
@@ -26,7 +26,9 @@
#include "Launcher.h"
#include <AK/FileSystemPath.h>
+#include <AK/Function.h>
#include <LibCore/ConfigFile.h>
+#include <LibCore/DirIterator.h>
#include <stdio.h>
#include <sys/stat.h>
@@ -47,6 +49,33 @@ Launcher& Launcher::the()
return *s_the;
}
+void Launcher::load_handlers(const String& af_dir)
+{
+ auto load_hashtable = [](auto& af, auto& key) {
+ HashTable<String> table;
+
+ auto config_value = af->read_entry("Launcher", key, {});
+ for (auto& key : config_value.split(','))
+ table.set(key.to_lowercase());
+
+ return table;
+ };
+
+ Core::DirIterator dt(af_dir, Core::DirIterator::SkipDots);
+ while (dt.has_next()) {
+ auto af_name = dt.next_path();
+ auto af_path = String::format("%s/%s", af_dir.characters(), af_name.characters());
+ auto af = Core::ConfigFile::open(af_path);
+ if (!af->has_key("App", "Name") || !af->has_key("App", "Executable"))
+ continue;
+ auto app_name = af->read_entry("App", "Name");
+ auto app_executable = af->read_entry("App", "Executable");
+ auto file_types = load_hashtable(af, "FileTypes");
+ auto protocols = load_hashtable(af, "Protocols");
+ m_handlers.set(app_executable, { app_name, app_executable, file_types, protocols });
+ }
+}
+
void Launcher::load_config(const Core::ConfigFile& cfg)
{
for (auto key : cfg.keys("FileType")) {
@@ -63,15 +92,35 @@ Vector<String> Launcher::handlers_for_url(const URL& url)
if (url.protocol() == "file")
return handlers_for_path(url.path());
- return { m_protocol_handlers.get(url.protocol()).value_or(m_protocol_handlers.get("*").value_or({})) };
+ return handlers_for(url.protocol(), m_protocol_handlers, [](auto& handler, auto& key) {
+ return handler.protocols.contains(key);
+ });
}
-bool Launcher::open_url(const URL& url)
+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_handlers(m_protocol_handlers, url.protocol(), url.to_string(), "/bin/Browser");
+ return open_with_user_preferences(m_protocol_handlers, url.protocol(), url.to_string(), "/bin/Browser");
+}
+
+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)
@@ -91,14 +140,14 @@ bool spawn(String executable, String argument)
return true;
}
-bool Launcher::open_with_handlers(const HashMap<String, String>& handlers, const String key, const String argument, const String default_program)
+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 = handlers.get(key);
+ 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 = handlers.get("*");
+ program_path = user_preferences.get("*");
if (program_path.has_value())
return spawn(program_path.value(), argument);
@@ -107,6 +156,29 @@ bool Launcher::open_with_handlers(const HashMap<String, String>& handlers, const
return spawn(default_program, argument);
}
+Vector<String> Launcher::handlers_for(const String& key, HashMap<String, String>& user_preference, Function<bool(Handler&, const String&)> handler_matches)
+{
+ Vector<String> handlers;
+
+ auto user_preferred = user_preference.get(key);
+ if (user_preferred.has_value())
+ handlers.append(user_preferred.value());
+
+ 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 (handler_matches(handler.value, key))
+ handlers.append(handler.value.executable);
+ }
+
+ auto user_default = user_preference.get("*");
+ if (handlers.size() == 0 && user_default.has_value())
+ handlers.append(user_default.value());
+
+ return handlers;
+}
+
Vector<String> Launcher::handlers_for_path(const String& path)
{
struct stat st;
@@ -120,7 +192,10 @@ Vector<String> Launcher::handlers_for_path(const String& path)
return { "/bin/FileManager" };
auto extension = FileSystemPath(path).extension().to_lowercase();
- return { m_file_handlers.get(extension).value_or(m_file_handlers.get("*").value_or({})) };
+
+ return handlers_for(extension, m_file_handlers, [](auto& handler, auto& key) {
+ return handler.file_types.contains(key);
+ });
}
bool Launcher::open_file_url(const URL& url)
@@ -142,7 +217,6 @@ bool Launcher::open_file_url(const URL& url)
String extension = {};
if (extension_parts.size() > 1)
extension = extension_parts.last();
- return open_with_handlers(m_file_handlers, extension, url.path(), "/bin/TextEdit");
+ return open_with_user_preferences(m_file_handlers, extension, url.path(), "/bin/TextEdit");
}
-
}
diff --git a/Services/LaunchServer/Launcher.h b/Services/LaunchServer/Launcher.h
index 0559c3c04b..ff241c6c7f 100644
--- a/Services/LaunchServer/Launcher.h
+++ b/Services/LaunchServer/Launcher.h
@@ -27,26 +27,38 @@
#pragma once
#include <AK/HashMap.h>
+#include <AK/HashTable.h>
#include <AK/URL.h>
#include <LibCore/ConfigFile.h>
namespace LaunchServer {
+struct Handler {
+ String name;
+ String executable;
+ HashTable<String> file_types;
+ HashTable<String> protocols;
+};
+
class Launcher {
public:
Launcher();
static Launcher& the();
+ void load_handlers(const String& af_dir);
void load_config(const Core::ConfigFile&);
- bool open_url(const URL&);
+ bool open_url(const URL&, const String& handler_name);
Vector<String> handlers_for_url(const URL&);
private:
+ HashMap<String, Handler> m_handlers;
HashMap<String, String> m_protocol_handlers;
HashMap<String, String> m_file_handlers;
+ Vector<String> handlers_for(const String& key, HashMap<String, String>& user_preferences, Function<bool(Handler&, const String&)> handler_matches);
Vector<String> handlers_for_path(const String&);
bool open_file_url(const URL&);
- bool open_with_handlers(const HashMap<String, String>& handlers, const String key, const String argument, const String default_program);
+ 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
index 61b2533d69..97c83fcbfb 100644
--- a/Services/LaunchServer/main.cpp
+++ b/Services/LaunchServer/main.cpp
@@ -42,6 +42,7 @@ int main(int argc, char** argv)
auto launcher = LaunchServer::Launcher();
+ launcher.load_handlers("/res/apps");
launcher.load_config(Core::ConfigFile::get_for_app("LaunchServer"));
if (pledge("stdio accept rpath proc exec", nullptr) < 0) {