ladybird/Userland/Services/WindowServer/AppletManager.cpp
Lenny Maiorani 0b7baa7e5a Services: Use default constructors/destructors
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#cother-other-default-operation-rules

"The compiler is more likely to get the default semantics right and
you cannot implement these functions better than the compiler."
2022-03-24 20:09:26 -07:00

194 lines
5.1 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright (c) 2020, Hüseyin Aslıtürk <asliturk@hotmail.com>
* Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include "AppletManager.h"
#include <AK/QuickSort.h>
#include <LibCore/EventLoop.h>
#include <LibGfx/Painter.h>
#include <WindowServer/MenuManager.h>
namespace WindowServer {
static AppletManager* s_the;
Vector<String> order_vector;
AppletManager::AppletManager()
{
s_the = this;
auto wm_config = Core::ConfigFile::open("/etc/WindowServer.ini").release_value_but_fixme_should_propagate_errors();
auto order = wm_config->read_entry("Applet", "Order");
order_vector = order.split(',');
}
AppletManager& AppletManager::the()
{
VERIFY(s_the);
return *s_the;
}
void AppletManager::set_position(const Gfx::IntPoint& position)
{
m_window->move_to(position);
m_window->set_visible(true);
}
void AppletManager::set_hovered_applet(Window* applet)
{
if (m_hovered_applet == applet)
return;
if (m_hovered_applet)
Core::EventLoop::current().post_event(*m_hovered_applet, make<Event>(Event::WindowLeft));
m_hovered_applet = applet;
if (m_hovered_applet)
Core::EventLoop::current().post_event(*m_hovered_applet, make<Event>(Event::WindowEntered));
}
void AppletManager::event(Core::Event& event)
{
if (event.type() == Event::WindowLeft && m_hovered_applet) {
set_hovered_applet(nullptr);
return;
}
if (!is<MouseEvent>(event))
return;
auto& mouse_event = static_cast<MouseEvent&>(event);
for (auto& applet : m_applets) {
if (!applet)
continue;
if (!applet->rect_in_applet_area().contains(mouse_event.position()))
continue;
auto local_event = mouse_event.translated(-applet->rect_in_applet_area().location());
set_hovered_applet(applet);
Core::EventLoop::current().post_event(*applet, make<MouseEvent>(local_event));
return;
}
}
void AppletManager::add_applet(Window& applet)
{
m_applets.append(applet);
// Prune any dead weak pointers from the applet list.
m_applets.remove_all_matching([](auto& entry) {
return entry.is_null();
});
quick_sort(m_applets, [](auto& a, auto& b) {
auto index_a = order_vector.find_first_index(a->title());
auto index_b = order_vector.find_first_index(b->title());
return index_a.value_or(0) > index_b.value_or(0);
});
relayout();
}
void AppletManager::relayout()
{
constexpr int applet_spacing = 4;
constexpr int applet_window_height = 19;
int total_width = 0;
for (auto& existing_applet : m_applets) {
total_width += max(0, existing_applet->size().width()) + applet_spacing;
}
if (total_width > 0)
total_width -= applet_spacing;
auto right_edge_x = total_width;
for (auto& existing_applet : m_applets) {
auto applet_size = existing_applet->size();
Gfx::IntRect new_applet_rect(right_edge_x - applet_size.width(), 0, applet_size.width(), applet_size.height());
Gfx::IntRect dummy_container_rect(0, 0, 0, applet_window_height);
new_applet_rect.center_vertically_within(dummy_container_rect);
existing_applet->set_rect_in_applet_area(new_applet_rect);
right_edge_x = existing_applet->rect_in_applet_area().x() - applet_spacing;
}
if (!m_window) {
m_window = Window::construct(*this, WindowType::AppletArea);
m_window->set_visible(false);
}
Gfx::IntRect rect { m_window->position(), Gfx::IntSize { total_width, applet_window_height } };
if (m_window->rect() == rect)
return;
m_window->set_rect(rect);
repaint();
WindowManager::the().tell_wms_applet_area_size_changed(rect.size());
}
void AppletManager::repaint()
{
if (!m_window) {
return;
}
auto rect = Gfx::IntRect { { 0, 0 }, m_window->size() };
if (!rect.is_empty()) {
Gfx::Painter painter(*m_window->backing_store());
painter.fill_rect(rect, WindowManager::the().palette().button());
}
}
void AppletManager::did_change_theme()
{
repaint();
}
void AppletManager::remove_applet(Window& applet)
{
m_applets.remove_first_matching([&](auto& entry) {
return &applet == entry.ptr();
});
relayout();
}
void AppletManager::draw()
{
for (auto& applet : m_applets) {
if (!applet)
continue;
draw_applet(*applet);
}
}
void AppletManager::draw_applet(const Window& applet)
{
if (!applet.backing_store())
return;
Gfx::Painter painter(*m_window->backing_store());
Gfx::PainterStateSaver saver(painter);
painter.add_clip_rect(applet.rect_in_applet_area());
painter.fill_rect(applet.rect_in_applet_area(), WindowManager::the().palette().button());
painter.blit(applet.rect_in_applet_area().location(), *applet.backing_store(), applet.backing_store()->rect());
}
void AppletManager::invalidate_applet(const Window& applet, const Gfx::IntRect&)
{
draw_applet(applet);
draw();
// FIXME: Invalidate only the exact rect we've been given.
if (m_window)
m_window->invalidate();
}
}