--- a/plugins/grid/grid.cpp +++ b/plugins/grid/grid.cpp @@ -25,10 +25,49 @@ #include "wayfire/plugins/ipc/ipc-activator.hpp" #include "wayfire/signal-provider.hpp" #include +#include +#include namespace { const std::string grid_view_id = "grid-view"; + +class grid_preview_node_t : public wf::scene::translation_node_t +{ + public: + std::optional find_node_at(const wf::pointf_t&) override + { + return {}; + } +}; + +class grid_preview_t : public wf::preview_indication_t +{ + std::shared_ptr overlay; + + public: + grid_preview_t(wf::geometry_t target, wf::output_t *output) : + wf::preview_indication_t(target, output, "move") + { + // The move helper renders the held window above all ordinary layers. + // Keep its drop target visible above that window, without taking input. + overlay = std::make_shared(); + overlay->set_offset(wf::origin(output->get_layout_geometry())); + wf::scene::readd_front(overlay, view->get_root_node()); + wf::scene::add_front(wf::get_core().scene(), overlay); + view->set_geometry(target); + // Fade in at the actual destination; growing from the pointer makes + // short visits to an edge look like incomplete or moving targets. + set_target_geometry(target, 1); + } + + ~grid_preview_t() override + { + view->damage(); + view->close(); + wf::scene::remove_child(overlay); + } +}; class grid_scope_toggle_data_t : public wf::custom_data_t { @@ -87,7 +126,7 @@ wf::option_wrapper_t quarter_snap_threshold{"move/quarter_snap_threshold"}; struct { - std::shared_ptr preview; + std::shared_ptr preview; wf::grid::slot_t slot_id = wf::grid::SLOT_NONE; std::string zone; wf::geometry_t geometry = {0, 0, 0, 0}; @@ -188,14 +227,7 @@ void clear_zone_preview() { - if (slot.preview) - { - // Dropping the helper alone leaves its compositor view mapped. - slot.preview->view->damage(); - slot.preview->view->get_root_node()->set_enabled(false); - slot.preview->view->close(); - slot.preview.reset(); - } + slot.preview.reset(); } bool handle_zone_move(wf::grid::grid_handle_move_signal *ev) @@ -250,9 +282,7 @@ clear_zone_preview(); slot.slot_id = wf::grid::SLOT_NONE; slot.zone = zone->name; - slot.preview = std::make_shared( - wf::pointf_t{(double)ev->input.x, (double)ev->input.y}, ev->output, "move"); - slot.preview->set_target_geometry(zone->geometry, 1); + slot.preview = std::make_shared(zone->geometry, ev->output); } return true; @@ -468,14 +498,9 @@ return; } - /* Destroy previous preview */ - if (slot.preview) - { - auto input = ev->input; - slot.preview->set_target_geometry(wf::pointf_t{(double)input.x, (double)input.y}, 0, - true); - slot.preview = nullptr; - } + // Remove the old target immediately, including its scene node. A + // shrinking ghost should not trail the pointer or outlive the drag. + clear_zone_preview(); slot.slot_id = new_slot_id; slot.geometry = slot_geometry; @@ -489,10 +514,7 @@ return; } - auto input = ev->input; - slot.preview = std::make_shared( - wf::pointf_t{(double)input.x, (double)input.y}, ev->output, "move"); - slot.preview->set_target_geometry(slot_geometry, 1); + slot.preview = std::make_shared(slot_geometry, ev->output); } };