mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 08:47:34 +00:00
LaunchServer+LibDesktop: Open from mime type
Before, LaunchServer would only open files based on their extension. This wouldn't work if the file had the wrong one.
This commit is contained in:
parent
031322fde3
commit
48766449e5
4 changed files with 65 additions and 12 deletions
|
@ -102,6 +102,17 @@ bool AppFile::run_in_terminal() const
|
|||
return m_config->read_bool_entry("App", "RunInTerminal", false);
|
||||
}
|
||||
|
||||
Vector<String> AppFile::launcher_mime_types() const
|
||||
{
|
||||
Vector<String> mime_types;
|
||||
for (auto& entry : m_config->read_entry("Launcher", "MimeTypes").split(',')) {
|
||||
entry = entry.trim_whitespace();
|
||||
if (!entry.is_empty())
|
||||
mime_types.append(entry);
|
||||
}
|
||||
return mime_types;
|
||||
}
|
||||
|
||||
Vector<String> AppFile::launcher_file_types() const
|
||||
{
|
||||
Vector<String> file_types;
|
||||
|
|
|
@ -32,6 +32,7 @@ public:
|
|||
String icon_path() const;
|
||||
GUI::Icon icon() const;
|
||||
bool run_in_terminal() const;
|
||||
Vector<String> launcher_mime_types() const;
|
||||
Vector<String> launcher_file_types() const;
|
||||
Vector<String> launcher_protocols() const;
|
||||
bool spawn() const;
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <AK/StringBuilder.h>
|
||||
#include <LibCore/ConfigFile.h>
|
||||
#include <LibCore/File.h>
|
||||
#include <LibCore/MimeData.h>
|
||||
#include <LibCore/Process.h>
|
||||
#include <LibDesktop/AppFile.h>
|
||||
#include <errno.h>
|
||||
|
@ -83,6 +84,9 @@ void Launcher::load_handlers(String const& af_dir)
|
|||
Desktop::AppFile::for_each([&](auto af) {
|
||||
auto app_name = af->name();
|
||||
auto app_executable = af->executable();
|
||||
HashTable<String> mime_types;
|
||||
for (auto& mime_type : af->launcher_mime_types())
|
||||
mime_types.set(mime_type);
|
||||
HashTable<String> file_types;
|
||||
for (auto& file_type : af->launcher_file_types())
|
||||
file_types.set(file_type);
|
||||
|
@ -90,13 +94,22 @@ void Launcher::load_handlers(String const& af_dir)
|
|||
for (auto& protocol : af->launcher_protocols())
|
||||
protocols.set(protocol);
|
||||
if (access(app_executable.characters(), X_OK) == 0)
|
||||
m_handlers.set(app_executable, { Handler::Type::Default, app_name, app_executable, file_types, protocols });
|
||||
m_handlers.set(app_executable, { Handler::Type::Default, app_name, app_executable, mime_types, file_types, protocols });
|
||||
},
|
||||
af_dir);
|
||||
}
|
||||
|
||||
void Launcher::load_config(Core::ConfigFile const& cfg)
|
||||
{
|
||||
for (auto key : cfg.keys("MimeType")) {
|
||||
auto handler = cfg.read_entry("MimeType", key).trim_whitespace();
|
||||
if (handler.is_empty())
|
||||
continue;
|
||||
if (access(handler.characters(), X_OK) != 0)
|
||||
continue;
|
||||
m_mime_handlers.set(key.to_lowercase(), handler);
|
||||
}
|
||||
|
||||
for (auto key : cfg.keys("FileType")) {
|
||||
auto handler = cfg.read_entry("FileType", key).trim_whitespace();
|
||||
if (handler.is_empty())
|
||||
|
@ -156,6 +169,20 @@ Vector<String> Launcher::handlers_with_details_for_url(const URL& url)
|
|||
return handlers;
|
||||
}
|
||||
|
||||
Optional<String> Launcher::mime_type_for_file(String path)
|
||||
{
|
||||
auto file_or_error = Core::File::open(path, Core::OpenMode::ReadOnly);
|
||||
if (file_or_error.is_error()) {
|
||||
return {};
|
||||
} else {
|
||||
auto file = file_or_error.release_value();
|
||||
// Read accounts for longest possible offset + signature we currently match against.
|
||||
auto bytes = file->read(0x9006);
|
||||
|
||||
return Core::guess_mime_type_based_on_sniffed_bytes(bytes.bytes());
|
||||
}
|
||||
}
|
||||
|
||||
bool Launcher::open_url(const URL& url, String const& handler_name)
|
||||
{
|
||||
if (!handler_name.is_null())
|
||||
|
@ -275,13 +302,21 @@ void Launcher::for_each_handler_for_path(String const& path, Function<bool(Handl
|
|||
f(get_handler_for_executable(Handler::Type::Application, path));
|
||||
|
||||
auto extension = LexicalPath::extension(path).to_lowercase();
|
||||
|
||||
auto mime_type = mime_type_for_file(path);
|
||||
if (mime_type.has_value()) {
|
||||
for_each_handler(mime_type.value(), m_mime_handlers, [&](auto const& handler) -> bool {
|
||||
if (handler.handler_type != Handler::Type::Default || handler.mime_types.contains(mime_type.value()))
|
||||
return f(handler);
|
||||
return false;
|
||||
});
|
||||
} else {
|
||||
for_each_handler(extension, m_file_handlers, [&](auto const& 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)
|
||||
{
|
||||
|
@ -312,10 +347,13 @@ bool Launcher::open_file_url(const URL& url)
|
|||
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();
|
||||
auto extension = LexicalPath::extension(url.path()).to_lowercase();
|
||||
auto mime_type = mime_type_for_file(url.path());
|
||||
|
||||
auto mime_type_or_extension = extension;
|
||||
bool should_use_mime_type = mime_type.has_value() && m_mime_handlers.get(mime_type.value()).has_value();
|
||||
if (should_use_mime_type)
|
||||
mime_type_or_extension = mime_type.value();
|
||||
|
||||
auto handler_optional = m_file_handlers.get("txt");
|
||||
if (!handler_optional.has_value())
|
||||
|
@ -339,6 +377,6 @@ bool Launcher::open_file_url(const URL& url)
|
|||
|
||||
additional_parameters.append(filepath);
|
||||
|
||||
return open_with_user_preferences(m_file_handlers, extension, additional_parameters, default_handler);
|
||||
return open_with_user_preferences(should_use_mime_type ? m_mime_handlers : m_file_handlers, mime_type_or_extension, additional_parameters, default_handler);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ struct Handler {
|
|||
Type handler_type;
|
||||
String name;
|
||||
String executable;
|
||||
HashTable<String> mime_types {};
|
||||
HashTable<String> file_types {};
|
||||
HashTable<String> protocols {};
|
||||
|
||||
|
@ -47,7 +48,9 @@ private:
|
|||
HashMap<String, Handler> m_handlers;
|
||||
HashMap<String, String> m_protocol_handlers;
|
||||
HashMap<String, String> m_file_handlers;
|
||||
HashMap<String, String> m_mime_handlers;
|
||||
|
||||
Optional<String> mime_type_for_file(String path);
|
||||
Handler get_handler_for_executable(Handler::Type, String const&) const;
|
||||
void for_each_handler(String const& key, HashMap<String, String>& user_preferences, Function<bool(Handler const&)> f);
|
||||
void for_each_handler_for_path(String const&, Function<bool(Handler const&)> f);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue