#include <dali/internal/clipboard/common/clipboard-impl.h>
// EXTERNAL INCLUDES
-#include <dali/devel-api/adaptor-framework/environment-variable.h>
#include <dali/devel-api/common/singleton-service.h>
#include <dali/internal/adaptor/tizen-wayland/dali-ecore-wl2.h>
#include <dali/integration-api/debug.h>
-#include <dali/public-api/adaptor-framework/timer.h>
-#include <map>
#include <unistd.h>
+#include <unordered_map>
namespace Dali
{
{
namespace Adaptor
{
-namespace
-{
-const char* DALI_CLIPBOARD_MULTI_SELECTION_TIMEOUT("DALI_CLIPBOARD_MULTI_SELECTION_TIMEOUT");
-const uint32_t DEFAULT_MULTI_SELECTION_TIMEOUT = 500u;
-}
-
static Eina_Bool EcoreEventDataSend(void* data, int type, void* event);
static Eina_Bool EcoreEventOfferDataReady(void* data, int type, void* event);
static Eina_Bool EcoreEventSelectionOffer(void* data, int type, void* event);
bool SetData(const Dali::Clipboard::ClipData& clipData)
{
- std::string mimeType = clipData.GetMimeType();
- std::string data = clipData.GetData();
+ mMimeType = clipData.GetMimeType();
+ mData = clipData.GetData();
- if(data.empty())
+ if(mData.empty())
{
DALI_LOG_ERROR("ClipData is empty, return false.\n");
return false;
}
const char* mimeTypes[2];
- mimeTypes[0] = mimeType.c_str();
+ mimeTypes[0] = mMimeType.c_str();
mimeTypes[1] = nullptr;
- mSetDatas[mimeType] = data;
-
Ecore_Wl2_Display* display = ecore_wl2_connected_display_get(NULL);
Ecore_Wl2_Input* input = ecore_wl2_input_default_input_get(display);
-
- uint32_t serial = ecore_wl2_dnd_selection_set(input, mimeTypes);
- DALI_LOG_RELEASE_INFO("selection_set success, serial:%u, type:%s, data:%s\n", serial, mimeType.c_str(), data.c_str());
-
- // If the serial is the same, it is the same source.
- // If the type is the same, it is a separate copy.
- if(mSerial == serial && mLastType != mimeType && !mMultiSelectionTimeout)
- {
- // Checks whether there is an identical type requested from one source.
- bool typeExists = false;
- for (const auto& type : mSetTypes)
- {
- if (type == mimeType)
- {
- typeExists = true;
- break;
- }
- }
-
- if(!typeExists) // Same copy.
- {
- // It requests all types of copies requested from one source at once.
- // EcoreEventDataSend callback is called as many as the number of requested types.
- mSetTypes.push_back(mimeType);
-
- size_t typeCount = mSetTypes.size();
- const char* types[typeCount + 1];
- for(size_t i = 0; i < typeCount; i++)
- {
- types[i] = mSetTypes[i].c_str();
- DALI_LOG_RELEASE_INFO("selection_set multi types, serial:%u, type:%s\n", serial, types[i]);
- }
- types[typeCount] = nullptr;
-
- // TODO : At this point, it is impossible to avoid duplicate calls,
- // because we cannot know how many more times the copy will be called for the same source.
- serial = ecore_wl2_dnd_selection_set(input, types);
- }
- else // Separate copy.
- {
- mSetTypes.clear();
- mSetTypes.push_back(mimeType);
- }
- }
- else
- {
- mSetTypes.clear();
- mSetTypes.push_back(mimeType);
- }
-
- // Store the last serial and type.
- mSerial = serial;
- mLastType = mimeType;
-
- SetMultiSelectionTimeout();
+ mSerial = ecore_wl2_dnd_selection_set(input, mimeTypes);
+ DALI_LOG_RELEASE_INFO("selection_set success, serial:%u, type:%s, data:%s\n", mSerial, mMimeType.c_str(), mData.c_str());
return true;
}
if(!offer)
{
DALI_LOG_ERROR("selection_get fail, request type:%s\n", mimeType.c_str());
- mLastOffer = nullptr;
return 0u;
}
return 0u;
}
- uint32_t lastDataId = mDataId;
mDataId++;
mDataRequestIds.push_back(mDataId);
mDataRequestItems[mDataId] = std::make_pair(mimeType, offer);
- // Not yet received a callback for the recent offer receive.
- if(mLastOffer == offer && mDataRequestItems.count(lastDataId))
- {
- // A receive request for the same offer and type is made only once.
- if(std::find(mGetTypes.begin(), mGetTypes.end(), mimeType) == mGetTypes.end())
- {
- mGetTypes.push_back(mimeType);
- mReservedOfferReceives[lastDataId] = mDataId;
- } // else do nothing.
- }
- else
- {
- mGetTypes.clear();
- mGetTypes.push_back(mimeType);
-
- DALI_LOG_RELEASE_INFO("offer_receive, id:%u, request type:%s\n", mDataId, mimeType.c_str());
- ecore_wl2_offer_receive(offer, const_cast<char*>(type));
- ecore_wl2_display_flush(ecore_wl2_input_display_get(input));
- }
-
- mLastOffer = offer;
-
+ DALI_LOG_RELEASE_INFO("offer_receive, id:%u, request type:%s\n", mDataId, mimeType.c_str());
+ ecore_wl2_offer_receive(offer, const_cast<char*>(type));
+ ecore_wl2_display_flush(ecore_wl2_input_display_get(input));
return mDataId;
}
if(ev->serial != mSerial)
{
- DALI_LOG_ERROR("ev->serial:%u, mSerial:%u, type:%s\n", ev->serial, mSerial, ev->type);
return;
}
- // Check whether the hash has data of the requested type.
- // If there is no data of the requested type, something has already gone wrong.
- std::string type = ev->type;
- std::string data = "";
- if(mSetDatas.count(type))
+ // no matching mime type.
+ if(mMimeType.compare(ev->type))
{
- data = mSetDatas[type];
+ auto it = mDataRequestIds.begin();
+ while(it != mDataRequestIds.end())
+ {
+ uint32_t dataRequestId = *it;
+ auto item = mDataRequestItems.find(dataRequestId);
+ if(item != mDataRequestItems.end())
+ {
+ std::string mimeType = static_cast<std::string>(item->second.first);
+ if(!mimeType.compare(ev->type))
+ {
+ mDataRequestItems.erase(dataRequestId);
+ it = mDataRequestIds.erase(it);
+ DALI_LOG_ERROR("no matching type, empty signal emit, request type:%s, available type:%s\n", ev->type, mMimeType.c_str());
+ mDataReceivedSignal.Emit(dataRequestId, "", "");
+ }
+ else
+ {
+ ++it;
+ }
+ }
+ }
+ return;
}
- size_t dataLength = strlen(data.c_str());
+ size_t dataLength = strlen(mData.c_str());
size_t bufferSize = dataLength + 1u;
char* buffer = new char[bufferSize];
return;
}
- memcpy(buffer, data.c_str(), dataLength);
+ memcpy(buffer, mData.c_str(), dataLength);
buffer[dataLength] = '\0';
auto ret = write(ev->fd, buffer, bufferSize);
close(ev->fd);
delete[] buffer;
- DALI_LOG_RELEASE_INFO("send data, type:%s, data:%s \n", ev->type, data.c_str());
- mDataSentSignal.Emit(ev->type, data.c_str());
+ DALI_LOG_RELEASE_INFO("send data, type:%s, data:%s \n", mMimeType.c_str(), mData.c_str());
+ mDataSentSignal.Emit(ev->type, mData.c_str());
}
void ReceiveData(void* event)
DALI_LOG_RELEASE_INFO("receive data, type:%s, data:%s\n", ev->mimetype, content.c_str());
- // Retrieve request id list.
- for(auto it = mDataRequestIds.begin(); it != mDataRequestIds.end();)
+ auto it = mDataRequestIds.begin();
+ while(it != mDataRequestIds.end())
{
uint32_t dataRequestId = *it;
- if(mDataRequestItems.count(dataRequestId))
+ auto item = mDataRequestItems.find(dataRequestId);
+ if(item != mDataRequestItems.end())
{
- auto item = mDataRequestItems[dataRequestId];
- std::string mimeType = static_cast<std::string>(item.first);
- Ecore_Wl2_Offer* offer = static_cast<Ecore_Wl2_Offer*>(item.second);
-
- // Processes all the same types stored in the request list.
- if(!mimeType.compare(ev->mimetype))
+ Ecore_Wl2_Offer* offer = static_cast<Ecore_Wl2_Offer*>(item->second.second);
+ if(offer == ev->offer)
{
+ std::string mimeType = static_cast<std::string>(item->second.first);
mDataRequestItems.erase(dataRequestId);
it = mDataRequestIds.erase(it);
-
- // A change in an offer means a change in the clipboard's data.
- // Old offers are not always invalid, but at least in Dali it is unknown whether they are valid or not.
- // For safe processing, old offers are considered invalid offers.
- if(offer && offer == ev->offer && mLastOffer == offer)
- {
- DALI_LOG_RELEASE_INFO("receive data, success signal emit, id:%u, type:%s\n", dataRequestId, mimeType.c_str());
- mDataReceivedSignal.Emit(dataRequestId, mimeType.c_str(), content.c_str());
-
- if(mReservedOfferReceives.count(dataRequestId))
- {
- uint32_t reservedId = mReservedOfferReceives[dataRequestId];
- if(mDataRequestItems.count(reservedId))
- {
- auto reservedItem = mDataRequestItems[reservedId];
- std::string reservedType = static_cast<std::string>(reservedItem.first);
- Ecore_Wl2_Offer* reservedOffer = static_cast<Ecore_Wl2_Offer*>(reservedItem.second);
-
- if(reservedOffer)
- {
- Ecore_Wl2_Display* display = ecore_wl2_connected_display_get(NULL);
- Ecore_Wl2_Input* input = ecore_wl2_input_default_input_get(display);
-
- DALI_LOG_RELEASE_INFO("offer_receive, id:%u, request type:%s\n", reservedId, reservedType.c_str());
- ecore_wl2_offer_receive(reservedOffer, const_cast<char*>(reservedType.c_str()));
- ecore_wl2_display_flush(ecore_wl2_input_display_get(input));
- }
- }
- mReservedOfferReceives.erase(dataRequestId);
- }
- }
- else // null or invalid offer.
- {
- DALI_LOG_RELEASE_INFO("invalid offer, id:%u, request type:%s\n", dataRequestId, mimeType.c_str());
- mDataReceivedSignal.Emit(dataRequestId, "", "");
-
- if(mReservedOfferReceives.count(dataRequestId))
- {
- mReservedOfferReceives.erase(dataRequestId);
- }
- }
+ DALI_LOG_RELEASE_INFO("receive data, success signal emit, id:%u, type:%s\n", dataRequestId, mimeType.c_str());
+ mDataReceivedSignal.Emit(dataRequestId, mimeType.c_str(), content.c_str());
}
- else // item's type and event data's type are different.
+ else
{
++it;
}
}
- else // There is no id in request items.
- {
- it = mDataRequestIds.erase(it);
- }
}
}
for(int i = 0; i < ev->num_types; i++)
{
+ DALI_LOG_RELEASE_INFO("mime type(%s)", ev->types[i]);
if(!formatMarkup.compare(ev->types[i]))
{
- // Ignore elementary markup from efl.
continue;
}
- selectedType = ev->types[i];
- DALI_LOG_RELEASE_INFO("data selected signal emit, type:%s\n", selectedType);
- mDataSelectedSignal.Emit(selectedType);
+ if(!selectedType)
+ {
+ selectedType = ev->types[i];
+ }
}
if(!selectedType)
DALI_LOG_ERROR("mime type is invalid.\n");
return;
}
- }
-
- void SetMultiSelectionTimeout()
- {
- mMultiSelectionTimeout = false;
- if(mMultiSelectionTimeoutTimer.IsRunning())
- {
- mMultiSelectionTimeoutTimer.Stop();
- }
- mMultiSelectionTimeoutTimer.Start();
- }
- bool OnMultiSelectionTimeout()
- {
- DALI_LOG_RELEASE_INFO("multi-selection end\n");
- mMultiSelectionTimeout = true;
- return false;
+ DALI_LOG_RELEASE_INFO("data selected signal emit, type:%s\n", selectedType);
+ mDataSelectedSignal.Emit(selectedType);
}
- uint32_t mSerial{std::numeric_limits<uint32_t>::max()};
- std::string mLastType; // mime type used in last copy.
- Ecore_Wl2_Offer* mLastOffer; // offer used in last paste.
-
+ uint32_t mSerial{std::numeric_limits<uint32_t>::max()};
+ std::string mMimeType;
+ std::string mData;
Ecore_Event_Handler* mSendHandler{nullptr};
Ecore_Event_Handler* mReceiveHandler{nullptr};
Ecore_Event_Handler* mSelectionHanlder{nullptr};
uint32_t mDataId{0};
std::vector<uint32_t> mDataRequestIds;
- std::map<uint32_t, std::pair<std::string, Ecore_Wl2_Offer*>> mDataRequestItems;
-
- std::vector<std::string> mSetTypes; // types for the same source (one user copy).
- std::map<std::string, std::string> mSetDatas; // datas for the same source (one user copy), key is mime type, value is data.
- std::vector<std::string> mGetTypes; // types requested to receive for the same offer.
- std::map<uint32_t, uint32_t> mReservedOfferReceives; // in order to process offer receive sequentially, key is current id, value is reserved id.
-
- Dali::Timer mMultiSelectionTimeoutTimer;
- bool mMultiSelectionTimeout{false};
+ std::unordered_map<uint32_t, std::pair<std::string, Ecore_Wl2_Offer*>> mDataRequestItems;
};
static Eina_Bool EcoreEventDataSend(void* data, int type, void* event)
Clipboard::Clipboard(Impl* impl)
: mImpl(impl)
{
- // Check environment variable for DALI_CLIPBOARD_MULTI_SELECTION_TIMEOUT
- auto timeoutString = Dali::EnvironmentVariable::GetEnvironmentVariable(DALI_CLIPBOARD_MULTI_SELECTION_TIMEOUT);
- uint32_t multiSelectionTimeout = timeoutString ? static_cast<uint32_t>(std::atoi(timeoutString)) : DEFAULT_MULTI_SELECTION_TIMEOUT;
-
- DALI_LOG_RELEASE_INFO("multi-selection timeout set:%u\n", multiSelectionTimeout);
- mImpl->mMultiSelectionTimeoutTimer = Dali::Timer::New(multiSelectionTimeout);
- mImpl->mMultiSelectionTimeoutTimer.TickSignal().Connect(this, &Clipboard::OnMultiSelectionTimeout);
}
Clipboard::~Clipboard()
return false;
}
-bool Clipboard::OnMultiSelectionTimeout()
-{
- return mImpl->OnMultiSelectionTimeout();
-}
-
} // namespace Adaptor
} // namespace Internal
#include <dali/devel-api/common/singleton-service.h>
#include <dali/internal/adaptor/common/adaptor-impl.h>
#include <dali/internal/window-system/ubuntu-x11/window-interface-ecore-x.h>
-#include <map>
-#include <queue>
namespace Dali
{
bool HasType(const std::string& mimeType)
{
- for(const auto& type : mMimeTypes)
- {
- if (type == mimeType)
- {
- return true;
- }
- }
- return false;
- }
-
- void UpdateData(std::string& mimeType, std::string& data, bool clearBuffer)
- {
- if(clearBuffer)
- {
- mMimeTypes.clear();
- mDatas.clear();
- }
- mMimeTypes.push_back(mimeType);
- mDatas[mimeType] = data;
+ return mMimeType == mimeType ? true : false;
}
bool SetData(const Dali::Clipboard::ClipData& clipData)
{
- std::string mimeType = clipData.GetMimeType();
- std::string data = clipData.GetData();
+ mMimeType = clipData.GetMimeType();
+ mData = clipData.GetData();
- if(mimeType.empty() || data.empty())
+ if(mData.empty())
{
return false;
}
- if(mLastType != mimeType && !mMultiSelectionTimeout)
- {
- bool clearBuffer = HasType(mimeType);
- UpdateData(mimeType, data, clearBuffer);
- }
- else
- {
- UpdateData(mimeType, data, true);
- }
-
- mLastType = mimeType;
-
- mDataSentSignal.Emit(mimeType.c_str(), data.c_str());
- mDataSelectedSignal.Emit(mimeType.c_str());
-
- SetMultiSelectionTimeout();
+ mDataSentSignal.Emit(mMimeType.c_str(), mData.c_str());
+ mDataSelectedSignal.Emit(mMimeType.c_str());
return true;
}
uint32_t GetData(const std::string &mimeType)
{
- if(mDatas.count(mimeType))
+ if(!mMimeType.compare(mimeType.c_str()))
{
mDataId++;
- mDataReceiveQueue.push(std::make_pair(mDataId, mimeType));
-
// For consistency of operation with tizen Wl2, a fake callback is occurs using a timer.
if(mDataReceiveTimer.IsRunning())
{
bool OnReceiveData()
{
- while(!mDataReceiveQueue.empty())
- {
- auto item = mDataReceiveQueue.front();
- mDataReceiveQueue.pop();
-
- uint32_t requestId = item.first;
- std::string requestType = item.second;
- std::string data = "";
-
- if(mDatas.count(requestType))
- {
- data = mDatas[requestType];
- }
-
- DALI_LOG_RELEASE_INFO("receive data, success signal emit, id:%u, type:%s, data:%s\n", requestId, requestType.c_str(), data.c_str());
- mDataReceivedSignal.Emit(requestId, requestType.c_str(), data.c_str());
- }
- return false;
- }
-
- void SetMultiSelectionTimeout()
- {
- mMultiSelectionTimeout = false;
- if(mMultiSelectionTimeoutTimer.IsRunning())
- {
- mMultiSelectionTimeoutTimer.Stop();
- }
- mMultiSelectionTimeoutTimer.Start();
- }
-
- bool OnMultiSelectionTimeout()
- {
- mMultiSelectionTimeout = true;
+ DALI_LOG_RELEASE_INFO("receive data, success signal emit, id:%u, type:%s, data:%s\n", mDataId, mMimeType.c_str(), mData.c_str());
+ mDataReceivedSignal.Emit(mDataId, mMimeType.c_str(), mData.c_str());
return false;
}
Ecore_X_Window mApplicationWindow;
+ std::string mMimeType;
+ std::string mData;
uint32_t mDataId{0};
- std::string mLastType;
-
- std::vector<std::string> mMimeTypes;
- std::map<std::string, std::string> mDatas; // type, data
- std::queue<std::pair<uint32_t, std::string>> mDataReceiveQueue; // id, type
Dali::Clipboard::DataSentSignalType mDataSentSignal;
Dali::Clipboard::DataReceivedSignalType mDataReceivedSignal;
Dali::Clipboard::DataSelectedSignalType mDataSelectedSignal;
Dali::Timer mDataReceiveTimer;
- Dali::Timer mMultiSelectionTimeoutTimer;
- bool mMultiSelectionTimeout{false};
};
Clipboard::Clipboard(Impl* impl)
: mImpl(impl)
{
- mImpl->mDataReceiveTimer = Dali::Timer::New(10u);
+ mImpl->mDataReceiveTimer = Dali::Timer::New(10);
mImpl->mDataReceiveTimer.TickSignal().Connect(this, &Clipboard::OnReceiveData);
-
- mImpl->mMultiSelectionTimeoutTimer = Dali::Timer::New(500u);
- mImpl->mMultiSelectionTimeoutTimer.TickSignal().Connect(this, &Clipboard::OnMultiSelectionTimeout);
}
Clipboard::~Clipboard()
return mImpl->OnReceiveData();
}
-bool Clipboard::OnMultiSelectionTimeout()
-{
- return mImpl->OnMultiSelectionTimeout();
-}
-
} // namespace Adaptor
} // namespace Internal