mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 15:57:45 +00:00
WindowServer+LibGUI: Notify GUI clients about menu item enter/leave
We now send out MenuItemEntered and MenuItemLeft messages to the client when the user hovers/unhovers menu items. On the client side, these become GUI::ActionEvent, with one of two types: ActionEnter or ActionLeave. They are sent to the Application. This will allow GUI applications to react to these events.
This commit is contained in:
parent
f8c2beec7c
commit
ba7e1ca2fb
7 changed files with 91 additions and 19 deletions
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
* Copyright (c) 2020-2021, Andreas Kling <kling@serenityos.org>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
@ -26,6 +26,7 @@
|
||||||
|
|
||||||
#include <AK/StringBuilder.h>
|
#include <AK/StringBuilder.h>
|
||||||
#include <LibCore/MimeData.h>
|
#include <LibCore/MimeData.h>
|
||||||
|
#include <LibGUI/Action.h>
|
||||||
#include <LibGUI/Event.h>
|
#include <LibGUI/Event.h>
|
||||||
|
|
||||||
namespace GUI {
|
namespace GUI {
|
||||||
|
@ -69,4 +70,14 @@ String KeyEvent::to_string() const
|
||||||
return builder.to_string();
|
return builder.to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ActionEvent::ActionEvent(Type type, Action& action)
|
||||||
|
: Event(type)
|
||||||
|
, m_action(action)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionEvent::~ActionEvent()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include <Kernel/API/KeyCode.h>
|
#include <Kernel/API/KeyCode.h>
|
||||||
#include <LibCore/Event.h>
|
#include <LibCore/Event.h>
|
||||||
#include <LibGUI/FocusSource.h>
|
#include <LibGUI/FocusSource.h>
|
||||||
|
#include <LibGUI/Forward.h>
|
||||||
#include <LibGUI/WindowType.h>
|
#include <LibGUI/WindowType.h>
|
||||||
#include <LibGfx/Bitmap.h>
|
#include <LibGfx/Bitmap.h>
|
||||||
#include <LibGfx/Point.h>
|
#include <LibGfx/Point.h>
|
||||||
|
@ -72,6 +73,8 @@ public:
|
||||||
Drop,
|
Drop,
|
||||||
ThemeChange,
|
ThemeChange,
|
||||||
ScreenRectChange,
|
ScreenRectChange,
|
||||||
|
ActionEnter,
|
||||||
|
ActionLeave,
|
||||||
|
|
||||||
__Begin_WM_Events,
|
__Begin_WM_Events,
|
||||||
WM_WindowRemoved,
|
WM_WindowRemoved,
|
||||||
|
@ -428,4 +431,16 @@ private:
|
||||||
FocusSource m_source { FocusSource::Programmatic };
|
FocusSource m_source { FocusSource::Programmatic };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ActionEvent final : public Event {
|
||||||
|
public:
|
||||||
|
ActionEvent(Type, Action&);
|
||||||
|
~ActionEvent();
|
||||||
|
|
||||||
|
Action const& action() const { return *m_action; }
|
||||||
|
Action& action() { return *m_action; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
NonnullRefPtr<Action> m_action;
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -273,6 +273,38 @@ void WindowServerConnection::handle(const Messages::WindowClient::MenuItemActiva
|
||||||
action->activate(menu);
|
action->activate(menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WindowServerConnection::handle(Messages::WindowClient::MenuItemEntered const& message)
|
||||||
|
{
|
||||||
|
auto* menu = Menu::from_menu_id(message.menu_id());
|
||||||
|
if (!menu) {
|
||||||
|
dbgln("WindowServerConnection received MenuItemEntered for invalid menu ID {}", message.menu_id());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto* action = menu->action_at(message.identifier());
|
||||||
|
if (!action)
|
||||||
|
return;
|
||||||
|
auto* app = Application::the();
|
||||||
|
if (!app)
|
||||||
|
return;
|
||||||
|
Core::EventLoop::current().post_event(*app, make<ActionEvent>(GUI::Event::ActionEnter, *action));
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowServerConnection::handle(Messages::WindowClient::MenuItemLeft const& message)
|
||||||
|
{
|
||||||
|
auto* menu = Menu::from_menu_id(message.menu_id());
|
||||||
|
if (!menu) {
|
||||||
|
dbgln("WindowServerConnection received MenuItemLeft for invalid menu ID {}", message.menu_id());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto* action = menu->action_at(message.identifier());
|
||||||
|
if (!action)
|
||||||
|
return;
|
||||||
|
auto* app = Application::the();
|
||||||
|
if (!app)
|
||||||
|
return;
|
||||||
|
Core::EventLoop::current().post_event(*app, make<ActionEvent>(GUI::Event::ActionLeave, *action));
|
||||||
|
}
|
||||||
|
|
||||||
void WindowServerConnection::handle(const Messages::WindowClient::ScreenRectChanged& message)
|
void WindowServerConnection::handle(const Messages::WindowClient::ScreenRectChanged& message)
|
||||||
{
|
{
|
||||||
Desktop::the().did_receive_screen_rect({}, message.rect());
|
Desktop::the().did_receive_screen_rect({}, message.rect());
|
||||||
|
|
|
@ -64,6 +64,8 @@ private:
|
||||||
virtual void handle(const Messages::WindowClient::WindowCloseRequest&) override;
|
virtual void handle(const Messages::WindowClient::WindowCloseRequest&) override;
|
||||||
virtual void handle(const Messages::WindowClient::WindowResized&) override;
|
virtual void handle(const Messages::WindowClient::WindowResized&) override;
|
||||||
virtual void handle(const Messages::WindowClient::MenuItemActivated&) override;
|
virtual void handle(const Messages::WindowClient::MenuItemActivated&) override;
|
||||||
|
virtual void handle(const Messages::WindowClient::MenuItemEntered&) override;
|
||||||
|
virtual void handle(const Messages::WindowClient::MenuItemLeft&) override;
|
||||||
virtual void handle(const Messages::WindowClient::MenuVisibilityDidChange&) override;
|
virtual void handle(const Messages::WindowClient::MenuVisibilityDidChange&) override;
|
||||||
virtual void handle(const Messages::WindowClient::ScreenRectChanged&) override;
|
virtual void handle(const Messages::WindowClient::ScreenRectChanged&) override;
|
||||||
virtual void handle(const Messages::WindowClient::AsyncSetWallpaperFinished&) override;
|
virtual void handle(const Messages::WindowClient::AsyncSetWallpaperFinished&) override;
|
||||||
|
|
|
@ -300,15 +300,16 @@ MenuItem* Menu::hovered_item() const
|
||||||
|
|
||||||
void Menu::update_for_new_hovered_item(bool make_input)
|
void Menu::update_for_new_hovered_item(bool make_input)
|
||||||
{
|
{
|
||||||
auto* hovered_item = this->hovered_item();
|
if (auto* hovered_item = this->hovered_item()) {
|
||||||
if (hovered_item && hovered_item->is_submenu()) {
|
if (hovered_item->is_submenu()) {
|
||||||
VERIFY(menu_window());
|
VERIFY(menu_window());
|
||||||
MenuManager::the().close_everyone_not_in_lineage(*hovered_item->submenu());
|
MenuManager::the().close_everyone_not_in_lineage(*hovered_item->submenu());
|
||||||
hovered_item->submenu()->do_popup(hovered_item->rect().top_right().translated(menu_window()->rect().location()), make_input, true);
|
hovered_item->submenu()->do_popup(hovered_item->rect().top_right().translated(menu_window()->rect().location()), make_input, true);
|
||||||
} else {
|
} else {
|
||||||
MenuManager::the().close_everyone_not_in_lineage(*this);
|
MenuManager::the().close_everyone_not_in_lineage(*this);
|
||||||
ensure_menu_window();
|
ensure_menu_window();
|
||||||
set_visible(true);
|
set_visible(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
redraw();
|
redraw();
|
||||||
}
|
}
|
||||||
|
@ -461,10 +462,7 @@ void Menu::event(Core::Event& event)
|
||||||
|
|
||||||
void Menu::clear_hovered_item()
|
void Menu::clear_hovered_item()
|
||||||
{
|
{
|
||||||
if (!hovered_item())
|
set_hovered_index(-1);
|
||||||
return;
|
|
||||||
m_hovered_item_index = -1;
|
|
||||||
redraw();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Menu::start_activation_animation(MenuItem& item)
|
void Menu::start_activation_animation(MenuItem& item)
|
||||||
|
@ -650,4 +648,20 @@ const Vector<size_t>* Menu::items_with_alt_shortcut(u32 alt_shortcut) const
|
||||||
return &it->value;
|
return &it->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Menu::set_hovered_index(int index, bool make_input)
|
||||||
|
{
|
||||||
|
if (m_hovered_item_index == index)
|
||||||
|
return;
|
||||||
|
if (auto* old_hovered_item = hovered_item()) {
|
||||||
|
if (client())
|
||||||
|
client()->post_message(Messages::WindowClient::MenuItemLeft(m_menu_id, old_hovered_item->identifier()));
|
||||||
|
}
|
||||||
|
m_hovered_item_index = index;
|
||||||
|
update_for_new_hovered_item(make_input);
|
||||||
|
if (auto* new_hovered_item = hovered_item()) {
|
||||||
|
if (client())
|
||||||
|
client()->post_message(Messages::WindowClient::MenuItemEntered(m_menu_id, new_hovered_item->identifier()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -101,11 +101,7 @@ public:
|
||||||
|
|
||||||
MenuItem* hovered_item() const;
|
MenuItem* hovered_item() const;
|
||||||
|
|
||||||
void set_hovered_index(int index, bool make_input = false)
|
void set_hovered_index(int index, bool make_input = false);
|
||||||
{
|
|
||||||
m_hovered_item_index = index;
|
|
||||||
update_for_new_hovered_item(make_input);
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear_hovered_item();
|
void clear_hovered_item();
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,8 @@ endpoint WindowClient = 4
|
||||||
WindowResized(i32 window_id, Gfx::IntRect new_rect) =|
|
WindowResized(i32 window_id, Gfx::IntRect new_rect) =|
|
||||||
|
|
||||||
MenuItemActivated(i32 menu_id, i32 identifier) =|
|
MenuItemActivated(i32 menu_id, i32 identifier) =|
|
||||||
|
MenuItemEntered(i32 menu_id, u32 identifier) =|
|
||||||
|
MenuItemLeft(i32 menu_id, u32 identifier) =|
|
||||||
MenuVisibilityDidChange(i32 menu_id, bool visible) =|
|
MenuVisibilityDidChange(i32 menu_id, bool visible) =|
|
||||||
|
|
||||||
ScreenRectChanged(Gfx::IntRect rect) =|
|
ScreenRectChanged(Gfx::IntRect rect) =|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue