mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 16:57:35 +00:00
WindowServer: Allow windows to be pinnable (always on top)
This patch adds the concept of a window being "Pinnable" (always drawn on top of other windows). This can be toggled through a new checkable action in the top left corner's window menu.
This commit is contained in:
parent
d5722eab36
commit
f6f14777ac
7 changed files with 87 additions and 0 deletions
BIN
Base/res/icons/16x16/window-pin.png
Normal file
BIN
Base/res/icons/16x16/window-pin.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 178 B |
|
@ -67,6 +67,13 @@ static Gfx::Bitmap& close_icon()
|
||||||
return *s_icon;
|
return *s_icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Gfx::Bitmap& pin_icon()
|
||||||
|
{
|
||||||
|
static Gfx::Bitmap* s_icon;
|
||||||
|
if (!s_icon)
|
||||||
|
s_icon = Gfx::Bitmap::load_from_file("/res/icons/16x16/window-pin.png").leak_ref();
|
||||||
|
return *s_icon;
|
||||||
|
}
|
||||||
Window::Window(Core::Object& parent, WindowType type)
|
Window::Window(Core::Object& parent, WindowType type)
|
||||||
: Core::Object(&parent)
|
: Core::Object(&parent)
|
||||||
, m_type(type)
|
, m_type(type)
|
||||||
|
@ -276,6 +283,9 @@ void Window::update_window_menu_items()
|
||||||
m_window_menu_maximize_item->set_enabled(m_resizable);
|
m_window_menu_maximize_item->set_enabled(m_resizable);
|
||||||
|
|
||||||
m_window_menu_move_item->set_enabled(m_minimized_state == WindowMinimizedState::None && !m_maximized && !m_fullscreen);
|
m_window_menu_move_item->set_enabled(m_minimized_state == WindowMinimizedState::None && !m_maximized && !m_fullscreen);
|
||||||
|
|
||||||
|
if (m_window_menu_pin_item)
|
||||||
|
m_window_menu_pin_item->set_text(m_pinned ? "Un-&Pin Window" : "&Pin Window");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window::set_minimized(bool minimized)
|
void Window::set_minimized(bool minimized)
|
||||||
|
@ -467,6 +477,16 @@ void Window::set_maximized(bool maximized, Optional<Gfx::IntPoint> fixed_point)
|
||||||
Core::EventLoop::current().post_event(*this, make<ResizeEvent>(m_rect));
|
Core::EventLoop::current().post_event(*this, make<ResizeEvent>(m_rect));
|
||||||
set_default_positioned(false);
|
set_default_positioned(false);
|
||||||
}
|
}
|
||||||
|
void Window::set_pinned(bool pinned)
|
||||||
|
{
|
||||||
|
if (m_pinned == pinned)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_pinned = pinned;
|
||||||
|
update_window_menu_items();
|
||||||
|
|
||||||
|
window_stack().move_pinned_windows_to_front();
|
||||||
|
}
|
||||||
void Window::set_vertically_maximized()
|
void Window::set_vertically_maximized()
|
||||||
{
|
{
|
||||||
if (m_maximized)
|
if (m_maximized)
|
||||||
|
@ -776,6 +796,16 @@ void Window::ensure_window_menu()
|
||||||
|
|
||||||
m_window_menu->add_item(make<MenuItem>(*m_window_menu, MenuItem::Type::Separator));
|
m_window_menu->add_item(make<MenuItem>(*m_window_menu, MenuItem::Type::Separator));
|
||||||
|
|
||||||
|
if (!m_modal) {
|
||||||
|
auto pin_item = make<MenuItem>(*m_window_menu, (unsigned)WindowMenuAction::TogglePinned, "&Pin Window");
|
||||||
|
m_window_menu_pin_item = pin_item.ptr();
|
||||||
|
m_window_menu_pin_item->set_icon(&pin_icon());
|
||||||
|
m_window_menu_pin_item->set_checkable(true);
|
||||||
|
m_window_menu->add_item(move(pin_item));
|
||||||
|
}
|
||||||
|
|
||||||
|
m_window_menu->add_item(make<MenuItem>(*m_window_menu, MenuItem::Type::Separator));
|
||||||
|
|
||||||
auto close_item = make<MenuItem>(*m_window_menu, (unsigned)WindowMenuAction::Close, "&Close");
|
auto close_item = make<MenuItem>(*m_window_menu, (unsigned)WindowMenuAction::Close, "&Close");
|
||||||
m_window_menu_close_item = close_item.ptr();
|
m_window_menu_close_item = close_item.ptr();
|
||||||
m_window_menu_close_item->set_icon(&close_icon());
|
m_window_menu_close_item->set_icon(&close_icon());
|
||||||
|
@ -818,6 +848,13 @@ void Window::handle_window_menu_action(WindowMenuAction action)
|
||||||
invalidate_last_rendered_screen_rects();
|
invalidate_last_rendered_screen_rects();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case WindowMenuAction::TogglePinned: {
|
||||||
|
auto& item = *m_window_menu->item_by_identifier((unsigned)action);
|
||||||
|
auto new_is_checked = !item.is_checked();
|
||||||
|
item.set_checked(new_is_checked);
|
||||||
|
WindowManager::the().set_pinned(*this, new_is_checked);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,7 @@ enum class WindowMenuAction {
|
||||||
ToggleMenubarVisibility,
|
ToggleMenubarVisibility,
|
||||||
Close,
|
Close,
|
||||||
Move,
|
Move,
|
||||||
|
TogglePinned,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class WindowMenuDefaultAction {
|
enum class WindowMenuDefaultAction {
|
||||||
|
@ -103,6 +104,9 @@ public:
|
||||||
bool is_maximized() const { return m_maximized; }
|
bool is_maximized() const { return m_maximized; }
|
||||||
void set_maximized(bool, Optional<Gfx::IntPoint> fixed_point = {});
|
void set_maximized(bool, Optional<Gfx::IntPoint> fixed_point = {});
|
||||||
|
|
||||||
|
bool is_pinned() const { return m_pinned; }
|
||||||
|
void set_pinned(bool);
|
||||||
|
|
||||||
void set_vertically_maximized();
|
void set_vertically_maximized();
|
||||||
|
|
||||||
bool is_fullscreen() const { return m_fullscreen; }
|
bool is_fullscreen() const { return m_fullscreen; }
|
||||||
|
@ -411,6 +415,7 @@ private:
|
||||||
bool m_invalidated_frame { true };
|
bool m_invalidated_frame { true };
|
||||||
bool m_hit_testing_enabled { true };
|
bool m_hit_testing_enabled { true };
|
||||||
bool m_modified { false };
|
bool m_modified { false };
|
||||||
|
bool m_pinned { false };
|
||||||
bool m_moving_to_another_stack { false };
|
bool m_moving_to_another_stack { false };
|
||||||
bool m_invalidate_last_render_rects { false };
|
bool m_invalidate_last_render_rects { false };
|
||||||
WindowTileType m_tiled { WindowTileType::None };
|
WindowTileType m_tiled { WindowTileType::None };
|
||||||
|
@ -439,6 +444,7 @@ private:
|
||||||
MenuItem* m_window_menu_maximize_item { nullptr };
|
MenuItem* m_window_menu_maximize_item { nullptr };
|
||||||
MenuItem* m_window_menu_move_item { nullptr };
|
MenuItem* m_window_menu_move_item { nullptr };
|
||||||
MenuItem* m_window_menu_close_item { nullptr };
|
MenuItem* m_window_menu_close_item { nullptr };
|
||||||
|
MenuItem* m_window_menu_pin_item { nullptr };
|
||||||
MenuItem* m_window_menu_menubar_visibility_item { nullptr };
|
MenuItem* m_window_menu_menubar_visibility_item { nullptr };
|
||||||
Optional<int> m_progress;
|
Optional<int> m_progress;
|
||||||
bool m_should_show_menubar { true };
|
bool m_should_show_menubar { true };
|
||||||
|
|
|
@ -2005,6 +2005,14 @@ void WindowManager::maximize_windows(Window& window, bool maximized)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WindowManager::set_pinned(Window& window, bool pinned)
|
||||||
|
{
|
||||||
|
for_each_window_in_modal_stack(window, [&](auto& w, bool) {
|
||||||
|
w.set_pinned(pinned);
|
||||||
|
return IterationDecision::Continue;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
Gfx::IntPoint WindowManager::get_recommended_window_position(Gfx::IntPoint const& desired)
|
Gfx::IntPoint WindowManager::get_recommended_window_position(Gfx::IntPoint const& desired)
|
||||||
{
|
{
|
||||||
// FIXME: Find a better source for the width and height to shift by.
|
// FIXME: Find a better source for the width and height to shift by.
|
||||||
|
|
|
@ -223,6 +223,7 @@ public:
|
||||||
void minimize_windows(Window&, bool);
|
void minimize_windows(Window&, bool);
|
||||||
void hide_windows(Window&, bool);
|
void hide_windows(Window&, bool);
|
||||||
void maximize_windows(Window&, bool);
|
void maximize_windows(Window&, bool);
|
||||||
|
void set_pinned(Window&, bool);
|
||||||
|
|
||||||
template<typename Function>
|
template<typename Function>
|
||||||
IterationDecision for_each_window_in_modal_stack(Window& window, Function f)
|
IterationDecision for_each_window_in_modal_stack(Window& window, Function f)
|
||||||
|
|
|
@ -24,6 +24,8 @@ void WindowStack::add(Window& window)
|
||||||
VERIFY(!window.is_on_any_window_stack({}));
|
VERIFY(!window.is_on_any_window_stack({}));
|
||||||
m_windows.append(window);
|
m_windows.append(window);
|
||||||
window.set_window_stack({}, this);
|
window.set_window_stack({}, this);
|
||||||
|
|
||||||
|
move_pinned_windows_to_front();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowStack::add_to_back(Window& window)
|
void WindowStack::add_to_back(Window& window)
|
||||||
|
@ -50,13 +52,45 @@ void WindowStack::move_to_front(Window& window)
|
||||||
{
|
{
|
||||||
if (m_windows.last() != &window)
|
if (m_windows.last() != &window)
|
||||||
window.invalidate();
|
window.invalidate();
|
||||||
|
|
||||||
m_windows.remove(window);
|
m_windows.remove(window);
|
||||||
m_windows.append(window);
|
m_windows.append(window);
|
||||||
|
|
||||||
|
move_pinned_windows_to_front();
|
||||||
|
|
||||||
|
if (window.is_pinned()) {
|
||||||
|
m_windows.remove(window);
|
||||||
|
m_windows.append(window);
|
||||||
|
window.invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowStack::move_pinned_windows_to_front()
|
||||||
|
{
|
||||||
|
Window::List pinned_list;
|
||||||
|
for (auto iterator = m_windows.begin(); iterator != m_windows.end(); ++iterator) {
|
||||||
|
auto& window = *iterator;
|
||||||
|
if (window.is_pinned()) {
|
||||||
|
m_windows.remove(window);
|
||||||
|
pinned_list.append(window);
|
||||||
|
iterator = m_windows.begin();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!pinned_list.is_empty()) {
|
||||||
|
auto& window = *pinned_list.begin();
|
||||||
|
pinned_list.remove(window);
|
||||||
|
m_windows.append(window);
|
||||||
|
window.invalidate();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowStack::move_all_windows(WindowStack& new_window_stack, Vector<Window*, 32>& windows_moved, MoveAllWindowsTo move_to)
|
void WindowStack::move_all_windows(WindowStack& new_window_stack, Vector<Window*, 32>& windows_moved, MoveAllWindowsTo move_to)
|
||||||
{
|
{
|
||||||
VERIFY(this != &new_window_stack);
|
VERIFY(this != &new_window_stack);
|
||||||
|
|
||||||
|
move_pinned_windows_to_front();
|
||||||
|
|
||||||
if (move_to == MoveAllWindowsTo::Front) {
|
if (move_to == MoveAllWindowsTo::Front) {
|
||||||
while (auto* window = m_windows.take_first()) {
|
while (auto* window = m_windows.take_first()) {
|
||||||
window->set_window_stack({}, nullptr);
|
window->set_window_stack({}, nullptr);
|
||||||
|
|
|
@ -22,6 +22,7 @@ public:
|
||||||
void add_to_back(Window&);
|
void add_to_back(Window&);
|
||||||
void remove(Window&);
|
void remove(Window&);
|
||||||
void move_to_front(Window&);
|
void move_to_front(Window&);
|
||||||
|
void move_pinned_windows_to_front();
|
||||||
|
|
||||||
enum class MoveAllWindowsTo {
|
enum class MoveAllWindowsTo {
|
||||||
Front,
|
Front,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue