summaryrefslogtreecommitdiff
path: root/vcl/unx/gtk4/transferableprovider.cxx
blob: 554b80c0d4a6d9a59eafcd036b5c82d0a8c4b7f9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#include <com/sun/star/datatransfer/XTransferable.hpp>
#include <unx/gtk/gtkinst.hxx>
#include "transferableprovider.hxx"

#define TRANSFERABLE_CONTENT(obj)                                                                  \
    (G_TYPE_CHECK_INSTANCE_CAST((obj), transerable_content_get_type(), TransferableContent))

struct _TransferableContent
{
    GdkContentProvider parent;
    VclToGtkHelper* m_pConversionHelper;
    css::datatransfer::XTransferable* m_pContents;
    Link<void*, void> m_aDetachClipboardLink;
};

namespace
{
struct _TransferableContentClass : public GdkContentProviderClass
{
};
}

G_DEFINE_TYPE(TransferableContent, transerable_content, GDK_TYPE_CONTENT_PROVIDER)

static void transerable_content_write_mime_type_async(GdkContentProvider* provider,
                                                      const char* mime_type, GOutputStream* stream,
                                                      int io_priority, GCancellable* cancellable,
                                                      GAsyncReadyCallback callback,
                                                      gpointer user_data)
{
    TransferableContent* self = TRANSFERABLE_CONTENT(provider);
    if (!self->m_pContents)
        return;
    // tdf#129809 take a reference in case m_aContents is replaced during this
    // call
    css::uno::Reference<css::datatransfer::XTransferable> xCurrentContents(self->m_pContents);
    self->m_pConversionHelper->setSelectionData(xCurrentContents, provider, mime_type, stream,
                                                io_priority, cancellable, callback, user_data);
}

static gboolean transerable_content_write_mime_type_finish(GdkContentProvider*,
                                                           GAsyncResult* result, GError** error)
{
    return g_task_propagate_boolean(G_TASK(result), error);
}

static GdkContentFormats* transerable_content_ref_formats(GdkContentProvider* provider)
{
    TransferableContent* self = TRANSFERABLE_CONTENT(provider);
    css::uno::Reference<css::datatransfer::XTransferable> xCurrentContents(self->m_pContents);
    if (!xCurrentContents)
        return nullptr;

    auto aFormats = xCurrentContents->getTransferDataFlavors();
    std::vector<OString> aGtkTargets(self->m_pConversionHelper->FormatsToGtk(aFormats));

    GdkContentFormatsBuilder* pBuilder = gdk_content_formats_builder_new();
    for (const auto& rFormat : aGtkTargets)
        gdk_content_formats_builder_add_mime_type(pBuilder, rFormat.getStr());
    return gdk_content_formats_builder_free_to_formats(pBuilder);
}

static void transerable_content_detach_clipboard(GdkContentProvider* provider, GdkClipboard*)
{
    TransferableContent* self = TRANSFERABLE_CONTENT(provider);
    self->m_aDetachClipboardLink.Call(nullptr);
}

static void transerable_content_class_init(TransferableContentClass* klass)
{
    GdkContentProviderClass* provider_class = GDK_CONTENT_PROVIDER_CLASS(klass);

    provider_class->ref_formats = transerable_content_ref_formats;
    provider_class->detach_clipboard = transerable_content_detach_clipboard;
    provider_class->write_mime_type_async = transerable_content_write_mime_type_async;
    provider_class->write_mime_type_finish = transerable_content_write_mime_type_finish;
}

static void transerable_content_init(TransferableContent* self)
{
    self->m_pConversionHelper = nullptr;
    self->m_pContents = nullptr;
    // prevent loplugin:unreffun firing on macro generated function
    (void)transerable_content_get_instance_private(self);
}

void transerable_content_set_transferable(TransferableContent* pContent,
                                          css::datatransfer::XTransferable* pTransferable)
{
    pContent->m_pContents = pTransferable;
}

void transerable_content_set_detach_clipboard_link(TransferableContent* pContent,
                                                   const Link<void*, void>& rDetachClipboardLink)
{
    pContent->m_aDetachClipboardLink = rDetachClipboardLink;
}

GdkContentProvider* transerable_content_new(VclToGtkHelper* pConversionHelper,
                                            css::datatransfer::XTransferable* pTransferable)
{
    TransferableContent* content
        = TRANSFERABLE_CONTENT(g_object_new(transerable_content_get_type(), nullptr));
    content->m_pConversionHelper = pConversionHelper;
    content->m_pContents = pTransferable;
    return GDK_CONTENT_PROVIDER(content);
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */