From 2e8e959896aed1802b03b82eab37aa0b4c36d159 Mon Sep 17 00:00:00 2001 From: Maciej Date: Wed, 29 Dec 2021 16:34:57 +0100 Subject: [PATCH] Taskbar: Abstract out quick launch entries ... into QuickLaunchEntry class. It will be used to implement adding plain executables to the taskbar. For now, it adds TRY() error handling to app launching :^) --- .../Services/Taskbar/QuickLaunchWidget.cpp | 103 +++++++++++------- Userland/Services/Taskbar/QuickLaunchWidget.h | 28 ++++- 2 files changed, 90 insertions(+), 41 deletions(-) diff --git a/Userland/Services/Taskbar/QuickLaunchWidget.cpp b/Userland/Services/Taskbar/QuickLaunchWidget.cpp index f968a27786..f18685b86f 100644 --- a/Userland/Services/Taskbar/QuickLaunchWidget.cpp +++ b/Userland/Services/Taskbar/QuickLaunchWidget.cpp @@ -7,8 +7,10 @@ #include "QuickLaunchWidget.h" #include #include +#include #include #include +#include #include namespace Taskbar { @@ -16,6 +18,27 @@ namespace Taskbar { constexpr auto quick_launch = "QuickLaunch"sv; constexpr int quick_launch_button_size = 24; +ErrorOr QuickLaunchEntryAppFile::launch() const +{ + auto executable = m_app_file->executable(); + + pid_t pid = TRY(Core::System::fork()); + if (pid == 0) { + if (chdir(Core::StandardPaths::home_directory().characters()) < 0) { + perror("chdir"); + exit(1); + } + if (m_app_file->run_in_terminal()) + execl("/bin/Terminal", "Terminal", "-e", executable.characters(), nullptr); + else + execl(executable.characters(), executable.characters(), nullptr); + perror("execl"); + VERIFY_NOT_REACHED(); + } else + TRY(Core::System::disown(pid)); + return {}; +} + QuickLaunchWidget::QuickLaunchWidget() { set_shrink_to_fit(true); @@ -36,10 +59,11 @@ QuickLaunchWidget::QuickLaunchWidget() auto keys = Config::list_keys("Taskbar", quick_launch); for (auto& name : keys) { - auto af_name = Config::read_string("Taskbar", quick_launch, name); - auto af_path = String::formatted("{}/{}", Desktop::AppFile::APP_FILES_DIRECTORY, af_name); - auto af = Desktop::AppFile::open(af_path); - add_or_adjust_button(name, af); + auto value = Config::read_string("Taskbar", quick_launch, name); + auto entry = QuickLaunchEntry::create_from_config_value(value); + if (!entry) + continue; + add_or_adjust_button(name, entry.release_nonnull()); } } @@ -47,40 +71,38 @@ QuickLaunchWidget::~QuickLaunchWidget() { } -void QuickLaunchWidget::add_or_adjust_button(String const& button_name, NonnullRefPtr app_file) +OwnPtr QuickLaunchEntry::create_from_config_value(StringView value) { - if (!app_file->is_valid()) - return; - auto button = find_child_of_type_named(button_name); - if (!button) { - button = &add(); + if (value.ends_with(".af")) { + auto af_path = String::formatted("{}/{}", Desktop::AppFile::APP_FILES_DIRECTORY, value); + return make(Desktop::AppFile::open(af_path)); } - auto app_executable = app_file->executable(); - auto app_run_in_terminal = app_file->run_in_terminal(); + return {}; +} + +OwnPtr QuickLaunchEntry::create_from_path(StringView path) +{ + if (path.ends_with(".af")) + return make(Desktop::AppFile::open(path)); + return {}; +} + +void QuickLaunchWidget::add_or_adjust_button(String const& button_name, NonnullOwnPtr&& entry) +{ + auto button = find_child_of_type_named(button_name); + if (!button) + button = &add(); + button->set_fixed_size(quick_launch_button_size, quick_launch_button_size); button->set_button_style(Gfx::ButtonStyle::Coolbar); - button->set_icon(app_file->icon().bitmap_for_size(16)); - button->set_tooltip(app_file->name()); + auto icon = entry->icon(); + button->set_icon(icon.bitmap_for_size(16)); + button->set_tooltip(entry->name()); button->set_name(button_name); - button->on_click = [app_executable, app_run_in_terminal](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); - } - if (app_run_in_terminal) - execl("/bin/Terminal", "Terminal", "-e", app_executable.characters(), nullptr); - else - execl(app_executable.characters(), app_executable.characters(), nullptr); - perror("execl"); - VERIFY_NOT_REACHED(); - } else { - if (disown(pid) < 0) - perror("disown"); - } + button->on_click = [entry = move(entry), this](auto) { + auto result = entry->launch(); + if (result.is_error()) + GUI::MessageBox::show_error(window(), String::formatted("Failed to open quick launch entry: {}", result.release_error())); }; button->on_context_menu_request = [this, button_name](auto& context_menu_event) { m_context_menu_app_name = button_name; @@ -100,9 +122,10 @@ void QuickLaunchWidget::config_key_was_removed(String const& domain, String cons void QuickLaunchWidget::config_string_did_change(String const& domain, String const& group, String const& key, String const& value) { if (domain == "Taskbar" && group == quick_launch) { - auto af_path = String::formatted("{}/{}", Desktop::AppFile::APP_FILES_DIRECTORY, value); - auto af = Desktop::AppFile::open(af_path); - add_or_adjust_button(key, af); + auto entry = QuickLaunchEntry::create_from_config_value(value); + if (!entry) + return; + add_or_adjust_button(key, entry.release_nonnull()); } } @@ -113,10 +136,10 @@ void QuickLaunchWidget::drop_event(GUI::DropEvent& event) if (event.mime_data().has_urls()) { auto urls = event.mime_data().urls(); for (auto& url : urls) { - auto af = Desktop::AppFile::open(url.path()); - if (af->is_valid()) { - auto item_name = af->name().replace(" ", "", true); - add_or_adjust_button(item_name, af); + auto entry = QuickLaunchEntry::create_from_path(url.path()); + if (entry) { + auto item_name = entry->name().replace(" ", "", true); + add_or_adjust_button(item_name, entry.release_nonnull()); Config::write_string("Taskbar", quick_launch, item_name, url.basename()); } } diff --git a/Userland/Services/Taskbar/QuickLaunchWidget.h b/Userland/Services/Taskbar/QuickLaunchWidget.h index 6f90c67c2f..fccecf88d9 100644 --- a/Userland/Services/Taskbar/QuickLaunchWidget.h +++ b/Userland/Services/Taskbar/QuickLaunchWidget.h @@ -13,6 +13,32 @@ namespace Taskbar { +class QuickLaunchEntry { +public: + virtual ~QuickLaunchEntry() = default; + virtual ErrorOr launch() const = 0; + virtual GUI::Icon icon() const = 0; + virtual String name() const = 0; + + static OwnPtr create_from_config_value(StringView path); + static OwnPtr create_from_path(StringView path); +}; + +class QuickLaunchEntryAppFile : public QuickLaunchEntry { +public: + explicit QuickLaunchEntryAppFile(NonnullRefPtr file) + : m_app_file(move(file)) + { + } + + virtual ErrorOr launch() const override; + virtual GUI::Icon icon() const override { return m_app_file->icon(); } + virtual String name() const override { return m_app_file->name(); } + +private: + NonnullRefPtr m_app_file; +}; + class QuickLaunchWidget : public GUI::Frame , public Config::Listener { C_OBJECT(QuickLaunchWidget); @@ -27,7 +53,7 @@ public: private: QuickLaunchWidget(); - void add_or_adjust_button(String const&, NonnullRefPtr); + void add_or_adjust_button(String const&, NonnullOwnPtr&&); RefPtr m_context_menu; RefPtr m_context_menu_default_action; String m_context_menu_app_name;