1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 08:47:34 +00:00

LibGUI: Support using a bitmap as override cursor

This commit is contained in:
Marco Cutecchia 2021-10-15 22:24:41 +02:00 committed by Andreas Kling
parent 4bfe060336
commit 116bb4888f
4 changed files with 46 additions and 26 deletions

View file

@ -1036,14 +1036,23 @@ Gfx::IntRect Widget::children_clip_rect() const
return rect(); return rect();
} }
void Widget::set_override_cursor(Gfx::StandardCursor cursor) void Widget::set_override_cursor(AK::Variant<Gfx::StandardCursor, NonnullRefPtr<Gfx::Bitmap>> cursor)
{ {
if (m_override_cursor == cursor) auto const& are_cursors_the_same = [](AK::Variant<Gfx::StandardCursor, NonnullRefPtr<Gfx::Bitmap>> const& a, AK::Variant<Gfx::StandardCursor, NonnullRefPtr<Gfx::Bitmap>> const& b) {
if (a.has<Gfx::StandardCursor>() != b.has<Gfx::StandardCursor>())
return false;
if (a.has<Gfx::StandardCursor>())
return a.get<Gfx::StandardCursor>() == b.get<Gfx::StandardCursor>();
return a.get<NonnullRefPtr<Gfx::Bitmap>>().ptr() == b.get<NonnullRefPtr<Gfx::Bitmap>>().ptr();
};
if (are_cursors_the_same(m_override_cursor, cursor))
return; return;
m_override_cursor = cursor; m_override_cursor = move(cursor);
if (auto* window = this->window()) if (auto* window = this->window()) {
window->update_cursor({}); window->update_cursor({});
}
} }
bool Widget::load_from_gml(const StringView& gml_string) bool Widget::load_from_gml(const StringView& gml_string)

View file

@ -9,6 +9,7 @@
#include <AK/EnumBits.h> #include <AK/EnumBits.h>
#include <AK/JsonObject.h> #include <AK/JsonObject.h>
#include <AK/String.h> #include <AK/String.h>
#include <AK/Variant.h>
#include <LibCore/Object.h> #include <LibCore/Object.h>
#include <LibGUI/Event.h> #include <LibGUI/Event.h>
#include <LibGUI/FocusPolicy.h> #include <LibGUI/FocusPolicy.h>
@ -272,8 +273,8 @@ public:
virtual Gfx::IntRect children_clip_rect() const; virtual Gfx::IntRect children_clip_rect() const;
Gfx::StandardCursor override_cursor() const { return m_override_cursor; } AK::Variant<Gfx::StandardCursor, NonnullRefPtr<Gfx::Bitmap>> override_cursor() const { return m_override_cursor; }
void set_override_cursor(Gfx::StandardCursor); void set_override_cursor(AK::Variant<Gfx::StandardCursor, NonnullRefPtr<Gfx::Bitmap>>);
bool load_from_gml(const StringView&); bool load_from_gml(const StringView&);
bool load_from_gml(const StringView&, RefPtr<Core::Object> (*unregistered_child_handler)(const String&)); bool load_from_gml(const StringView&, RefPtr<Core::Object> (*unregistered_child_handler)(const String&));
@ -373,7 +374,7 @@ private:
WeakPtr<Widget> m_focus_proxy; WeakPtr<Widget> m_focus_proxy;
FocusPolicy m_focus_policy { FocusPolicy::NoFocus }; FocusPolicy m_focus_policy { FocusPolicy::NoFocus };
Gfx::StandardCursor m_override_cursor { Gfx::StandardCursor::None }; AK::Variant<Gfx::StandardCursor, NonnullRefPtr<Gfx::Bitmap>> m_override_cursor { Gfx::StandardCursor::None };
}; };
inline Widget* Widget::parent_widget() inline Widget* Widget::parent_widget()

View file

@ -317,21 +317,28 @@ void Window::make_window_manager(unsigned event_mask)
GUI::WindowManagerServerConnection::the().async_set_manager_window(m_window_id); GUI::WindowManagerServerConnection::the().async_set_manager_window(m_window_id);
} }
bool Window::are_cursors_the_same(AK::Variant<Gfx::StandardCursor, NonnullRefPtr<Gfx::Bitmap>> const& left, AK::Variant<Gfx::StandardCursor, NonnullRefPtr<Gfx::Bitmap>> const& right) const
{
if (left.has<Gfx::StandardCursor>() != right.has<Gfx::StandardCursor>())
return false;
if (left.has<Gfx::StandardCursor>())
return left.get<Gfx::StandardCursor>() == right.get<Gfx::StandardCursor>();
return left.get<NonnullRefPtr<Gfx::Bitmap>>().ptr() == right.get<NonnullRefPtr<Gfx::Bitmap>>().ptr();
}
void Window::set_cursor(Gfx::StandardCursor cursor) void Window::set_cursor(Gfx::StandardCursor cursor)
{ {
if (m_cursor == cursor) if (are_cursors_the_same(m_cursor, cursor))
return; return;
m_cursor = cursor; m_cursor = cursor;
m_custom_cursor = nullptr;
update_cursor(); update_cursor();
} }
void Window::set_cursor(const Gfx::Bitmap& cursor) void Window::set_cursor(NonnullRefPtr<Gfx::Bitmap> cursor)
{ {
if (m_custom_cursor == &cursor) if (are_cursors_the_same(m_cursor, cursor))
return; return;
m_cursor = Gfx::StandardCursor::None; m_cursor = cursor;
m_custom_cursor = &cursor;
update_cursor(); update_cursor();
} }
@ -1135,21 +1142,22 @@ void Window::set_progress(Optional<int> progress)
void Window::update_cursor() void Window::update_cursor()
{ {
Gfx::StandardCursor new_cursor; auto new_cursor = m_cursor;
if (m_hovered_widget && m_hovered_widget->override_cursor() != Gfx::StandardCursor::None) if (m_hovered_widget) {
new_cursor = m_hovered_widget->override_cursor(); auto override_cursor = m_hovered_widget->override_cursor();
else if (override_cursor.has<NonnullRefPtr<Gfx::Bitmap>>() || override_cursor.get<Gfx::StandardCursor>() != Gfx::StandardCursor::None)
new_cursor = m_cursor; new_cursor = move(override_cursor);
}
if (!m_custom_cursor && m_effective_cursor == new_cursor) if (are_cursors_the_same(m_effective_cursor, new_cursor))
return; return;
m_effective_cursor = new_cursor; m_effective_cursor = new_cursor;
if (m_custom_cursor) if (new_cursor.has<NonnullRefPtr<Gfx::Bitmap>>())
WindowServerConnection::the().async_set_window_custom_cursor(m_window_id, m_custom_cursor->to_shareable_bitmap()); WindowServerConnection::the().async_set_window_custom_cursor(m_window_id, new_cursor.get<NonnullRefPtr<Gfx::Bitmap>>()->to_shareable_bitmap());
else else
WindowServerConnection::the().async_set_window_cursor(m_window_id, (u32)m_effective_cursor); WindowServerConnection::the().async_set_window_cursor(m_window_id, (u32)new_cursor.get<Gfx::StandardCursor>());
} }
void Window::focus_a_widget_if_possible(FocusSource source) void Window::focus_a_widget_if_possible(FocusSource source)

View file

@ -9,6 +9,7 @@
#include <AK/Function.h> #include <AK/Function.h>
#include <AK/OwnPtr.h> #include <AK/OwnPtr.h>
#include <AK/String.h> #include <AK/String.h>
#include <AK/Variant.h>
#include <AK/WeakPtr.h> #include <AK/WeakPtr.h>
#include <LibCore/Object.h> #include <LibCore/Object.h>
#include <LibGUI/FocusSource.h> #include <LibGUI/FocusSource.h>
@ -169,7 +170,7 @@ public:
void set_resize_aspect_ratio(const Optional<Gfx::IntSize>& ratio); void set_resize_aspect_ratio(const Optional<Gfx::IntSize>& ratio);
void set_cursor(Gfx::StandardCursor); void set_cursor(Gfx::StandardCursor);
void set_cursor(const Gfx::Bitmap&); void set_cursor(NonnullRefPtr<Gfx::Bitmap>);
void set_icon(const Gfx::Bitmap*); void set_icon(const Gfx::Bitmap*);
void apply_icon(); void apply_icon();
@ -240,6 +241,8 @@ private:
void flip(const Vector<Gfx::IntRect, 32>& dirty_rects); void flip(const Vector<Gfx::IntRect, 32>& dirty_rects);
void force_update(); void force_update();
bool are_cursors_the_same(AK::Variant<Gfx::StandardCursor, NonnullRefPtr<Gfx::Bitmap>> const&, AK::Variant<Gfx::StandardCursor, NonnullRefPtr<Gfx::Bitmap>> const&) const;
WeakPtr<Widget> m_previously_focused_widget; WeakPtr<Widget> m_previously_focused_widget;
OwnPtr<WindowBackingStore> m_front_store; OwnPtr<WindowBackingStore> m_front_store;
@ -248,7 +251,6 @@ private:
NonnullRefPtr<Menubar> m_menubar; NonnullRefPtr<Menubar> m_menubar;
RefPtr<Gfx::Bitmap> m_icon; RefPtr<Gfx::Bitmap> m_icon;
RefPtr<Gfx::Bitmap> m_custom_cursor;
int m_window_id { 0 }; int m_window_id { 0 };
float m_opacity_when_windowless { 1.0f }; float m_opacity_when_windowless { 1.0f };
float m_alpha_hit_threshold { 0.0f }; float m_alpha_hit_threshold { 0.0f };
@ -265,8 +267,8 @@ private:
Gfx::IntSize m_base_size; Gfx::IntSize m_base_size;
Color m_background_color { Color::WarmGray }; Color m_background_color { Color::WarmGray };
WindowType m_window_type { WindowType::Normal }; WindowType m_window_type { WindowType::Normal };
Gfx::StandardCursor m_cursor { Gfx::StandardCursor::None }; AK::Variant<Gfx::StandardCursor, NonnullRefPtr<Gfx::Bitmap>> m_cursor { Gfx::StandardCursor::None };
Gfx::StandardCursor m_effective_cursor { Gfx::StandardCursor::None }; AK::Variant<Gfx::StandardCursor, NonnullRefPtr<Gfx::Bitmap>> m_effective_cursor { Gfx::StandardCursor::None };
bool m_is_active_input { false }; bool m_is_active_input { false };
bool m_has_alpha_channel { false }; bool m_has_alpha_channel { false };
bool m_double_buffering_enabled { true }; bool m_double_buffering_enabled { true };