vcl/unx/gtk3/gtkinst.cxx | 98 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 91 insertions(+), 7 deletions(-)
New commits: commit 231ad90b597410cab7f4f2e9a7b4547d97fb9972 Author: Caolán McNamara <caol...@redhat.com> AuthorDate: Thu Jan 19 15:37:31 2023 +0000 Commit: Caolán McNamara <caol...@redhat.com> CommitDate: Fri Jan 20 08:53:53 2023 +0000 tdf#149412 gtk3: show all selected rows in dnd icon otherwise it looks like only one row is getting moved Change-Id: Ie0b63a9c3cea377c3753785d9c6f7958cbc7ac1b Reviewed-on: https://gerrit.libreoffice.org/c/core/+/145818 Tested-by: Jenkins Reviewed-by: Caolán McNamara <caol...@redhat.com> diff --git a/vcl/unx/gtk3/gtkinst.cxx b/vcl/unx/gtk3/gtkinst.cxx index 4fa9dce0a5b5..339958ff606d 100644 --- a/vcl/unx/gtk3/gtkinst.cxx +++ b/vcl/unx/gtk3/gtkinst.cxx @@ -2829,8 +2829,10 @@ private: #endif int m_nPressedButton; #if !GTK_CHECK_VERSION(4, 0, 0) +protected: int m_nPressStartX; int m_nPressStartY; +private: #endif ImplSVEvent* m_pDragCancelEvent; GtkCssProvider* m_pBgCssProvider; @@ -3267,6 +3269,14 @@ private: return false; } +#if GTK_CHECK_VERSION(4, 0, 0) + virtual void drag_set_icon(GtkDragSource*) +#else + virtual void drag_set_icon(GdkDragContext*) +#endif + { + } + #if GTK_CHECK_VERSION(4, 0, 0) void signal_drag_begin(GtkDragSource* context) #else @@ -3278,19 +3288,22 @@ private: { #if !GTK_CHECK_VERSION(4, 0, 0) launch_drag_cancel(context); -#else - (void)context; #endif return; } -#if !GTK_CHECK_VERSION(4, 0, 0) if (bUnsetDragIcon) { +#if !GTK_CHECK_VERSION(4, 0, 0) cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 0, 0); gtk_drag_set_icon_surface(context, surface); cairo_surface_destroy(surface); - } #endif + } + else + { + drag_set_icon(context); + } + if (!m_xDragSource) return; m_xDragSource->setActiveDragSource(); @@ -4902,11 +4915,11 @@ namespace { Size aSize(rDevice.GetOutputSizePixel()); cairo_surface_t* orig_surface = get_underlying_cairo_surface(rDevice); - double m_fXScale, m_fYScale; - dl_cairo_surface_get_device_scale(orig_surface, &m_fXScale, &m_fYScale); + double fXScale, fYScale; + dl_cairo_surface_get_device_scale(orig_surface, &fXScale, &fYScale); cairo_surface_t* surface; - if (m_fXScale != 1.0 || m_fYScale != -1) + if (fXScale != 1.0 || fYScale != -1) { surface = cairo_surface_create_similar_image(orig_surface, CAIRO_FORMAT_ARGB32, @@ -16441,6 +16454,77 @@ public: return false; } +#if GTK_CHECK_VERSION(4, 0, 0) + virtual void drag_set_icon(GtkDragSource*) override + { + } +#else + virtual void drag_set_icon(GdkDragContext* context) override + { + GtkTreeSelection *selection = gtk_tree_view_get_selection(m_pTreeView); + if (gtk_tree_selection_get_mode(selection) == GTK_SELECTION_MULTIPLE) + { + int nWidth = 0; + int nHeight = 0; + + GList* pList = gtk_tree_selection_get_selected_rows(gtk_tree_view_get_selection(m_pTreeView), nullptr); + std::vector<cairo_surface_t*> surfaces; + std::vector<int> heights; + for (GList* pItem = g_list_first(pList); pItem; pItem = g_list_next(pItem)) + { + GtkTreePath* pPath = static_cast<GtkTreePath*>(pItem->data); + + surfaces.push_back(gtk_tree_view_create_row_drag_icon(m_pTreeView, pPath)); + + double x1, x2, y1, y2; + cairo_t* cr = cairo_create(surfaces.back()); + cairo_clip_extents(cr, &x1, &y1, &x2, &y2); + cairo_destroy(cr); + + heights.push_back(y2 - y1); + + nWidth = std::max(nWidth, static_cast<int>(x2 - x1)); + nHeight += heights.back(); + } + g_list_free_full(pList, reinterpret_cast<GDestroyNotify>(gtk_tree_path_free)); + + // if its just one, then don't do anything and leave the default dnd icon as-is + if (surfaces.size() > 1) + { + cairo_surface_t* target = cairo_surface_create_similar(surfaces[0], + cairo_surface_get_content(surfaces[0]), + nWidth, + nHeight); + + cairo_t* cr = cairo_create(target); + + double y_pos = 0; + for (size_t i = 0; i < surfaces.size(); ++i) + { + cairo_set_source_surface(cr, surfaces[i], 2, y_pos + 2); + cairo_rectangle(cr, 0, y_pos, nWidth, heights[i]); + cairo_fill(cr); + y_pos += heights[i]; + } + + cairo_destroy(cr); + + double fXScale, fYScale; + dl_cairo_surface_get_device_scale(target, &fXScale, &fYScale); + cairo_surface_set_device_offset(target, + - m_nPressStartX * fXScale, + 0); + + gtk_drag_set_icon_surface(context, target); + cairo_surface_destroy(target); + } + + for (auto surface : surfaces) + cairo_surface_destroy(surface); + } + } +#endif + virtual void do_signal_drag_end() override { g_DragSource = nullptr;