mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 12:47:45 +00:00
Services: Move to Userland/Services/
This commit is contained in:
parent
4055b03291
commit
c7ac7e6eaf
170 changed files with 4 additions and 4 deletions
9
Userland/Services/Taskbar/CMakeLists.txt
Normal file
9
Userland/Services/Taskbar/CMakeLists.txt
Normal file
|
@ -0,0 +1,9 @@
|
|||
set(SOURCES
|
||||
main.cpp
|
||||
TaskbarButton.cpp
|
||||
TaskbarWindow.cpp
|
||||
WindowList.cpp
|
||||
)
|
||||
|
||||
serenity_bin(Taskbar)
|
||||
target_link_libraries(Taskbar LibGUI LibDesktop)
|
162
Userland/Services/Taskbar/TaskbarButton.cpp
Normal file
162
Userland/Services/Taskbar/TaskbarButton.cpp
Normal file
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "TaskbarButton.h"
|
||||
#include "WindowList.h"
|
||||
#include <LibGUI/Action.h>
|
||||
#include <LibGUI/Painter.h>
|
||||
#include <LibGUI/WindowServerConnection.h>
|
||||
#include <LibGfx/Font.h>
|
||||
#include <LibGfx/FontDatabase.h>
|
||||
#include <LibGfx/Palette.h>
|
||||
#include <LibGfx/StylePainter.h>
|
||||
|
||||
TaskbarButton::TaskbarButton(const WindowIdentifier& identifier)
|
||||
: m_identifier(identifier)
|
||||
{
|
||||
}
|
||||
|
||||
TaskbarButton::~TaskbarButton()
|
||||
{
|
||||
}
|
||||
|
||||
void TaskbarButton::context_menu_event(GUI::ContextMenuEvent&)
|
||||
{
|
||||
GUI::WindowServerConnection::the().post_message(Messages::WindowServer::WM_PopupWindowMenu(m_identifier.client_id(), m_identifier.window_id(), screen_relative_rect().location()));
|
||||
}
|
||||
|
||||
void TaskbarButton::update_taskbar_rect()
|
||||
{
|
||||
GUI::WindowServerConnection::the().post_message(
|
||||
Messages::WindowServer::WM_SetWindowTaskbarRect(
|
||||
m_identifier.client_id(),
|
||||
m_identifier.window_id(),
|
||||
screen_relative_rect()));
|
||||
}
|
||||
|
||||
void TaskbarButton::clear_taskbar_rect()
|
||||
{
|
||||
GUI::WindowServerConnection::the().post_message(
|
||||
Messages::WindowServer::WM_SetWindowTaskbarRect(
|
||||
m_identifier.client_id(),
|
||||
m_identifier.window_id(),
|
||||
{}));
|
||||
}
|
||||
|
||||
void TaskbarButton::resize_event(GUI::ResizeEvent& event)
|
||||
{
|
||||
update_taskbar_rect();
|
||||
return GUI::Button::resize_event(event);
|
||||
}
|
||||
|
||||
static void paint_custom_progress_bar(GUI::Painter& painter, const Gfx::IntRect& rect, const Gfx::IntRect& text_rect, const Palette& palette, int min, int max, int value, const StringView& text, const Gfx::Font& font, Gfx::TextAlignment text_alignment)
|
||||
{
|
||||
float range_size = max - min;
|
||||
float progress = (value - min) / range_size;
|
||||
float progress_width = progress * rect.width();
|
||||
|
||||
Gfx::IntRect progress_rect { rect.x(), rect.y(), (int)progress_width, rect.height() };
|
||||
|
||||
{
|
||||
Gfx::PainterStateSaver saver(painter);
|
||||
painter.add_clip_rect(progress_rect);
|
||||
|
||||
Color start_color = palette.active_window_border1();
|
||||
Color end_color = palette.active_window_border2();
|
||||
painter.fill_rect_with_gradient(rect, start_color, end_color);
|
||||
|
||||
if (!text.is_null()) {
|
||||
painter.draw_text(text_rect.translated(1, 1), text, font, text_alignment, palette.base_text(), Gfx::TextElision::Right);
|
||||
painter.draw_text(text_rect, text, font, text_alignment, palette.base_text().inverted(), Gfx::TextElision::Right);
|
||||
}
|
||||
}
|
||||
|
||||
Gfx::IntRect hole_rect { (int)progress_width, 0, (int)(rect.width() - progress_width), rect.height() };
|
||||
hole_rect.move_by(rect.location());
|
||||
hole_rect.set_right_without_resize(rect.right());
|
||||
Gfx::PainterStateSaver saver(painter);
|
||||
painter.add_clip_rect(hole_rect);
|
||||
if (!text.is_null())
|
||||
painter.draw_text(text_rect, text, font, text_alignment, palette.base_text(), Gfx::TextElision::Right);
|
||||
}
|
||||
|
||||
void TaskbarButton::paint_event(GUI::PaintEvent& event)
|
||||
{
|
||||
ASSERT(icon());
|
||||
auto& icon = *this->icon();
|
||||
auto& font = is_checked() ? Gfx::FontDatabase::default_bold_font() : this->font();
|
||||
auto& window = WindowList::the().ensure_window(m_identifier);
|
||||
|
||||
GUI::Painter painter(*this);
|
||||
painter.add_clip_rect(event.rect());
|
||||
|
||||
Gfx::StylePainter::paint_button(painter, rect(), palette(), button_style(), is_being_pressed(), is_hovered(), is_checked(), is_enabled());
|
||||
|
||||
if (text().is_empty())
|
||||
return;
|
||||
|
||||
bool has_progress = window.progress() >= 0 && window.progress() <= 100;
|
||||
|
||||
auto content_rect = rect().shrunken(8, 2);
|
||||
auto icon_location = content_rect.center().translated(-(icon.width() / 2), -(icon.height() / 2));
|
||||
if (!text().is_empty())
|
||||
icon_location.set_x(content_rect.x());
|
||||
|
||||
if (!text().is_empty()) {
|
||||
content_rect.move_by(icon.width() + 4, 0);
|
||||
content_rect.set_width(content_rect.width() - icon.width() - 4);
|
||||
}
|
||||
|
||||
Gfx::IntRect text_rect { 0, 0, font.width(text()), font.glyph_height() };
|
||||
if (text_rect.width() > content_rect.width())
|
||||
text_rect.set_width(content_rect.width());
|
||||
text_rect.align_within(content_rect, text_alignment());
|
||||
|
||||
if (is_being_pressed() || is_checked()) {
|
||||
text_rect.move_by(1, 1);
|
||||
icon_location.move_by(1, 1);
|
||||
}
|
||||
|
||||
if (has_progress) {
|
||||
auto adjusted_rect = rect().shrunken(4, 4);
|
||||
if (is_being_pressed() || is_checked()) {
|
||||
adjusted_rect.set_height(adjusted_rect.height() + 1);
|
||||
}
|
||||
paint_custom_progress_bar(painter, adjusted_rect, text_rect, palette(), 0, 100, window.progress(), text(), font, text_alignment());
|
||||
}
|
||||
|
||||
if (is_enabled()) {
|
||||
if (is_hovered())
|
||||
painter.blit_brightened(icon_location, icon, icon.rect());
|
||||
else
|
||||
painter.blit(icon_location, icon, icon.rect());
|
||||
} else {
|
||||
painter.blit_disabled(icon_location, icon, icon.rect(), palette());
|
||||
}
|
||||
|
||||
if (!has_progress)
|
||||
paint_text(painter, text_rect, font, text_alignment());
|
||||
}
|
48
Userland/Services/Taskbar/TaskbarButton.h
Normal file
48
Userland/Services/Taskbar/TaskbarButton.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "WindowIdentifier.h"
|
||||
#include <LibGUI/Button.h>
|
||||
|
||||
class TaskbarButton final : public GUI::Button {
|
||||
C_OBJECT(TaskbarButton)
|
||||
public:
|
||||
virtual ~TaskbarButton() override;
|
||||
|
||||
void update_taskbar_rect();
|
||||
void clear_taskbar_rect();
|
||||
|
||||
private:
|
||||
explicit TaskbarButton(const WindowIdentifier&);
|
||||
|
||||
virtual void context_menu_event(GUI::ContextMenuEvent&) override;
|
||||
virtual void resize_event(GUI::ResizeEvent&) override;
|
||||
virtual void paint_event(GUI::PaintEvent&) override;
|
||||
|
||||
WindowIdentifier m_identifier;
|
||||
};
|
314
Userland/Services/Taskbar/TaskbarWindow.cpp
Normal file
314
Userland/Services/Taskbar/TaskbarWindow.cpp
Normal file
|
@ -0,0 +1,314 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "TaskbarWindow.h"
|
||||
#include "TaskbarButton.h"
|
||||
#include <AK/SharedBuffer.h>
|
||||
#include <LibCore/ConfigFile.h>
|
||||
#include <LibCore/StandardPaths.h>
|
||||
#include <LibDesktop/AppFile.h>
|
||||
#include <LibGUI/BoxLayout.h>
|
||||
#include <LibGUI/Button.h>
|
||||
#include <LibGUI/Desktop.h>
|
||||
#include <LibGUI/Frame.h>
|
||||
#include <LibGUI/Icon.h>
|
||||
#include <LibGUI/Painter.h>
|
||||
#include <LibGUI/Window.h>
|
||||
#include <LibGUI/WindowServerConnection.h>
|
||||
#include <LibGfx/Palette.h>
|
||||
#include <serenity.h>
|
||||
#include <stdio.h>
|
||||
|
||||
//#define EVENT_DEBUG
|
||||
|
||||
class TaskbarWidget final : public GUI::Widget {
|
||||
C_OBJECT(TaskbarWidget);
|
||||
|
||||
public:
|
||||
virtual ~TaskbarWidget() override { }
|
||||
|
||||
private:
|
||||
TaskbarWidget() { }
|
||||
|
||||
virtual void paint_event(GUI::PaintEvent& event) override
|
||||
{
|
||||
GUI::Painter painter(*this);
|
||||
painter.add_clip_rect(event.rect());
|
||||
painter.fill_rect(rect(), palette().button());
|
||||
painter.draw_line({ 0, 1 }, { width() - 1, 1 }, palette().threed_highlight());
|
||||
}
|
||||
|
||||
virtual void did_layout() override
|
||||
{
|
||||
WindowList::the().for_each_window([&](auto& window) {
|
||||
if (auto* button = window.button())
|
||||
static_cast<TaskbarButton*>(button)->update_taskbar_rect();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
TaskbarWindow::TaskbarWindow()
|
||||
{
|
||||
set_window_type(GUI::WindowType::Taskbar);
|
||||
set_title("Taskbar");
|
||||
|
||||
on_screen_rect_change(GUI::Desktop::the().rect());
|
||||
|
||||
GUI::Desktop::the().on_rect_change = [this](const Gfx::IntRect& rect) { on_screen_rect_change(rect); };
|
||||
|
||||
auto& widget = set_main_widget<TaskbarWidget>();
|
||||
widget.set_layout<GUI::HorizontalBoxLayout>();
|
||||
widget.layout()->set_margins({ 3, 2, 3, 2 });
|
||||
widget.layout()->set_spacing(3);
|
||||
|
||||
m_default_icon = Gfx::Bitmap::load_from_file("/res/icons/16x16/window.png");
|
||||
|
||||
create_quick_launch_bar();
|
||||
}
|
||||
|
||||
TaskbarWindow::~TaskbarWindow()
|
||||
{
|
||||
}
|
||||
|
||||
void TaskbarWindow::create_quick_launch_bar()
|
||||
{
|
||||
auto& quick_launch_bar = main_widget()->add<GUI::Frame>();
|
||||
quick_launch_bar.set_layout<GUI::HorizontalBoxLayout>();
|
||||
quick_launch_bar.layout()->set_spacing(0);
|
||||
quick_launch_bar.layout()->set_margins({ 3, 0, 3, 0 });
|
||||
quick_launch_bar.set_frame_thickness(0);
|
||||
|
||||
int total_width = 6;
|
||||
bool first = true;
|
||||
|
||||
auto config = Core::ConfigFile::get_for_app("Taskbar");
|
||||
constexpr const char* quick_launch = "QuickLaunch";
|
||||
|
||||
// FIXME: Core::ConfigFile does not keep the order of the entries.
|
||||
for (auto& name : config->keys(quick_launch)) {
|
||||
auto af_name = config->read_entry(quick_launch, name);
|
||||
auto af_path = String::formatted("{}/{}", Desktop::AppFile::APP_FILES_DIRECTORY, af_name);
|
||||
auto af = Desktop::AppFile::open(af_path);
|
||||
if (!af->is_valid())
|
||||
continue;
|
||||
auto app_executable = af->executable();
|
||||
const int button_size = 24;
|
||||
auto& button = quick_launch_bar.add<GUI::Button>();
|
||||
button.set_fixed_size(button_size, button_size);
|
||||
button.set_button_style(Gfx::ButtonStyle::CoolBar);
|
||||
button.set_icon(af->icon().bitmap_for_size(16));
|
||||
button.set_tooltip(af->name());
|
||||
button.on_click = [app_executable](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);
|
||||
}
|
||||
execl(app_executable.characters(), app_executable.characters(), nullptr);
|
||||
perror("execl");
|
||||
ASSERT_NOT_REACHED();
|
||||
} else {
|
||||
if (disown(pid) < 0)
|
||||
perror("disown");
|
||||
}
|
||||
};
|
||||
|
||||
if (!first)
|
||||
total_width += quick_launch_bar.layout()->spacing();
|
||||
first = false;
|
||||
total_width += button_size;
|
||||
}
|
||||
|
||||
quick_launch_bar.set_fixed_size(total_width, 24);
|
||||
}
|
||||
|
||||
void TaskbarWindow::on_screen_rect_change(const Gfx::IntRect& rect)
|
||||
{
|
||||
Gfx::IntRect new_rect { rect.x(), rect.bottom() - taskbar_height() + 1, rect.width(), taskbar_height() };
|
||||
set_rect(new_rect);
|
||||
}
|
||||
|
||||
NonnullRefPtr<GUI::Button> TaskbarWindow::create_button(const WindowIdentifier& identifier)
|
||||
{
|
||||
auto& button = main_widget()->add<TaskbarButton>(identifier);
|
||||
button.set_min_size(20, 23);
|
||||
button.set_max_size(140, 23);
|
||||
button.set_text_alignment(Gfx::TextAlignment::CenterLeft);
|
||||
button.set_icon(*m_default_icon);
|
||||
return button;
|
||||
}
|
||||
|
||||
static bool should_include_window(GUI::WindowType window_type, bool is_frameless)
|
||||
{
|
||||
return window_type == GUI::WindowType::Normal && !is_frameless;
|
||||
}
|
||||
|
||||
void TaskbarWindow::add_window_button(::Window& window, const WindowIdentifier& identifier)
|
||||
{
|
||||
if (window.button())
|
||||
return;
|
||||
window.set_button(create_button(identifier));
|
||||
auto* button = window.button();
|
||||
button->on_click = [window = &window, identifier, button](auto) {
|
||||
// We need to look at the button's checked state here to figure
|
||||
// out if the application is active or not. That's because this
|
||||
// button's window may not actually be active when a modal window
|
||||
// is displayed, in which case window->is_active() would return
|
||||
// false because window is the modal window's owner (which is not
|
||||
// active)
|
||||
if (window->is_minimized() || !button->is_checked()) {
|
||||
GUI::WindowServerConnection::the().post_message(Messages::WindowServer::WM_SetActiveWindow(identifier.client_id(), identifier.window_id()));
|
||||
} else {
|
||||
GUI::WindowServerConnection::the().post_message(Messages::WindowServer::WM_SetWindowMinimized(identifier.client_id(), identifier.window_id(), true));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void TaskbarWindow::remove_window_button(::Window& window, bool was_removed)
|
||||
{
|
||||
auto* button = window.button();
|
||||
if (!button)
|
||||
return;
|
||||
if (!was_removed)
|
||||
static_cast<TaskbarButton*>(button)->clear_taskbar_rect();
|
||||
window.set_button(nullptr);
|
||||
button->remove_from_parent();
|
||||
}
|
||||
|
||||
void TaskbarWindow::update_window_button(::Window& window, bool show_as_active)
|
||||
{
|
||||
auto* button = window.button();
|
||||
if (!button)
|
||||
return;
|
||||
button->set_text(window.title());
|
||||
button->set_checked(show_as_active);
|
||||
}
|
||||
|
||||
::Window* TaskbarWindow::find_window_owner(::Window& window) const
|
||||
{
|
||||
if (!window.is_modal())
|
||||
return &window;
|
||||
|
||||
::Window* parent = nullptr;
|
||||
auto* current_window = &window;
|
||||
while (current_window) {
|
||||
parent = WindowList::the().find_parent(*current_window);
|
||||
if (!parent || !parent->is_modal())
|
||||
break;
|
||||
current_window = parent;
|
||||
}
|
||||
return parent;
|
||||
}
|
||||
|
||||
void TaskbarWindow::wm_event(GUI::WMEvent& event)
|
||||
{
|
||||
WindowIdentifier identifier { event.client_id(), event.window_id() };
|
||||
switch (event.type()) {
|
||||
case GUI::Event::WM_WindowRemoved: {
|
||||
#ifdef EVENT_DEBUG
|
||||
auto& removed_event = static_cast<GUI::WMWindowRemovedEvent&>(event);
|
||||
dbgln("WM_WindowRemoved: client_id={}, window_id={}",
|
||||
removed_event.client_id(),
|
||||
removed_event.window_id());
|
||||
#endif
|
||||
if (auto* window = WindowList::the().window(identifier))
|
||||
remove_window_button(*window, true);
|
||||
WindowList::the().remove_window(identifier);
|
||||
update();
|
||||
break;
|
||||
}
|
||||
case GUI::Event::WM_WindowRectChanged: {
|
||||
#ifdef EVENT_DEBUG
|
||||
auto& changed_event = static_cast<GUI::WMWindowRectChangedEvent&>(event);
|
||||
dbgln("WM_WindowRectChanged: client_id={}, window_id={}, rect={}",
|
||||
changed_event.client_id(),
|
||||
changed_event.window_id(),
|
||||
changed_event.rect());
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
case GUI::Event::WM_WindowIconBitmapChanged: {
|
||||
auto& changed_event = static_cast<GUI::WMWindowIconBitmapChangedEvent&>(event);
|
||||
#ifdef EVENT_DEBUG
|
||||
dbgln("WM_WindowIconBitmapChanged: client_id={}, window_id={}, icon_buffer_id={}",
|
||||
changed_event.client_id(),
|
||||
changed_event.window_id(),
|
||||
changed_event.icon_buffer_id());
|
||||
#endif
|
||||
if (auto* window = WindowList::the().window(identifier)) {
|
||||
auto buffer = SharedBuffer::create_from_shbuf_id(changed_event.icon_buffer_id());
|
||||
ASSERT(buffer);
|
||||
if (window->button())
|
||||
window->button()->set_icon(Gfx::Bitmap::create_with_shared_buffer(Gfx::BitmapFormat::RGBA32, *buffer, changed_event.icon_size()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case GUI::Event::WM_WindowStateChanged: {
|
||||
auto& changed_event = static_cast<GUI::WMWindowStateChangedEvent&>(event);
|
||||
#ifdef EVENT_DEBUG
|
||||
dbgln("WM_WindowStateChanged: client_id={}, window_id={}, title={}, rect={}, is_active={}, is_minimized={}",
|
||||
changed_event.client_id(),
|
||||
changed_event.window_id(),
|
||||
changed_event.title(),
|
||||
changed_event.rect(),
|
||||
changed_event.is_active(),
|
||||
changed_event.is_minimized());
|
||||
#endif
|
||||
if (!should_include_window(changed_event.window_type(), changed_event.is_frameless()))
|
||||
break;
|
||||
auto& window = WindowList::the().ensure_window(identifier);
|
||||
window.set_parent_identifier({ changed_event.parent_client_id(), changed_event.parent_window_id() });
|
||||
if (!window.is_modal())
|
||||
add_window_button(window, identifier);
|
||||
else
|
||||
remove_window_button(window, false);
|
||||
window.set_title(changed_event.title());
|
||||
window.set_rect(changed_event.rect());
|
||||
window.set_modal(changed_event.is_modal());
|
||||
window.set_active(changed_event.is_active());
|
||||
window.set_minimized(changed_event.is_minimized());
|
||||
window.set_progress(changed_event.progress());
|
||||
|
||||
auto* window_owner = find_window_owner(window);
|
||||
if (window_owner == &window) {
|
||||
update_window_button(window, window.is_active());
|
||||
} else if (window_owner) {
|
||||
// check the window owner's button if the modal's window button
|
||||
// would have been checked
|
||||
ASSERT(window.is_modal());
|
||||
update_window_button(*window_owner, window.is_active());
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
53
Userland/Services/Taskbar/TaskbarWindow.h
Normal file
53
Userland/Services/Taskbar/TaskbarWindow.h
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "WindowList.h"
|
||||
#include <LibGUI/Widget.h>
|
||||
#include <LibGUI/Window.h>
|
||||
|
||||
class TaskbarWindow final : public GUI::Window {
|
||||
C_OBJECT(TaskbarWindow)
|
||||
public:
|
||||
TaskbarWindow();
|
||||
virtual ~TaskbarWindow() override;
|
||||
|
||||
int taskbar_height() const { return 28; }
|
||||
|
||||
private:
|
||||
void create_quick_launch_bar();
|
||||
void on_screen_rect_change(const Gfx::IntRect&);
|
||||
NonnullRefPtr<GUI::Button> create_button(const WindowIdentifier&);
|
||||
void add_window_button(::Window&, const WindowIdentifier&);
|
||||
void remove_window_button(::Window&, bool);
|
||||
void update_window_button(::Window&, bool);
|
||||
::Window* find_window_owner(::Window&) const;
|
||||
|
||||
virtual void wm_event(GUI::WMEvent&) override;
|
||||
|
||||
RefPtr<Gfx::Bitmap> m_default_icon;
|
||||
};
|
63
Userland/Services/Taskbar/WindowIdentifier.h
Normal file
63
Userland/Services/Taskbar/WindowIdentifier.h
Normal file
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Traits.h>
|
||||
|
||||
class WindowIdentifier {
|
||||
public:
|
||||
WindowIdentifier() = default;
|
||||
WindowIdentifier(int client_id, int window_id)
|
||||
: m_client_id(client_id)
|
||||
, m_window_id(window_id)
|
||||
{
|
||||
}
|
||||
|
||||
int client_id() const { return m_client_id; }
|
||||
int window_id() const { return m_window_id; }
|
||||
|
||||
bool operator==(const WindowIdentifier& other) const
|
||||
{
|
||||
return m_client_id == other.m_client_id && m_window_id == other.m_window_id;
|
||||
}
|
||||
|
||||
bool is_valid() const
|
||||
{
|
||||
return m_client_id != -1 && m_window_id != -1;
|
||||
}
|
||||
|
||||
private:
|
||||
int m_client_id { -1 };
|
||||
int m_window_id { -1 };
|
||||
};
|
||||
|
||||
namespace AK {
|
||||
template<>
|
||||
struct Traits<WindowIdentifier> : public GenericTraits<WindowIdentifier> {
|
||||
static unsigned hash(const WindowIdentifier& w) { return pair_int_hash(w.client_id(), w.window_id()); }
|
||||
};
|
||||
}
|
71
Userland/Services/Taskbar/WindowList.cpp
Normal file
71
Userland/Services/Taskbar/WindowList.cpp
Normal file
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "WindowList.h"
|
||||
|
||||
WindowList& WindowList::the()
|
||||
{
|
||||
static WindowList* s_the;
|
||||
if (!s_the)
|
||||
s_the = new WindowList;
|
||||
return *s_the;
|
||||
}
|
||||
|
||||
Window* WindowList::find_parent(const Window& window)
|
||||
{
|
||||
if (!window.parent_identifier().is_valid())
|
||||
return nullptr;
|
||||
for (auto& it : m_windows) {
|
||||
auto& w = *it.value;
|
||||
if (w.identifier() == window.parent_identifier())
|
||||
return &w;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Window* WindowList::window(const WindowIdentifier& identifier)
|
||||
{
|
||||
auto it = m_windows.find(identifier);
|
||||
if (it != m_windows.end())
|
||||
return it->value;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Window& WindowList::ensure_window(const WindowIdentifier& identifier)
|
||||
{
|
||||
auto it = m_windows.find(identifier);
|
||||
if (it != m_windows.end())
|
||||
return *it->value;
|
||||
auto window = make<Window>(identifier);
|
||||
auto& window_ref = *window;
|
||||
m_windows.set(identifier, move(window));
|
||||
return window_ref;
|
||||
}
|
||||
|
||||
void WindowList::remove_window(const WindowIdentifier& identifier)
|
||||
{
|
||||
m_windows.remove(identifier);
|
||||
}
|
115
Userland/Services/Taskbar/WindowList.h
Normal file
115
Userland/Services/Taskbar/WindowList.h
Normal file
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "WindowIdentifier.h"
|
||||
#include <AK/HashMap.h>
|
||||
#include <AK/String.h>
|
||||
#include <LibGUI/Button.h>
|
||||
#include <LibGfx/Rect.h>
|
||||
|
||||
class Window {
|
||||
public:
|
||||
explicit Window(const WindowIdentifier& identifier)
|
||||
: m_identifier(identifier)
|
||||
{
|
||||
}
|
||||
|
||||
~Window()
|
||||
{
|
||||
if (m_button)
|
||||
m_button->remove_from_parent();
|
||||
}
|
||||
|
||||
const WindowIdentifier& identifier() const { return m_identifier; }
|
||||
|
||||
void set_parent_identifier(const WindowIdentifier& parent_identifier) { m_parent_identifier = parent_identifier; }
|
||||
const WindowIdentifier& parent_identifier() const { return m_parent_identifier; }
|
||||
|
||||
String title() const { return m_title; }
|
||||
void set_title(const String& title) { m_title = title; }
|
||||
|
||||
Gfx::IntRect rect() const { return m_rect; }
|
||||
void set_rect(const Gfx::IntRect& rect) { m_rect = rect; }
|
||||
|
||||
GUI::Button* button() { return m_button; }
|
||||
void set_button(GUI::Button* button) { m_button = button; }
|
||||
|
||||
void set_active(bool active) { m_active = active; }
|
||||
bool is_active() const { return m_active; }
|
||||
|
||||
void set_minimized(bool minimized) { m_minimized = minimized; }
|
||||
bool is_minimized() const { return m_minimized; }
|
||||
|
||||
void set_modal(bool modal) { m_modal = modal; }
|
||||
bool is_modal() const { return m_modal; }
|
||||
|
||||
void set_progress(int progress)
|
||||
{
|
||||
if (m_progress == progress)
|
||||
return;
|
||||
m_progress = progress;
|
||||
if (m_button)
|
||||
m_button->update();
|
||||
}
|
||||
|
||||
int progress() const { return m_progress; }
|
||||
|
||||
const Gfx::Bitmap* icon() const { return m_icon.ptr(); }
|
||||
|
||||
private:
|
||||
WindowIdentifier m_identifier;
|
||||
WindowIdentifier m_parent_identifier;
|
||||
String m_title;
|
||||
Gfx::IntRect m_rect;
|
||||
RefPtr<GUI::Button> m_button;
|
||||
RefPtr<Gfx::Bitmap> m_icon;
|
||||
bool m_active { false };
|
||||
bool m_minimized { false };
|
||||
bool m_modal { false };
|
||||
int m_progress { -1 };
|
||||
};
|
||||
|
||||
class WindowList {
|
||||
public:
|
||||
static WindowList& the();
|
||||
|
||||
template<typename Callback>
|
||||
void for_each_window(Callback callback)
|
||||
{
|
||||
for (auto& it : m_windows)
|
||||
callback(*it.value);
|
||||
}
|
||||
|
||||
Window* find_parent(const Window&);
|
||||
Window* window(const WindowIdentifier&);
|
||||
Window& ensure_window(const WindowIdentifier&);
|
||||
void remove_window(const WindowIdentifier&);
|
||||
|
||||
private:
|
||||
HashMap<WindowIdentifier, NonnullOwnPtr<Window>> m_windows;
|
||||
};
|
57
Userland/Services/Taskbar/main.cpp
Normal file
57
Userland/Services/Taskbar/main.cpp
Normal file
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "TaskbarWindow.h"
|
||||
#include <LibCore/EventLoop.h>
|
||||
#include <LibGUI/Application.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
if (pledge("stdio shared_buffer accept proc exec rpath unix cpath fattr sigaction", nullptr) < 0) {
|
||||
perror("pledge");
|
||||
return 1;
|
||||
}
|
||||
|
||||
auto app = GUI::Application::construct(argc, argv);
|
||||
app->event_loop().register_signal(SIGCHLD, [](int) {
|
||||
// Wait all available children
|
||||
while (waitpid(-1, nullptr, WNOHANG) > 0)
|
||||
;
|
||||
});
|
||||
|
||||
if (pledge("stdio shared_buffer accept proc exec rpath", nullptr) < 0) {
|
||||
perror("pledge");
|
||||
return 1;
|
||||
}
|
||||
|
||||
TaskbarWindow window;
|
||||
window.show();
|
||||
|
||||
return app->exec();
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue