summaryrefslogtreecommitdiffstats
path: root/common/Clipboard.hpp
blob: 669e27b54b6a26b1191931a21f83eaaad7198e51 (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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
/*
 * 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/.
 */

// Clipboard abstraction.

#pragma once

#include <string>
#include <vector>
#include <unordered_map>
#include <mutex>

#include <stdlib.h>
#include <Log.hpp>
#include <Exceptions.hpp>
#include <Poco/MemoryStream.h>

struct ClipboardData
{
    std::vector<std::string> _mimeTypes;
    std::vector<std::string> _content;
    ClipboardData()
    {
    }

    void read(std::istream& inStream)
    {
        while (!inStream.eof())
        {
            std::string mime, hexLen, newline;
            std::getline(inStream, mime, '\n');
            std::getline(inStream, hexLen, '\n');
            if (mime.length() && hexLen.length() && !inStream.fail())
            {
                uint64_t len = strtoll( hexLen.c_str(), nullptr, 16 );
                std::string content(len, ' ');
                inStream.read(&content[0], len);
                if (inStream.fail())
                    throw ParseError("error during reading the stream");
                std::getline(inStream, newline, '\n');
                if (mime.length() > 0)
                {
                    _mimeTypes.push_back(mime);
                    _content.push_back(content);
                }
            }
        }
    }

    size_t size()
    {
        assert(_mimeTypes.size() == _content.size());
        return _mimeTypes.size();
    }

    void dumpState(std::ostream& os)
    {
        os << "Clipboard with " << size() << " entries\n";
        for (size_t i = 0; i < size(); ++i)
            os << "\t[" << i << "] - size " << _content[i].size() <<
                " type: '" << _mimeTypes[i] << "'\n";
    }

    bool findType(const std::string &mime, std::string &value)
    {
        for (size_t i = 0; i < _mimeTypes.size(); ++i)
        {
            if (_mimeTypes[i] == mime)
            {
                value = _content[i];
                return true;
            }
        }
        value = "";
        return false;
    }
};

/// Used to store expired view's clipboards
class ClipboardCache
{
    std::mutex _mutex;
    struct Entry {
        std::chrono::steady_clock::time_point _inserted;
        std::shared_ptr<std::string> _rawData; // big.
    };
    // clipboard key -> data
    std::unordered_map<std::string, Entry> _cache;
public:
    ClipboardCache()
    {
    }

    void insertClipboard(const std::string key[2],
                         const char *data, size_t size)
    {
        if (size == 0)
        {
            LOG_TRC("clipboard cache - ignores empty clipboard data");
            return;
        }
        Entry ent;
        ent._inserted = std::chrono::steady_clock::now();
        ent._rawData = std::make_shared<std::string>(data, size);
        LOG_TRC("insert cached clipboard: " + key[0] + " and " + key[1]);
        std::lock_guard<std::mutex> lock(_mutex);
        _cache[key[0]] = ent;
        _cache[key[1]] = ent;
    }

    std::shared_ptr<std::string> getClipboard(const std::string &key)
    {
        std::lock_guard<std::mutex> lock(_mutex);
        std::shared_ptr<std::string> data;
        auto it = _cache.find(key);
        if (it != _cache.end())
            data = it->second._rawData;
        return data;
    }

    void checkexpiry()
    {
        std::lock_guard<std::mutex> lock(_mutex);
        auto now = std::chrono::steady_clock::now();
        LOG_TRC("check expiry of cached clipboards");
        for (auto it = _cache.begin(); it != _cache.end();)
        {
            if (std::chrono::duration_cast<std::chrono::minutes>(now - it->second._inserted).count() >= 10)
            {
                LOG_TRC("expiring expiry of cached clipboard: " + it->first);
                it = _cache.erase(it);
            }
            else
                ++it;
        }
    }
};

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