mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 13:18:13 +00:00
WindowServer+LibGUI: Pass the set of mime types being dragged to client
Previously the client would only learn the mime type of what was being dropped on it once the drop occurred. To enable more sophisticated filtering of drag & drop, we now pass along the list of mime types being dragged to the client with each MouseMove event. (Note that MouseMove is translated to the various Drag* events in LibGUI on the client side.)
This commit is contained in:
parent
3b94af2c07
commit
67b91d51a7
15 changed files with 32 additions and 26 deletions
|
@ -261,7 +261,7 @@ void Application::set_pending_drop_widget(Widget* widget)
|
||||||
m_pending_drop_widget->update();
|
m_pending_drop_widget->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::set_drag_hovered_widget_impl(Widget* widget, const Gfx::IntPoint& position, const String& mime_type)
|
void Application::set_drag_hovered_widget_impl(Widget* widget, const Gfx::IntPoint& position, Vector<String> mime_types)
|
||||||
{
|
{
|
||||||
if (widget == m_drag_hovered_widget)
|
if (widget == m_drag_hovered_widget)
|
||||||
return;
|
return;
|
||||||
|
@ -275,7 +275,7 @@ void Application::set_drag_hovered_widget_impl(Widget* widget, const Gfx::IntPoi
|
||||||
m_drag_hovered_widget = widget;
|
m_drag_hovered_widget = widget;
|
||||||
|
|
||||||
if (m_drag_hovered_widget) {
|
if (m_drag_hovered_widget) {
|
||||||
DragEvent enter_event(Event::DragEnter, position, mime_type);
|
DragEvent enter_event(Event::DragEnter, position, move(mime_types));
|
||||||
enter_event.ignore();
|
enter_event.ignore();
|
||||||
m_drag_hovered_widget->dispatch_event(enter_event, m_drag_hovered_widget->window());
|
m_drag_hovered_widget->dispatch_event(enter_event, m_drag_hovered_widget->window());
|
||||||
if (enter_event.is_accepted())
|
if (enter_event.is_accepted())
|
||||||
|
|
|
@ -90,9 +90,9 @@ public:
|
||||||
Widget* pending_drop_widget() { return m_pending_drop_widget.ptr(); }
|
Widget* pending_drop_widget() { return m_pending_drop_widget.ptr(); }
|
||||||
const Widget* pending_drop_widget() const { return m_pending_drop_widget.ptr(); }
|
const Widget* pending_drop_widget() const { return m_pending_drop_widget.ptr(); }
|
||||||
|
|
||||||
void set_drag_hovered_widget(Badge<Window>, Widget* widget, const Gfx::IntPoint& position = {}, const String& mime_type = {})
|
void set_drag_hovered_widget(Badge<Window>, Widget* widget, const Gfx::IntPoint& position = {}, Vector<String> mime_types = {})
|
||||||
{
|
{
|
||||||
set_drag_hovered_widget_impl(widget, position, mime_type);
|
set_drag_hovered_widget_impl(widget, position, move(mime_types));
|
||||||
}
|
}
|
||||||
void notify_drag_cancelled(Badge<WindowServerConnection>);
|
void notify_drag_cancelled(Badge<WindowServerConnection>);
|
||||||
|
|
||||||
|
@ -102,7 +102,7 @@ private:
|
||||||
void tooltip_show_timer_did_fire();
|
void tooltip_show_timer_did_fire();
|
||||||
void tooltip_hide_timer_did_fire();
|
void tooltip_hide_timer_did_fire();
|
||||||
|
|
||||||
void set_drag_hovered_widget_impl(Widget*, const Gfx::IntPoint& = {}, const String& = {});
|
void set_drag_hovered_widget_impl(Widget*, const Gfx::IntPoint& = {}, Vector<String> = {});
|
||||||
void set_pending_drop_widget(Widget*);
|
void set_pending_drop_widget(Widget*);
|
||||||
|
|
||||||
OwnPtr<Core::EventLoop> m_event_loop;
|
OwnPtr<Core::EventLoop> m_event_loop;
|
||||||
|
|
|
@ -347,19 +347,19 @@ private:
|
||||||
|
|
||||||
class DragEvent final : public Event {
|
class DragEvent final : public Event {
|
||||||
public:
|
public:
|
||||||
DragEvent(Type type, const Gfx::IntPoint& position, const String& data_type)
|
DragEvent(Type type, const Gfx::IntPoint& position, Vector<String> mime_types)
|
||||||
: Event(type)
|
: Event(type)
|
||||||
, m_position(position)
|
, m_position(position)
|
||||||
, m_data_type(data_type)
|
, m_mime_types(move(mime_types))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
const Gfx::IntPoint& position() const { return m_position; }
|
const Gfx::IntPoint& position() const { return m_position; }
|
||||||
const String& data_type() const { return m_data_type; }
|
const Vector<String>& mime_types() const { return m_mime_types; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Gfx::IntPoint m_position;
|
Gfx::IntPoint m_position;
|
||||||
String m_data_type;
|
Vector<String> m_mime_types;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DropEvent final : public Event {
|
class DropEvent final : public Event {
|
||||||
|
|
|
@ -589,11 +589,11 @@ String FileSystemModel::column_name(int column) const
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FileSystemModel::accepts_drag(const ModelIndex& index, const StringView& data_type)
|
bool FileSystemModel::accepts_drag(const ModelIndex& index, const Vector<String>& mime_types)
|
||||||
{
|
{
|
||||||
if (!index.is_valid())
|
if (!index.is_valid())
|
||||||
return false;
|
return false;
|
||||||
if (data_type != "text/uri-list")
|
if (!mime_types.contains_slow("text/uri-list"))
|
||||||
return false;
|
return false;
|
||||||
auto& node = this->node(index);
|
auto& node = this->node(index);
|
||||||
return node.is_directory();
|
return node.is_directory();
|
||||||
|
|
|
@ -147,7 +147,7 @@ public:
|
||||||
virtual ModelIndex parent_index(const ModelIndex&) const override;
|
virtual ModelIndex parent_index(const ModelIndex&) const override;
|
||||||
virtual ModelIndex index(int row, int column = 0, const ModelIndex& parent = ModelIndex()) const override;
|
virtual ModelIndex index(int row, int column = 0, const ModelIndex& parent = ModelIndex()) const override;
|
||||||
virtual StringView drag_data_type() const override { return "text/uri-list"; }
|
virtual StringView drag_data_type() const override { return "text/uri-list"; }
|
||||||
virtual bool accepts_drag(const ModelIndex&, const StringView& data_type) override;
|
virtual bool accepts_drag(const ModelIndex&, const Vector<String>& mime_types) override;
|
||||||
virtual bool is_column_sortable(int column_index) const override { return column_index != Column::Icon; }
|
virtual bool is_column_sortable(int column_index) const override { return column_index != Column::Icon; }
|
||||||
virtual bool is_editable(const ModelIndex&) const override;
|
virtual bool is_editable(const ModelIndex&) const override;
|
||||||
virtual bool is_searchable() const override { return true; }
|
virtual bool is_searchable() const override { return true; }
|
||||||
|
|
|
@ -270,10 +270,7 @@ void IconView::drag_move_event(DragEvent& event)
|
||||||
auto index = index_at_event_position(event.position());
|
auto index = index_at_event_position(event.position());
|
||||||
ModelIndex new_drop_candidate_index;
|
ModelIndex new_drop_candidate_index;
|
||||||
if (index.is_valid()) {
|
if (index.is_valid()) {
|
||||||
bool acceptable = model()->accepts_drag(index, event.data_type());
|
bool acceptable = model()->accepts_drag(index, event.mime_types());
|
||||||
#ifdef DRAGDROP_DEBUG
|
|
||||||
dbg() << "Drag of type '" << event.data_type() << "' moving over " << index << ", acceptable: " << acceptable;
|
|
||||||
#endif
|
|
||||||
if (acceptable)
|
if (acceptable)
|
||||||
new_drop_candidate_index = index;
|
new_drop_candidate_index = index;
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,7 +71,7 @@ ModelIndex Model::index(int row, int column, const ModelIndex&) const
|
||||||
return create_index(row, column);
|
return create_index(row, column);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Model::accepts_drag(const ModelIndex&, const StringView&)
|
bool Model::accepts_drag(const ModelIndex&, const Vector<String>&)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,7 +82,7 @@ public:
|
||||||
virtual bool is_searchable() const { return false; }
|
virtual bool is_searchable() const { return false; }
|
||||||
virtual void set_data(const ModelIndex&, const Variant&) { }
|
virtual void set_data(const ModelIndex&, const Variant&) { }
|
||||||
virtual int tree_column() const { return 0; }
|
virtual int tree_column() const { return 0; }
|
||||||
virtual bool accepts_drag(const ModelIndex&, const StringView& data_type);
|
virtual bool accepts_drag(const ModelIndex&, const Vector<String>& mime_types);
|
||||||
virtual Vector<ModelIndex, 1> matches(const StringView&, unsigned = MatchesFlag::AllMatching, const ModelIndex& = ModelIndex()) { return {}; }
|
virtual Vector<ModelIndex, 1> matches(const StringView&, unsigned = MatchesFlag::AllMatching, const ModelIndex& = ModelIndex()) { return {}; }
|
||||||
|
|
||||||
virtual bool is_column_sortable([[maybe_unused]] int column_index) const { return true; }
|
virtual bool is_column_sortable([[maybe_unused]] int column_index) const { return true; }
|
||||||
|
|
|
@ -510,7 +510,9 @@ void Widget::drag_move_event(DragEvent&)
|
||||||
|
|
||||||
void Widget::drag_enter_event(DragEvent& event)
|
void Widget::drag_enter_event(DragEvent& event)
|
||||||
{
|
{
|
||||||
dbgln("{} {:p} DRAG ENTER @ {}, {}", class_name(), this, event.position(), event.data_type());
|
StringBuilder builder;
|
||||||
|
builder.join(',', event.mime_types());
|
||||||
|
dbgln("{} {:p} DRAG ENTER @ {}, {}", class_name(), this, event.position(), builder.string_view());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::drag_leave_event(Event&)
|
void Widget::drag_leave_event(Event&)
|
||||||
|
|
|
@ -446,14 +446,14 @@ void Window::handle_drag_move_event(DragEvent& event)
|
||||||
auto result = m_main_widget->hit_test(event.position());
|
auto result = m_main_widget->hit_test(event.position());
|
||||||
ASSERT(result.widget);
|
ASSERT(result.widget);
|
||||||
|
|
||||||
Application::the()->set_drag_hovered_widget({}, result.widget, result.local_position, event.data_type());
|
Application::the()->set_drag_hovered_widget({}, result.widget, result.local_position, event.mime_types());
|
||||||
|
|
||||||
// NOTE: Setting the drag hovered widget may have executed arbitrary code, so re-check that the widget is still there.
|
// NOTE: Setting the drag hovered widget may have executed arbitrary code, so re-check that the widget is still there.
|
||||||
if (!result.widget)
|
if (!result.widget)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (result.widget->has_pending_drop()) {
|
if (result.widget->has_pending_drop()) {
|
||||||
DragEvent drag_move_event(static_cast<Event::Type>(event.type()), result.local_position, event.data_type());
|
DragEvent drag_move_event(static_cast<Event::Type>(event.type()), result.local_position, event.mime_types());
|
||||||
result.widget->dispatch_event(drag_move_event, this);
|
result.widget->dispatch_event(drag_move_event, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -246,7 +246,7 @@ void WindowServerConnection::handle(const Messages::WindowClient::MouseMove& mes
|
||||||
{
|
{
|
||||||
if (auto* window = Window::from_window_id(message.window_id())) {
|
if (auto* window = Window::from_window_id(message.window_id())) {
|
||||||
if (message.is_drag())
|
if (message.is_drag())
|
||||||
Core::EventLoop::current().post_event(*window, make<DragEvent>(Event::DragMove, message.mouse_position(), message.drag_data_type()));
|
Core::EventLoop::current().post_event(*window, make<DragEvent>(Event::DragMove, message.mouse_position(), message.mime_types()));
|
||||||
else
|
else
|
||||||
Core::EventLoop::current().post_event(*window, make<MouseEvent>(Event::MouseMove, message.mouse_position(), message.buttons(), to_gmousebutton(message.button()), message.modifiers(), message.wheel_delta()));
|
Core::EventLoop::current().post_event(*window, make<MouseEvent>(Event::MouseMove, message.mouse_position(), message.buttons(), to_gmousebutton(message.button()), message.modifiers(), message.wheel_delta()));
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,7 +126,13 @@ public:
|
||||||
unsigned modifiers() const { return m_modifiers; }
|
unsigned modifiers() const { return m_modifiers; }
|
||||||
int wheel_delta() const { return m_wheel_delta; }
|
int wheel_delta() const { return m_wheel_delta; }
|
||||||
bool is_drag() const { return m_drag; }
|
bool is_drag() const { return m_drag; }
|
||||||
const String& drag_data_type() const { return m_drag_data_type; }
|
|
||||||
|
Vector<String> mime_types() const
|
||||||
|
{
|
||||||
|
if (!m_mime_data)
|
||||||
|
return {};
|
||||||
|
return m_mime_data->formats();
|
||||||
|
}
|
||||||
|
|
||||||
void set_drag(bool b) { m_drag = b; }
|
void set_drag(bool b) { m_drag = b; }
|
||||||
void set_mime_data(const Core::MimeData& mime_data) { m_mime_data = mime_data; }
|
void set_mime_data(const Core::MimeData& mime_data) { m_mime_data = mime_data; }
|
||||||
|
@ -140,7 +146,6 @@ private:
|
||||||
unsigned m_modifiers { 0 };
|
unsigned m_modifiers { 0 };
|
||||||
int m_wheel_delta { 0 };
|
int m_wheel_delta { 0 };
|
||||||
bool m_drag { false };
|
bool m_drag { false };
|
||||||
String m_drag_data_type;
|
|
||||||
RefPtr<const Core::MimeData> m_mime_data;
|
RefPtr<const Core::MimeData> m_mime_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -162,6 +162,8 @@ void Screen::on_receive_mouse_data(const MousePacket& packet)
|
||||||
post_mousedown_or_mouseup_if_needed(MouseButton::Forward);
|
post_mousedown_or_mouseup_if_needed(MouseButton::Forward);
|
||||||
if (m_cursor_location != prev_location) {
|
if (m_cursor_location != prev_location) {
|
||||||
auto message = make<MouseEvent>(Event::MouseMove, m_cursor_location, buttons, MouseButton::None, m_modifiers);
|
auto message = make<MouseEvent>(Event::MouseMove, m_cursor_location, buttons, MouseButton::None, m_modifiers);
|
||||||
|
if (WindowManager::the().dnd_client())
|
||||||
|
message->set_mime_data(WindowManager::the().dnd_mime_data());
|
||||||
Core::EventLoop::current().post_event(WindowManager::the(), move(message));
|
Core::EventLoop::current().post_event(WindowManager::the(), move(message));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -182,7 +182,7 @@ void Window::handle_mouse_event(const MouseEvent& event)
|
||||||
|
|
||||||
switch (event.type()) {
|
switch (event.type()) {
|
||||||
case Event::MouseMove:
|
case Event::MouseMove:
|
||||||
m_client->post_message(Messages::WindowClient::MouseMove(m_window_id, event.position(), (u32)event.button(), event.buttons(), event.modifiers(), event.wheel_delta(), event.is_drag(), event.drag_data_type()));
|
m_client->post_message(Messages::WindowClient::MouseMove(m_window_id, event.position(), (u32)event.button(), event.buttons(), event.modifiers(), event.wheel_delta(), event.is_drag(), event.mime_types()));
|
||||||
break;
|
break;
|
||||||
case Event::MouseDown:
|
case Event::MouseDown:
|
||||||
m_client->post_message(Messages::WindowClient::MouseDown(m_window_id, event.position(), (u32)event.button(), event.buttons(), event.modifiers(), event.wheel_delta()));
|
m_client->post_message(Messages::WindowClient::MouseDown(m_window_id, event.position(), (u32)event.button(), event.buttons(), event.modifiers(), event.wheel_delta()));
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
endpoint WindowClient = 4
|
endpoint WindowClient = 4
|
||||||
{
|
{
|
||||||
Paint(i32 window_id, Gfx::IntSize window_size, Vector<Gfx::IntRect> rects) =|
|
Paint(i32 window_id, Gfx::IntSize window_size, Vector<Gfx::IntRect> rects) =|
|
||||||
MouseMove(i32 window_id, Gfx::IntPoint mouse_position, u32 button, u32 buttons, u32 modifiers, i32 wheel_delta, bool is_drag, String drag_data_type) =|
|
MouseMove(i32 window_id, Gfx::IntPoint mouse_position, u32 button, u32 buttons, u32 modifiers, i32 wheel_delta, bool is_drag, Vector<String> mime_types) =|
|
||||||
MouseDown(i32 window_id, Gfx::IntPoint mouse_position, u32 button, u32 buttons, u32 modifiers, i32 wheel_delta) =|
|
MouseDown(i32 window_id, Gfx::IntPoint mouse_position, u32 button, u32 buttons, u32 modifiers, i32 wheel_delta) =|
|
||||||
MouseDoubleClick(i32 window_id, Gfx::IntPoint mouse_position, u32 button, u32 buttons, u32 modifiers, i32 wheel_delta) =|
|
MouseDoubleClick(i32 window_id, Gfx::IntPoint mouse_position, u32 button, u32 buttons, u32 modifiers, i32 wheel_delta) =|
|
||||||
MouseUp(i32 window_id, Gfx::IntPoint mouse_position, u32 button, u32 buttons, u32 modifiers, i32 wheel_delta) =|
|
MouseUp(i32 window_id, Gfx::IntPoint mouse_position, u32 button, u32 buttons, u32 modifiers, i32 wheel_delta) =|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue