2020-01-18 09:38:21 +01:00
|
|
|
/*
|
2023-02-20 19:03:44 +01:00
|
|
|
* Copyright (c) 2018-2023, Andreas Kling <kling@serenityos.org>
|
2020-01-18 09:38:21 +01:00
|
|
|
*
|
2021-04-22 01:24:48 -07:00
|
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
2020-01-18 09:38:21 +01:00
|
|
|
*/
|
|
|
|
|
|
2020-08-22 13:08:39 +02:00
|
|
|
#include <AK/NeverDestroyed.h>
|
2023-02-06 18:39:59 +01:00
|
|
|
#include <LibConfig/Client.h>
|
2020-02-16 09:17:49 +01:00
|
|
|
#include <LibCore/EventLoop.h>
|
2020-02-06 20:33:02 +01:00
|
|
|
#include <LibGUI/Action.h>
|
|
|
|
|
#include <LibGUI/Application.h>
|
2020-05-14 22:51:15 +02:00
|
|
|
#include <LibGUI/Clipboard.h>
|
2022-02-25 12:39:33 +02:00
|
|
|
#include <LibGUI/ConnectionToWindowServer.h>
|
2020-02-06 20:33:02 +01:00
|
|
|
#include <LibGUI/Desktop.h>
|
|
|
|
|
#include <LibGUI/Label.h>
|
2021-04-13 16:18:20 +02:00
|
|
|
#include <LibGUI/Menubar.h>
|
2020-02-06 20:33:02 +01:00
|
|
|
#include <LibGUI/Painter.h>
|
|
|
|
|
#include <LibGUI/Window.h>
|
2022-04-09 09:28:38 +02:00
|
|
|
#include <LibGfx/Font/Font.h>
|
2020-02-14 23:53:11 +01:00
|
|
|
#include <LibGfx/Palette.h>
|
2019-02-11 14:43:43 +01:00
|
|
|
|
2020-02-02 15:07:41 +01:00
|
|
|
namespace GUI {
|
2019-02-11 14:56:23 +01:00
|
|
|
|
2020-12-28 21:26:47 +01:00
|
|
|
class Application::TooltipWindow final : public Window {
|
|
|
|
|
C_OBJECT(TooltipWindow);
|
|
|
|
|
|
|
|
|
|
public:
|
2023-09-10 16:44:32 +02:00
|
|
|
void set_tooltip(String tooltip)
|
2020-12-28 21:26:47 +01:00
|
|
|
{
|
2023-09-10 16:44:32 +02:00
|
|
|
m_label->set_text(move(tooltip));
|
2022-06-12 23:17:42 +02:00
|
|
|
int tooltip_width = m_label->effective_min_size().width().as_int() + 10;
|
2022-07-11 17:32:29 +00:00
|
|
|
int line_count = m_label->text().count("\n"sv);
|
2023-03-03 19:32:19 +01:00
|
|
|
int font_size = m_label->font().pixel_size_rounded_up();
|
|
|
|
|
int tooltip_height = font_size * (1 + line_count) + ((font_size + 1) / 2) * line_count + 8;
|
2021-06-02 14:46:15 -06:00
|
|
|
|
|
|
|
|
Gfx::IntRect desktop_rect = Desktop::the().rect();
|
|
|
|
|
if (tooltip_width > desktop_rect.width())
|
|
|
|
|
tooltip_width = desktop_rect.width();
|
|
|
|
|
|
2021-07-04 10:41:51 +02:00
|
|
|
set_rect(rect().x(), rect().y(), tooltip_width, tooltip_height);
|
2020-12-28 21:26:47 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
TooltipWindow()
|
|
|
|
|
{
|
|
|
|
|
set_window_type(WindowType::Tooltip);
|
2022-08-09 21:42:40 +02:00
|
|
|
set_obey_widget_min_size(false);
|
2023-09-19 01:13:48 +01:00
|
|
|
m_label = set_main_widget<Label>();
|
2020-12-28 21:26:47 +01:00
|
|
|
m_label->set_background_role(Gfx::ColorRole::Tooltip);
|
|
|
|
|
m_label->set_foreground_role(Gfx::ColorRole::TooltipText);
|
|
|
|
|
m_label->set_fill_with_background_color(true);
|
2023-04-29 16:47:52 -04:00
|
|
|
m_label->set_frame_style(Gfx::FrameStyle::Plain);
|
2021-04-11 01:09:44 +02:00
|
|
|
m_label->set_autosize(true);
|
2020-12-28 21:26:47 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RefPtr<Label> m_label;
|
|
|
|
|
};
|
|
|
|
|
|
2020-08-22 13:08:39 +02:00
|
|
|
static NeverDestroyed<WeakPtr<Application>> s_the;
|
2020-02-02 15:07:41 +01:00
|
|
|
|
2020-07-04 16:52:01 +02:00
|
|
|
Application* Application::the()
|
2019-02-11 14:56:23 +01:00
|
|
|
{
|
2020-12-29 13:14:21 -07:00
|
|
|
// NOTE: If we don't explicitly call revoke_weak_ptrs() in the
|
|
|
|
|
// ~Application destructor, we would have to change this to
|
|
|
|
|
// return s_the->strong_ref().ptr();
|
|
|
|
|
// This is because this is using the unsafe operator*/operator->
|
|
|
|
|
// that do not have the ability to check the ref count!
|
2020-08-22 13:08:39 +02:00
|
|
|
return *s_the;
|
2019-02-11 14:56:23 +01:00
|
|
|
}
|
|
|
|
|
|
2023-05-05 00:24:53 -04:00
|
|
|
ErrorOr<NonnullRefPtr<Application>> Application::create(Main::Arguments const& arguments)
|
2019-02-11 14:43:43 +01:00
|
|
|
{
|
2023-05-05 00:24:53 -04:00
|
|
|
if (*s_the)
|
|
|
|
|
return Error::from_string_literal("An Application has already been created for this process!");
|
|
|
|
|
|
|
|
|
|
auto application = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) Application {}));
|
|
|
|
|
*s_the = *application;
|
|
|
|
|
|
|
|
|
|
application->m_event_loop = TRY(try_make<Core::EventLoop>());
|
|
|
|
|
|
2022-02-25 12:39:33 +02:00
|
|
|
ConnectionToWindowServer::the();
|
2023-05-05 00:28:07 -04:00
|
|
|
TRY(Clipboard::initialize({}));
|
2023-05-05 00:24:53 -04:00
|
|
|
|
|
|
|
|
if (arguments.argc > 0)
|
|
|
|
|
application->m_invoked_as = arguments.argv[0];
|
2020-05-12 15:47:13 +02:00
|
|
|
|
2020-08-14 19:55:25 +02:00
|
|
|
if (getenv("GUI_FOCUS_DEBUG"))
|
2023-05-05 00:24:53 -04:00
|
|
|
application->m_focus_debugging_enabled = true;
|
2020-05-12 15:47:13 +02:00
|
|
|
|
2021-07-28 00:58:01 +02:00
|
|
|
if (getenv("GUI_HOVER_DEBUG"))
|
2023-05-05 00:24:53 -04:00
|
|
|
application->m_hover_debugging_enabled = true;
|
2021-07-28 00:58:01 +02:00
|
|
|
|
2021-01-09 00:11:17 +01:00
|
|
|
if (getenv("GUI_DND_DEBUG"))
|
2023-05-05 00:24:53 -04:00
|
|
|
application->m_dnd_debugging_enabled = true;
|
2021-01-09 00:11:17 +01:00
|
|
|
|
2023-05-06 08:17:24 +02:00
|
|
|
if (!arguments.strings.is_empty()) {
|
|
|
|
|
for (auto arg : arguments.strings.slice(1))
|
|
|
|
|
TRY(application->m_args.try_append(arg));
|
|
|
|
|
}
|
2023-05-05 00:24:53 -04:00
|
|
|
|
|
|
|
|
application->m_tooltip_show_timer = TRY(Core::Timer::create_single_shot(700, [weak_application = application->make_weak_ptr<Application>()] {
|
|
|
|
|
weak_application->request_tooltip_show();
|
|
|
|
|
}));
|
2020-12-28 21:26:47 +01:00
|
|
|
|
2023-05-05 00:24:53 -04:00
|
|
|
application->m_tooltip_hide_timer = TRY(Core::Timer::create_single_shot(50, [weak_application = application->make_weak_ptr<Application>()] {
|
|
|
|
|
weak_application->tooltip_hide_timer_did_fire();
|
|
|
|
|
}));
|
2020-12-28 21:26:47 +01:00
|
|
|
|
2023-05-05 00:24:53 -04:00
|
|
|
return application;
|
2019-02-11 14:43:43 +01:00
|
|
|
}
|
|
|
|
|
|
2021-11-03 19:53:33 +01:00
|
|
|
static bool s_in_teardown;
|
|
|
|
|
|
|
|
|
|
bool Application::in_teardown()
|
|
|
|
|
{
|
|
|
|
|
return s_in_teardown;
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-02 15:07:41 +01:00
|
|
|
Application::~Application()
|
2019-02-11 14:43:43 +01:00
|
|
|
{
|
2021-11-03 19:53:33 +01:00
|
|
|
s_in_teardown = true;
|
2020-07-04 16:52:01 +02:00
|
|
|
revoke_weak_ptrs();
|
2019-02-11 14:43:43 +01:00
|
|
|
}
|
|
|
|
|
|
2020-02-02 15:07:41 +01:00
|
|
|
int Application::exec()
|
2019-02-11 14:43:43 +01:00
|
|
|
{
|
2020-07-01 20:49:00 +02:00
|
|
|
return m_event_loop->exec();
|
2019-02-11 14:43:43 +01:00
|
|
|
}
|
|
|
|
|
|
2020-02-02 15:07:41 +01:00
|
|
|
void Application::quit(int exit_code)
|
2019-02-11 14:56:23 +01:00
|
|
|
{
|
2019-02-17 09:58:35 +01:00
|
|
|
m_event_loop->quit(exit_code);
|
2019-02-11 14:56:23 +01:00
|
|
|
}
|
|
|
|
|
|
2020-02-02 15:07:41 +01:00
|
|
|
void Application::register_global_shortcut_action(Badge<Action>, Action& action)
|
2019-03-03 12:32:15 +01:00
|
|
|
{
|
2019-04-20 21:56:56 +02:00
|
|
|
m_global_shortcut_actions.set(action.shortcut(), &action);
|
2021-06-24 12:42:50 +03:00
|
|
|
m_global_shortcut_actions.set(action.alternate_shortcut(), &action);
|
2019-03-03 12:32:15 +01:00
|
|
|
}
|
|
|
|
|
|
2020-02-02 15:07:41 +01:00
|
|
|
void Application::unregister_global_shortcut_action(Badge<Action>, Action& action)
|
2019-03-03 12:32:15 +01:00
|
|
|
{
|
2019-04-20 21:56:56 +02:00
|
|
|
m_global_shortcut_actions.remove(action.shortcut());
|
2021-06-24 12:42:50 +03:00
|
|
|
m_global_shortcut_actions.remove(action.alternate_shortcut());
|
2019-03-03 12:32:15 +01:00
|
|
|
}
|
|
|
|
|
|
2022-02-05 18:39:34 +11:00
|
|
|
Action* Application::action_for_shortcut(Shortcut const& shortcut) const
|
2019-03-03 12:32:15 +01:00
|
|
|
{
|
2022-02-05 18:39:34 +11:00
|
|
|
auto it = m_global_shortcut_actions.find(shortcut);
|
2019-04-20 21:56:56 +02:00
|
|
|
if (it == m_global_shortcut_actions.end())
|
2019-03-03 12:32:15 +01:00
|
|
|
return nullptr;
|
|
|
|
|
return (*it).value;
|
|
|
|
|
}
|
2019-04-08 18:58:44 +02:00
|
|
|
|
2023-09-10 16:44:32 +02:00
|
|
|
void Application::show_tooltip(String tooltip, Widget const* tooltip_source_widget)
|
2019-04-08 18:58:44 +02:00
|
|
|
{
|
2022-08-15 06:00:33 -04:00
|
|
|
if (!Desktop::the().system_effects().tooltips())
|
|
|
|
|
return;
|
2020-08-15 11:44:34 +02:00
|
|
|
m_tooltip_source_widget = tooltip_source_widget;
|
2019-04-08 18:58:44 +02:00
|
|
|
if (!m_tooltip_window) {
|
2020-02-15 01:27:37 +01:00
|
|
|
m_tooltip_window = TooltipWindow::construct();
|
2019-04-08 18:58:44 +02:00
|
|
|
m_tooltip_window->set_double_buffering_enabled(false);
|
|
|
|
|
}
|
2020-12-28 21:26:47 +01:00
|
|
|
m_tooltip_window->set_tooltip(move(tooltip));
|
|
|
|
|
|
|
|
|
|
if (m_tooltip_window->is_visible()) {
|
2021-08-07 13:58:53 +02:00
|
|
|
request_tooltip_show();
|
2020-12-28 21:26:47 +01:00
|
|
|
m_tooltip_show_timer->stop();
|
|
|
|
|
m_tooltip_hide_timer->stop();
|
|
|
|
|
} else {
|
|
|
|
|
m_tooltip_show_timer->restart();
|
|
|
|
|
m_tooltip_hide_timer->stop();
|
2019-12-05 17:59:06 +01:00
|
|
|
}
|
2019-04-08 18:58:44 +02:00
|
|
|
}
|
|
|
|
|
|
2023-09-10 16:44:32 +02:00
|
|
|
void Application::show_tooltip_immediately(String tooltip, Widget const* tooltip_source_widget)
|
2021-08-07 13:58:53 +02:00
|
|
|
{
|
2022-08-15 06:00:33 -04:00
|
|
|
if (!Desktop::the().system_effects().tooltips())
|
|
|
|
|
return;
|
2021-08-07 13:58:53 +02:00
|
|
|
m_tooltip_source_widget = tooltip_source_widget;
|
|
|
|
|
if (!m_tooltip_window) {
|
|
|
|
|
m_tooltip_window = TooltipWindow::construct();
|
|
|
|
|
m_tooltip_window->set_double_buffering_enabled(false);
|
|
|
|
|
}
|
|
|
|
|
m_tooltip_window->set_tooltip(move(tooltip));
|
|
|
|
|
|
|
|
|
|
request_tooltip_show();
|
|
|
|
|
m_tooltip_show_timer->stop();
|
|
|
|
|
m_tooltip_hide_timer->stop();
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-02 15:07:41 +01:00
|
|
|
void Application::hide_tooltip()
|
2019-04-08 18:58:44 +02:00
|
|
|
{
|
2020-12-28 21:26:47 +01:00
|
|
|
m_tooltip_show_timer->stop();
|
|
|
|
|
m_tooltip_hide_timer->start();
|
2019-04-08 18:58:44 +02:00
|
|
|
}
|
2019-07-23 18:16:25 +02:00
|
|
|
|
2020-02-02 15:07:41 +01:00
|
|
|
void Application::did_create_window(Badge<Window>)
|
2019-10-25 00:23:35 -05:00
|
|
|
{
|
|
|
|
|
if (m_event_loop->was_exit_requested())
|
|
|
|
|
m_event_loop->unquit();
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-02 15:07:41 +01:00
|
|
|
void Application::did_delete_last_window(Badge<Window>)
|
2019-07-23 18:16:25 +02:00
|
|
|
{
|
|
|
|
|
if (m_quit_when_last_window_deleted)
|
|
|
|
|
m_event_loop->quit(0);
|
|
|
|
|
}
|
2019-12-24 20:57:54 +01:00
|
|
|
|
2021-01-16 17:20:53 +01:00
|
|
|
void Application::set_system_palette(Core::AnonymousBuffer& buffer)
|
2019-12-24 20:57:54 +01:00
|
|
|
{
|
|
|
|
|
if (!m_system_palette)
|
2021-01-16 17:20:53 +01:00
|
|
|
m_system_palette = Gfx::PaletteImpl::create_with_anonymous_buffer(buffer);
|
2019-12-24 20:57:54 +01:00
|
|
|
else
|
|
|
|
|
m_system_palette->replace_internal_buffer({}, buffer);
|
|
|
|
|
|
|
|
|
|
if (!m_palette)
|
|
|
|
|
m_palette = m_system_palette;
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-20 19:03:44 +01:00
|
|
|
void Application::set_palette(Palette& palette)
|
2019-12-24 20:57:54 +01:00
|
|
|
{
|
2019-12-29 00:47:49 +01:00
|
|
|
m_palette = palette.impl();
|
2019-12-24 20:57:54 +01:00
|
|
|
}
|
2020-02-02 15:07:41 +01:00
|
|
|
|
2020-02-15 01:18:12 +01:00
|
|
|
Gfx::Palette Application::palette() const
|
|
|
|
|
{
|
|
|
|
|
return Palette(*m_palette);
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-07 13:58:53 +02:00
|
|
|
void Application::request_tooltip_show()
|
2020-12-28 21:26:47 +01:00
|
|
|
{
|
2021-02-23 20:42:32 +01:00
|
|
|
VERIFY(m_tooltip_window);
|
2020-12-28 21:26:47 +01:00
|
|
|
Gfx::IntRect desktop_rect = Desktop::the().rect();
|
|
|
|
|
|
2022-04-01 20:58:27 +03:00
|
|
|
int const margin = 30;
|
2022-02-25 12:39:33 +02:00
|
|
|
Gfx::IntPoint adjusted_pos = ConnectionToWindowServer::the().get_global_cursor_position();
|
2020-12-28 21:26:47 +01:00
|
|
|
|
2022-07-25 19:16:56 -05:00
|
|
|
adjusted_pos.translate_by(0, 14);
|
2020-12-28 21:26:47 +01:00
|
|
|
|
|
|
|
|
if (adjusted_pos.x() + m_tooltip_window->width() >= desktop_rect.width() - margin) {
|
|
|
|
|
adjusted_pos = adjusted_pos.translated(-m_tooltip_window->width(), 0);
|
|
|
|
|
}
|
|
|
|
|
if (adjusted_pos.y() + m_tooltip_window->height() >= desktop_rect.height() - margin) {
|
|
|
|
|
adjusted_pos = adjusted_pos.translated(0, -(m_tooltip_window->height() * 2));
|
|
|
|
|
}
|
2021-06-02 14:46:15 -06:00
|
|
|
if (adjusted_pos.x() < 0)
|
|
|
|
|
adjusted_pos.set_x(0);
|
2020-12-28 21:26:47 +01:00
|
|
|
|
|
|
|
|
m_tooltip_window->move_to(adjusted_pos);
|
|
|
|
|
m_tooltip_window->show();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Application::tooltip_hide_timer_did_fire()
|
|
|
|
|
{
|
|
|
|
|
m_tooltip_source_widget = nullptr;
|
|
|
|
|
if (m_tooltip_window)
|
|
|
|
|
m_tooltip_window->hide();
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-05 15:43:59 +01:00
|
|
|
void Application::window_did_become_active(Badge<Window>, Window& window)
|
|
|
|
|
{
|
|
|
|
|
m_active_window = window.make_weak_ptr<Window>();
|
2021-07-28 20:22:42 +02:00
|
|
|
window.update();
|
2021-01-05 15:43:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Application::window_did_become_inactive(Badge<Window>, Window& window)
|
|
|
|
|
{
|
|
|
|
|
if (m_active_window.ptr() != &window)
|
|
|
|
|
return;
|
2021-07-28 20:22:42 +02:00
|
|
|
window.update();
|
2021-01-05 15:43:59 +01:00
|
|
|
m_active_window = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-09 00:11:17 +01:00
|
|
|
void Application::set_pending_drop_widget(Widget* widget)
|
|
|
|
|
{
|
|
|
|
|
if (m_pending_drop_widget == widget)
|
|
|
|
|
return;
|
|
|
|
|
if (m_pending_drop_widget)
|
|
|
|
|
m_pending_drop_widget->update();
|
|
|
|
|
m_pending_drop_widget = widget;
|
|
|
|
|
if (m_pending_drop_widget)
|
|
|
|
|
m_pending_drop_widget->update();
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-23 14:41:26 +02:00
|
|
|
void Application::set_drag_hovered_widget_impl(Widget* widget, Gfx::IntPoint position, Vector<String> mime_types)
|
2021-01-08 22:23:06 +01:00
|
|
|
{
|
|
|
|
|
if (widget == m_drag_hovered_widget)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (m_drag_hovered_widget) {
|
2021-01-09 00:11:17 +01:00
|
|
|
Event leave_event(Event::DragLeave);
|
|
|
|
|
m_drag_hovered_widget->dispatch_event(leave_event, m_drag_hovered_widget->window());
|
2021-01-08 22:23:06 +01:00
|
|
|
}
|
|
|
|
|
|
2021-01-09 00:11:17 +01:00
|
|
|
set_pending_drop_widget(nullptr);
|
2021-01-08 22:23:06 +01:00
|
|
|
m_drag_hovered_widget = widget;
|
|
|
|
|
|
|
|
|
|
if (m_drag_hovered_widget) {
|
2021-01-09 11:01:41 +01:00
|
|
|
DragEvent enter_event(Event::DragEnter, position, move(mime_types));
|
2021-01-09 00:11:17 +01:00
|
|
|
enter_event.ignore();
|
|
|
|
|
m_drag_hovered_widget->dispatch_event(enter_event, m_drag_hovered_widget->window());
|
|
|
|
|
if (enter_event.is_accepted())
|
|
|
|
|
set_pending_drop_widget(m_drag_hovered_widget);
|
2022-06-20 11:56:18 +02:00
|
|
|
ConnectionToWindowServer::the().async_set_accepts_drag(enter_event.is_accepted());
|
2021-01-08 22:23:06 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-25 12:39:33 +02:00
|
|
|
void Application::notify_drag_cancelled(Badge<ConnectionToWindowServer>)
|
2021-01-08 22:23:06 +01:00
|
|
|
{
|
|
|
|
|
set_drag_hovered_widget_impl(nullptr);
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-17 18:21:15 +02:00
|
|
|
void Application::event(Core::Event& event)
|
|
|
|
|
{
|
|
|
|
|
if (event.type() == GUI::Event::ActionEnter || event.type() == GUI::Event::ActionLeave) {
|
|
|
|
|
auto& action_event = static_cast<ActionEvent&>(event);
|
|
|
|
|
auto& action = action_event.action();
|
|
|
|
|
if (action_event.type() == GUI::Event::ActionEnter) {
|
|
|
|
|
if (on_action_enter)
|
|
|
|
|
on_action_enter(action);
|
|
|
|
|
} else {
|
|
|
|
|
if (on_action_leave)
|
|
|
|
|
on_action_leave(action);
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-06-16 14:16:31 +02:00
|
|
|
if (event.type() == GUI::Event::ThemeChange) {
|
|
|
|
|
if (on_theme_change)
|
|
|
|
|
on_theme_change();
|
|
|
|
|
}
|
2023-08-06 18:09:39 +02:00
|
|
|
EventReceiver::event(event);
|
2021-04-17 18:21:15 +02:00
|
|
|
}
|
|
|
|
|
|
2023-02-06 18:39:59 +01:00
|
|
|
void Application::set_config_domain(String config_domain)
|
|
|
|
|
{
|
|
|
|
|
m_config_domain = move(config_domain);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Application::register_recent_file_actions(Badge<GUI::Menu>, Vector<NonnullRefPtr<GUI::Action>> actions)
|
|
|
|
|
{
|
|
|
|
|
m_recent_file_actions = move(actions);
|
|
|
|
|
update_recent_file_actions();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Application::update_recent_file_actions()
|
|
|
|
|
{
|
|
|
|
|
VERIFY(!m_config_domain.is_empty());
|
|
|
|
|
|
|
|
|
|
size_t number_of_recently_open_files = 0;
|
|
|
|
|
auto update_action = [&](size_t index) {
|
|
|
|
|
auto& action = m_recent_file_actions[index];
|
|
|
|
|
char buffer = static_cast<char>('0' + index);
|
|
|
|
|
auto key = StringView(&buffer, 1);
|
|
|
|
|
auto path = Config::read_string(m_config_domain, "RecentFiles"sv, key);
|
|
|
|
|
|
|
|
|
|
if (path.is_empty()) {
|
|
|
|
|
action->set_visible(false);
|
|
|
|
|
action->set_enabled(false);
|
|
|
|
|
} else {
|
|
|
|
|
action->set_visible(true);
|
|
|
|
|
action->set_enabled(true);
|
|
|
|
|
action->set_text(path);
|
2023-06-17 16:37:55 +01:00
|
|
|
action->set_status_tip(String::formatted("Open {}", path).release_value_but_fixme_should_propagate_errors());
|
2023-02-06 18:39:59 +01:00
|
|
|
++number_of_recently_open_files;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
for (size_t i = 0; i < max_recently_open_files(); ++i)
|
|
|
|
|
update_action(i);
|
|
|
|
|
|
|
|
|
|
// Hide or show the "(No recently open files)" placeholder.
|
|
|
|
|
m_recent_file_actions.last()->set_visible(number_of_recently_open_files == 0);
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-19 16:18:03 +00:00
|
|
|
void Application::set_most_recently_open_file(ByteString new_path)
|
2023-02-06 18:39:59 +01:00
|
|
|
{
|
2023-12-16 17:49:34 +03:30
|
|
|
Vector<ByteString> new_recent_files_list;
|
2023-02-06 18:39:59 +01:00
|
|
|
|
|
|
|
|
for (size_t i = 0; i < max_recently_open_files(); ++i) {
|
|
|
|
|
static_assert(max_recently_open_files() < 10);
|
|
|
|
|
char buffer = static_cast<char>('0' + i);
|
|
|
|
|
auto key = StringView(&buffer, 1);
|
|
|
|
|
new_recent_files_list.append(Config::read_string(m_config_domain, "RecentFiles"sv, key));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
new_recent_files_list.remove_all_matching([&](auto& existing_path) {
|
|
|
|
|
return existing_path.view() == new_path;
|
|
|
|
|
});
|
|
|
|
|
|
2024-01-19 16:18:03 +00:00
|
|
|
new_recent_files_list.prepend(new_path);
|
2023-02-06 18:39:59 +01:00
|
|
|
|
|
|
|
|
for (size_t i = 0; i < max_recently_open_files(); ++i) {
|
|
|
|
|
auto& path = new_recent_files_list[i];
|
|
|
|
|
char buffer = static_cast<char>('0' + i);
|
|
|
|
|
auto key = StringView(&buffer, 1);
|
|
|
|
|
Config::write_string(
|
|
|
|
|
m_config_domain,
|
|
|
|
|
"RecentFiles"sv,
|
|
|
|
|
key,
|
|
|
|
|
path);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
update_recent_file_actions();
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-02 15:07:41 +01:00
|
|
|
}
|