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 :^)
This commit is contained in:
Maciej 2021-12-29 16:34:57 +01:00 committed by Andreas Kling
parent ccb8374434
commit 2e8e959896
Notes: sideshowbarker 2024-07-17 20:32:51 +09:00
2 changed files with 90 additions and 41 deletions

View File

@ -7,8 +7,10 @@
#include "QuickLaunchWidget.h"
#include <LibConfig/Client.h>
#include <LibCore/MimeData.h>
#include <LibCore/System.h>
#include <LibGUI/BoxLayout.h>
#include <LibGUI/Menu.h>
#include <LibGUI/MessageBox.h>
#include <serenity.h>
namespace Taskbar {
@ -16,6 +18,27 @@ namespace Taskbar {
constexpr auto quick_launch = "QuickLaunch"sv;
constexpr int quick_launch_button_size = 24;
ErrorOr<void> 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<Desktop::AppFile> app_file)
OwnPtr<QuickLaunchEntry> QuickLaunchEntry::create_from_config_value(StringView value)
{
if (!app_file->is_valid())
return;
auto button = find_child_of_type_named<GUI::Button>(button_name);
if (!button) {
button = &add<GUI::Button>();
if (value.ends_with(".af")) {
auto af_path = String::formatted("{}/{}", Desktop::AppFile::APP_FILES_DIRECTORY, value);
return make<QuickLaunchEntryAppFile>(Desktop::AppFile::open(af_path));
}
auto app_executable = app_file->executable();
auto app_run_in_terminal = app_file->run_in_terminal();
return {};
}
OwnPtr<QuickLaunchEntry> QuickLaunchEntry::create_from_path(StringView path)
{
if (path.ends_with(".af"))
return make<QuickLaunchEntryAppFile>(Desktop::AppFile::open(path));
return {};
}
void QuickLaunchWidget::add_or_adjust_button(String const& button_name, NonnullOwnPtr<QuickLaunchEntry>&& entry)
{
auto button = find_child_of_type_named<GUI::Button>(button_name);
if (!button)
button = &add<GUI::Button>();
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());
}
}

View File

@ -13,6 +13,32 @@
namespace Taskbar {
class QuickLaunchEntry {
public:
virtual ~QuickLaunchEntry() = default;
virtual ErrorOr<void> launch() const = 0;
virtual GUI::Icon icon() const = 0;
virtual String name() const = 0;
static OwnPtr<QuickLaunchEntry> create_from_config_value(StringView path);
static OwnPtr<QuickLaunchEntry> create_from_path(StringView path);
};
class QuickLaunchEntryAppFile : public QuickLaunchEntry {
public:
explicit QuickLaunchEntryAppFile(NonnullRefPtr<Desktop::AppFile> file)
: m_app_file(move(file))
{
}
virtual ErrorOr<void> 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<Desktop::AppFile> 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<Desktop::AppFile>);
void add_or_adjust_button(String const&, NonnullOwnPtr<QuickLaunchEntry>&&);
RefPtr<GUI::Menu> m_context_menu;
RefPtr<GUI::Action> m_context_menu_default_action;
String m_context_menu_app_name;