diff --git a/Applications/FileManager/DirectoryView.cpp b/Applications/FileManager/DirectoryView.cpp index bcf49179ab..65834ee3ea 100644 --- a/Applications/FileManager/DirectoryView.cpp +++ b/Applications/FileManager/DirectoryView.cpp @@ -45,6 +45,11 @@ NonnullRefPtr LauncherHandler::create_launch_action(Function DirectoryView::get_default_launch_handler(const NonnullRefPtrVector& handlers) { + // If this is an application, pick it first + for (size_t i = 0; i < handlers.size(); i++) { + if (handlers[i].details().launcher_type == Desktop::Launcher::LauncherType::Application) + return handlers[i]; + } // If there's a handler preferred by the user, pick this first for (size_t i = 0; i < handlers.size(); i++) { if (handlers[i].details().launcher_type == Desktop::Launcher::LauncherType::UserPreferred) @@ -99,8 +104,8 @@ void DirectoryView::handle_activation(const GUI::ModelIndex& index) auto url = URL::create_with_file_protocol(path); auto launcher_handlers = get_launch_handlers(url); auto default_launcher = get_default_launch_handler(launcher_handlers); - if (default_launcher) { - Desktop::Launcher::open(url, default_launcher->details()); + if (default_launcher && on_launch) { + on_launch(url, *default_launcher); } else { auto error_message = String::format("Could not open %s", path.characters()); GUI::MessageBox::show(error_message, "File Manager", GUI::MessageBox::Type::Error); diff --git a/Applications/FileManager/DirectoryView.h b/Applications/FileManager/DirectoryView.h index 88fedefb74..b5728987ea 100644 --- a/Applications/FileManager/DirectoryView.h +++ b/Applications/FileManager/DirectoryView.h @@ -70,6 +70,7 @@ public: void refresh(); + Function on_launch; Function on_path_change; Function on_selection_change; Function on_context_menu_request; diff --git a/Applications/FileManager/main.cpp b/Applications/FileManager/main.cpp index af96c596a2..0237349b2a 100644 --- a/Applications/FileManager/main.cpp +++ b/Applications/FileManager/main.cpp @@ -742,11 +742,16 @@ int run_in_windowed_mode(RefPtr config, String initial_locatio NonnullRefPtrVector current_file_handlers; RefPtr file_context_menu_action_default_action; - auto file_open_action_handler = [&](const LauncherHandler& launcher_handler) { + directory_view.on_launch = [&](const AK::URL&, const LauncherHandler& launcher_handler) { pid_t child; - for (auto& path : selected_file_paths()) { - const char* argv[] = { launcher_handler.details().name.characters(), path.characters(), nullptr }; + if (launcher_handler.details().launcher_type == Desktop::Launcher::LauncherType::Application) { + const char* argv[] = { launcher_handler.details().name.characters(), nullptr }; posix_spawn(&child, launcher_handler.details().executable.characters(), nullptr, nullptr, const_cast(argv), environ); + } else { + for (auto& path : selected_file_paths()) { + const char* argv[] = { launcher_handler.details().name.characters(), path.characters(), nullptr }; + posix_spawn(&child, launcher_handler.details().executable.characters(), nullptr, nullptr, const_cast(argv), environ); + } } }; @@ -759,7 +764,8 @@ int run_in_windowed_mode(RefPtr config, String initial_locatio folder_specific_paste_action->set_enabled(should_get_enabled); directory_context_menu->popup(event.screen_position()); } else { - current_file_handlers = directory_view.get_launch_handlers(node.full_path(directory_view.model())); + auto full_path = node.full_path(directory_view.model()); + current_file_handlers = directory_view.get_launch_handlers(full_path); file_context_menu = GUI::Menu::construct("Directory View File"); file_context_menu->add_action(copy_action); @@ -770,10 +776,13 @@ int run_in_windowed_mode(RefPtr config, String initial_locatio bool added_open_menu_items = false; auto default_file_handler = directory_view.get_default_launch_handler(current_file_handlers); if (default_file_handler) { - auto file_open_action = default_file_handler->create_launch_action([&](auto& launcher_handler) { - file_open_action_handler(launcher_handler); + auto file_open_action = default_file_handler->create_launch_action([&, full_path = move(full_path)](auto& launcher_handler) { + directory_view.on_launch(URL::create_with_file_protocol(full_path), launcher_handler); }); - file_open_action->set_text(String::format("Open in %s", file_open_action->text().characters())); + if (default_file_handler->details().launcher_type == Desktop::Launcher::LauncherType::Application) + file_open_action->set_text(String::format("Run %s", file_open_action->text().characters())); + else + file_open_action->set_text(String::format("Open in %s", file_open_action->text().characters())); file_context_menu_action_default_action = file_open_action; @@ -789,8 +798,8 @@ int run_in_windowed_mode(RefPtr config, String initial_locatio for (auto& handler : current_file_handlers) { if (&handler == default_file_handler.ptr()) continue; - file_open_with_menu.add_action(handler.create_launch_action([&](auto& launcher_handler) { - file_open_action_handler(launcher_handler); + file_open_with_menu.add_action(handler.create_launch_action([&, full_path = move(full_path)](auto& launcher_handler) { + directory_view.on_launch(URL::create_with_file_protocol(full_path), launcher_handler); })); } } diff --git a/Libraries/LibDesktop/Launcher.cpp b/Libraries/LibDesktop/Launcher.cpp index 8a42beebc8..39b6888810 100644 --- a/Libraries/LibDesktop/Launcher.cpp +++ b/Libraries/LibDesktop/Launcher.cpp @@ -44,7 +44,9 @@ auto Launcher::Details::from_details_str(const String& details_str) -> NonnullRe details->name = obj.get("name").to_string(); if (auto type_value = obj.get_ptr("type")) { auto type_str = type_value->to_string(); - if (type_str == "userpreferred") + if (type_str == "app") + details->launcher_type = LauncherType::Application; + else if (type_str == "userpreferred") details->launcher_type = LauncherType::UserPreferred; else if (type_str == "userdefault") details->launcher_type = LauncherType::UserDefault; @@ -83,6 +85,7 @@ bool Launcher::open(const URL& url, const String& handler_name) bool Launcher::open(const URL& url, const Details& details) { + ASSERT(details.launcher_type != LauncherType::Application); // Launcher should not be used to execute arbitrary applications return open(url, details.executable); } diff --git a/Libraries/LibDesktop/Launcher.h b/Libraries/LibDesktop/Launcher.h index 0dc0748231..3a42b1ae82 100644 --- a/Libraries/LibDesktop/Launcher.h +++ b/Libraries/LibDesktop/Launcher.h @@ -38,6 +38,7 @@ class Launcher { public: enum class LauncherType { Default = 0, + Application, UserPreferred, UserDefault }; diff --git a/Services/LaunchServer/Launcher.cpp b/Services/LaunchServer/Launcher.cpp index 4715de42a6..ef179ec403 100644 --- a/Services/LaunchServer/Launcher.cpp +++ b/Services/LaunchServer/Launcher.cpp @@ -66,6 +66,9 @@ String Handler::to_details_str() const 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; @@ -75,10 +78,12 @@ String Handler::to_details_str() const default: break; } - JsonObject icons_obj; - for (auto& icon : icons) - icons_obj.set(icon.key, icon.value); - obj.add("icons", move(icons_obj)); + if (!icons.is_empty()) { + JsonObject icons_obj; + for (auto& icon : icons) + icons_obj.set(icon.key, icon.value); + obj.add("icons", move(icons_obj)); + } obj.finish(); return builder.build(); } @@ -282,6 +287,9 @@ void Launcher::for_each_handler_for_path(const String& path, Function bool { @@ -303,7 +311,7 @@ bool Launcher::open_file_url(const URL& url) if (S_ISDIR(st.st_mode)) return spawn("/bin/FileManager", url.path()); - if (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) + 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('.'); diff --git a/Services/LaunchServer/Launcher.h b/Services/LaunchServer/Launcher.h index 2796cdb960..2108ffd897 100644 --- a/Services/LaunchServer/Launcher.h +++ b/Services/LaunchServer/Launcher.h @@ -36,6 +36,7 @@ namespace LaunchServer { struct Handler { enum class Type { Default = 0, + Application, UserPreferred, UserDefault };