// SPDX-FileCopyrightText: 2011 - 2022 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: GPL-3.0-or-later

#include "waylandclipboard.h"
// #include "readpipedatatask.h"
#include "clipboarddataprocess.h"
#include "systemclipboard.h"
#include "datamanage/clipdata.h"
#include "datamanage/clipdatarecord.h"
#include "datamanage/clipdataproperty.h"
#include "imageprocess.h"
#include "xwl/xwldatabridge.h"
#include "displayjack_clipboard.h"

extern "C"
{
#include "log.h"
#include "waylandclipboardprotocol.h"
#include "wayland-wlr-data-control-unstable-v1-client-protocol.h"
}

#include <wayland-client.h>

#include <poll.h>
#include <signal.h>
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/signalfd.h>
#include <sys/timerfd.h>
#include <time.h>
#include <unistd.h>
#include <algorithm>
#include <sys/wait.h>

#define TIMER_EVENT 2
#define SIGNAL_EVENT 1

WaylandClipboardProtocol *clip;

std::atomic<bool> g_clipTopstate{false};
ClipData *g_clipDataTop = nullptr;

int clean_up_entries = -1;
int watch_signals = -1;
int display_fd = -1;

// 全局变量，用于线程退出控制
WaylandClipboardProtocol *g_clip = NULL;
map<string, string> lastFormats;

vector<string> getWaylandFormats(WaylandClipboardProtocol *vClip)
{
    vector<string> t_arryStr;
    if (vClip->selection_s) {
        for (int i = 0; i < vClip->selection_s->num_types; i++) {
            t_arryStr.push_back(string(vClip->selection_s->types[i].type));
        }
    }
    return t_arryStr;
}

static void global_add(void *data, struct wl_registry *registry, uint32_t name,
                       const char *interface, uint32_t version)
{
    WaylandClipboardProtocol *vclip = (WaylandClipboardProtocol *)data;
    if (strcmp(interface, "zwlr_data_control_manager_v1") == 0) {
        vclip->cmng = (zwlr_data_control_manager_v1 *)wl_registry_bind(registry, name,
                                                                       &zwlr_data_control_manager_v1_interface, 1);
    } else if (strcmp(interface, "wl_seat") == 0) {
        vclip->seat = (wl_seat *)wl_registry_bind(registry, name, &wl_seat_interface, 5);
    }
}

static void global_remove(void *data, struct wl_registry *registry,
                          uint32_t name)
{
    /* Empty */
}

struct wl_registry_listener registry_listener = {
    .global = global_add,
    .global_remove = global_remove
};

static void prepare_read(struct wl_display *display)
{
    while (wl_display_prepare_read(display) != 0) {
        wl_display_dispatch_pending(display);
    }
    wl_display_flush(display);
}

void data_get_source(ClipData *clipD, source_buffer *src)
{
    vector<string> vMimeData = clipD->getMimeTypes();

    int vRecorderCount = clipD->getRecordCount();

    for (int i = 0; i < vRecorderCount; i++) {
        ClipDataRecord *vDataR = clipD->getRecordAt(i);
        if (!vDataR)
            continue;

        src->len[src->num_types] = ClipboardDataProcess::getDataLength(vDataR->getDataPath().c_str());

        if (src->len[src->num_types] < MAX_DATA_SIZE - READ_SIZE) {
            src->data[src->num_types] = Xmalloc(src->len[src->num_types]);
            vector<char> imageData = ClipboardDataProcess::getData(vDataR->getDataPath().c_str());
            memcpy(src->data[src->num_types], &imageData[0], src->len[src->num_types]);
        } else {
            src->data[src->num_types] = NULL;
        }

        src->types[src->num_types].type = Xstrdup(vDataR->getMimeType().c_str());
        memset(src->types[src->num_types].filepath, 0, FILIE_PATH);
        memcpy(src->types[src->num_types].filepath, vDataR->getDataPath().c_str(), vDataR->getDataPath().size());
        src->types[src->num_types].pos = src->num_types;

        src->num_types++;

        if (src->num_types >= MAX_MIME_TYPES)
            break;
    }
}

int WaylandClipDataCheck(void *arg)
{
    WaylandClipboardProtocol *pWayland = (WaylandClipboardProtocol *)arg;
    if (!pWayland || (pWayland->selection_o && pWayland->selection_o->buf != SELECTION))
        return -1;
    // 获取当前系统时间（毫秒）
    long long milliseconds = ClipboardDataProcess::getCurrentTime(); // 将时间转换为毫秒
    static long long lastOfferTime = 0;
    vector<string> curFormats = getWaylandFormats(pWayland);
    vector<string> t_lastFormats = ClipboardDataProcess::getMapKeys(lastFormats);
    std::sort(curFormats.begin(), curFormats.end());
    std::sort(t_lastFormats.begin(), t_lastFormats.end());
    bool listEqual = false;
    if (curFormats.size() == t_lastFormats.size()) {
        listEqual = std::equal(curFormats.begin(), curFormats.end(), t_lastFormats.begin());
    }

    // 两次offer的时间间隔小于500ms，且list相同，不处理
    if (milliseconds - lastOfferTime < 500 && listEqual) {
        lastOfferTime = ClipboardDataProcess::getCurrentTime();
        g_clipDataTop = SystemClipboard::getInstance().getActiveClipData();
        return -1;
    }
    lastOfferTime = ClipboardDataProcess::getCurrentTime();

    // 适配厂商云桌面粘贴问题
    if (ClipboardDataProcess::isContains(curFormats, "uos/remote-copy")) {
        log_error("Data from SHENXINFU_CLIPBOARD_MANAGER, ignored \n");
        return -2;
    }

    // 转移系统剪贴板所有权时造成的两次内容变化不需要显示，以下为与系统约定好的标识
    if (ClipboardDataProcess::isContains(curFormats, "FROM_DEEPIN_CLIPBOARD_MANAGER")) {
        log_error("Data from DEEPIN_CLIPBOARD_MANAGER, ignored \n");
        return -3;
    }
    lastFormats.clear();
    for (const auto &format : curFormats) {
        // if (format.find("image/") != std::string::npos && (ClipboardDataProcess::isContains(curFormats,"application/x-qt-image") ? true : "image/png" != format))
        lastFormats.insert(make_pair(format, string()));
    }
    return 0;
}

void *wayland_single_data_process(void *arg)
{
    WaylandClipboardProtocol *pWayland = (WaylandClipboardProtocol *)arg;
    if (!pWayland)
        return NULL;

    if (!pWayland->display)
        return NULL;
    pthread_setcanceltype(PTHREAD_CANCEL_ENABLE, NULL);
    pthread_setcancelstate(PTHREAD_CANCEL_DEFERRED, NULL);

    if (WaylandClipDataCheck(pWayland) == 0 && pWayland->selection_o->num_types > 0) {
        WaylandClip_Get_Selection(pWayland);
        WaylandClip_Sync_Buffers(pWayland);
        if (pWayland->datachange(pWayland) >= 0)
            WaylandClip_Set_Selection(pWayland);
    }
    return NULL;
}

void *wayland_data_process(void *arg)
{
    WaylandClipboardProtocol *pWayland = (WaylandClipboardProtocol *)arg;
    if (!pWayland)
        return NULL;

    if (!pWayland->display)
        return NULL;
    struct pollfd wait_for_events[] = {
        {.fd = display_fd, .events = POLLIN},
        {.fd = watch_signals, .events = POLLIN},
        {.fd = clean_up_entries, .events = POLLIN}
    };

    pthread_t t_id = -1;

    while (pWayland->lock) {
        prepare_read(pWayland->display);

        if (pWayland->selection_s->expired) {
            pWayland->clearflag = false;
            wl_display_cancel_read(pWayland->display);

            // if(t_id != -1)
            //   pthread_cancel(t_id);
            // pthread_create(&t_id,NULL,wayland_single_data_process,arg);
            // pthread_join(t_id,NULL);

            int vFlagState = WaylandClipDataCheck(pWayland);
            if (vFlagState == 0 && pWayland->selection_o->num_types > 0 && pWayland->selection_o->buf != PRIMARY) {
                WaylandClip_Get_Selection(pWayland);
                WaylandClip_Sync_Buffers(pWayland);
                int stateValue = pWayland->datachange(pWayland);
                if (stateValue >= 0 || stateValue == -5) {
                    WaylandClip_Set_Selection(pWayland);
                } else {
                    Offer_Clear(pWayland->selection_o);
                    pWayland->clearflag = true;
                }
            } else if (vFlagState == -1 && pWayland->selection_o->num_types > 0 && pWayland->selection_o->buf != PRIMARY && g_clipDataTop) {
                Source_Clear(pWayland->selection_s);
                Offer_Clear(pWayland->selection_o);
                data_get_source(g_clipDataTop, pWayland->selection_s);
                WaylandClip_Set_Selection(pWayland);
            } else {
                Offer_Clear(pWayland->selection_o);
                pWayland->clearflag = true;
            }
            prepare_read(pWayland->display);
            pWayland->selection_s->expired = false;
        }
        if (pWayland->clearflag) {
            wl_display_cancel_read(pWayland->display);
            if (pWayland->selection_o->num_types > 0) {
                int vFlagState = WaylandClipDataCheck(pWayland);
                if (vFlagState == 0 && pWayland->selection_o->buf != PRIMARY) {
                    WaylandClip_Get_Selection(pWayland);
                    WaylandClip_Sync_Buffers(pWayland);
                    int stateValue = pWayland->datachange(pWayland);
                    if (stateValue >= 0 || stateValue == -5) {
                        WaylandClip_Set_Selection(pWayland);
                        pWayland->clearflag = false;
                    } else {
                        Offer_Clear(pWayland->selection_o);
                    }
                } else if (vFlagState == -1  && pWayland->selection_o->buf != PRIMARY && g_clipDataTop) {
                    Source_Clear(pWayland->selection_s);
                    Offer_Clear(pWayland->selection_o);
                    data_get_source(g_clipDataTop, pWayland->selection_s);
                    WaylandClip_Set_Selection(pWayland);
                } else {
                    Offer_Clear(pWayland->selection_o);
                }
            }

            prepare_read(pWayland->display);
        }

        int eventStates = poll(wait_for_events, 3, 0);

        if (eventStates < 0) {
            fprintf(stderr, "Poll failed\n");
            wl_display_cancel_read(pWayland->display);
            return NULL;
        }

        if (eventStates == 0) {
            if (g_clipTopstate && g_clipDataTop) {
                wl_display_cancel_read(pWayland->display);
                Source_Clear(pWayland->selection_s);
                Offer_Clear(pWayland->selection_o);
                data_get_source(g_clipDataTop, pWayland->selection_s);
                WaylandClip_Set_Selection(pWayland);
                prepare_read(pWayland->display);
                g_clipTopstate = false;
                pWayland->clearflag = false;
            }
            wl_display_read_events(pWayland->display);
            usleep(10000);
            continue;
        }

        if (poll(&wait_for_events[SIGNAL_EVENT], 1, 0) > 0) {
            printf("Stopping Kaprica...\n");
            wl_display_cancel_read(pWayland->display);
            break;
        }

        if (poll(&wait_for_events[TIMER_EVENT], 1, 0) > 0) {
            /* Read just to clear the buffer */
            uint64_t tmp;
            read(clean_up_entries, &tmp, sizeof(uint64_t));
            printf("Removed  old entries\n");
        }

        wl_display_read_events(pWayland->display);
        pthread_testcancel();
    }
    return NULL;
}

void destoryWaylandClipboard(void *arg)
{
    WaylandClipboardProtocol *pWayland = (WaylandClipboardProtocol *)arg;
    if (!pWayland) {
        log_error("wayland backend has been destroyed \n");
        return;
    }
    if (clip->xwl) {
        // static_cast<XwlDataBridge*>(clip->xwl)->stop();
        delete clip->xwl;
        clip->xwl = NULL;
    }
    /* Cleanup that shouldn't be necessary but helps analyze with valgrind */
    close(watch_signals);
    close(clean_up_entries);
    if (pWayland->lock) {
        pthread_mutex_lock(&pWayland->cond_lock);
        pWayland->lock = false;
        pthread_mutex_unlock(&pWayland->cond_lock);

        // cancel pthread
        void *retval = NULL;
        pthread_cancel(pWayland->dispatch); // cancel
        pthread_join(pWayland->dispatch, &retval);
    }

    WaylandClip_Destroy(pWayland);
}
ClipData *compareData(WaylandClipboardProtocol *vClipPtr)
{
    ClipData *clipD = NULL;

    vector<string> curFormats = getWaylandFormats(vClipPtr);
    std::sort(curFormats.begin(), curFormats.end());

    int vDataCount = SystemClipboard::getInstance().getClipDataCount();
    bool flag = false;
    for (int i = 0; i < vDataCount; i++) {
        ClipData *vClip = SystemClipboard::getInstance().getClipDataAt(i);
        vector<string> t_lastFormats = vClip->getMimeTypes();
        std::sort(t_lastFormats.begin(), t_lastFormats.end());
        if (curFormats.size() != t_lastFormats.size()) {
            continue;
        }
        if (!std::equal(curFormats.begin(), curFormats.end(), t_lastFormats.begin())) {
            continue;
        }

        int vRecorderCount = vClip->getRecordCount();
        int vSameNum = 0;
        for (int j = 0; j < vRecorderCount; j++) {
            ClipDataRecord *vDataR = vClip->getRecordAt(j);
            if (!vDataR)
                continue;
            if (string(vClipPtr->selection_s->types[j].filepath).empty())
                continue;
            if (strcmp("TIMESTAMP", vClipPtr->selection_s->types[j].type) == 0 ||
                    ClipboardDataProcess::compareFiles(vDataR->getDataPath(), string(vClipPtr->selection_s->types[j].filepath))) {
                vSameNum++;
            }
        }

        if (vSameNum == vRecorderCount) {
            clipD = vClip;
            break;
        }
    }
    return clipD;
}

int WaylandClipDataChange(void *arg)
{
    WaylandClipboardProtocol *pWayland = (WaylandClipboardProtocol *)arg;
    if (!pWayland)
        return -1;
    if (pClipHandle) {
        //去掉add listener为空不存储数据
        if (!pClipHandle->ClipDataAddListener) {
            return -7;
        }
    }
    // 过滤重复数据
    // 对比上次粘贴的数据，如果一样就不再粘贴
    ClipData *vDataOld = compareData(pWayland);
    if (vDataOld) {
        int vDataCount = SystemClipboard::getInstance().getClipDataCount();
        bool flag = false;
        ClipData *vClip = SystemClipboard::getInstance().getClipDataAt(vDataCount - 1);
        if (vDataOld == vClip) {
            int cancelState = SystemClipboard::getInstance().cancelTopData();
            if (cancelState == 0) {
                vDataOld->getProperty()->setTimestamp(ClipboardDataProcess::getCurrentTime());
                SystemClipboard::getInstance().dataAddProcess(vDataCount - 1);
            }
            return -5;
        }
        Source_Clear(pWayland->selection_s);
        data_get_source(vDataOld, pWayland->selection_s);
        // WaylandClip_Set_Selection(clip);
        vDataOld->getProperty()->setTimestamp(ClipboardDataProcess::getCurrentTime());
        int index = SystemClipboard::getInstance().setDataTop(vDataOld);
        SystemClipboard::getInstance().dataDeleteProcess(vDataOld->getName());
        SystemClipboard::getInstance().dataAddProcess(index);
        if (clip->xwl) {
            static_cast<XwlDataBridge *>(clip->xwl)->setClipData(vDataOld);
        }
        log_info("Data is exits! \n");
        return 1;
    }

    vector<string> curFormats = getWaylandFormats(pWayland);
    long long lastOfferTime = ClipboardDataProcess::getCurrentTime();

    ClipDataProperty *t_dataProperty = new ClipDataProperty();
    ClipData *t_clipdata = new ClipData();
    t_clipdata->setProperty(t_dataProperty);

    string t_path = SystemClipboard::getInstance().getPath();
    map<string, string> &t_formatMap = t_dataProperty->getMimeTypes();

    offer_buffer *ofr = pWayland->selection_o;

    // 去除文本为空数据
    bool isTextempty = false;
    for (int i = 0; i < ofr->num_types; i++) {
        if (ofr->invalid_data[i])
            continue;
        if (ClipboardDataProcess::isContains(curFormats, "file") || ClipboardDataProcess::isContains(curFormats, "image")) {
            continue;
        } else {
            if (string(ofr->types[i].type) == "text/plain") {
                vector<char> t_str = ClipboardDataProcess::readText(ofr->types[i].filepath);
                if (t_str.empty()) {
                    isTextempty = true;
                }
            }
        }
    }

    if (isTextempty) {
        delete t_clipdata;
        t_clipdata = nullptr;
        return -6; // 文本为空删除掉，过滤文本数据错误情况
    }

    for (int i = 0; i < ofr->num_types; i++) {
        if (ofr->invalid_data[i])
            continue;

        ClipDataRecord *t_datarecord = new ClipDataRecord();
        t_datarecord->setMimeType(string(ofr->types[i].type));
        t_datarecord->setDataPath(string(ofr->types[i].filepath));
        // 图片类型的数据直接把数据拿出来，不去调用mimeData->data()方法，会导致很卡
        if (ClipboardDataProcess::isContains(curFormats, "image")) {
            vector<char> imageData = ClipboardDataProcess::readImage(ofr->types[i].filepath);

            if (imageData.empty()) {
                delete t_datarecord;
                t_datarecord = nullptr;
                continue;
            }

            int t_w = 0;
            int t_h = 0;
            int rw = 0;
            int rh = 0;
            vector<char> simageData = ImageDataProcess::scaleImage(imageData, string(ofr->types[i].type), t_w, t_h, rw, rh);
            if (simageData.empty()) {
                vector<char> t_str = ClipboardDataProcess::getLenData(ofr->types[i].filepath, TextSmalllen);
                t_datarecord->setData(&t_str[0], t_str.size());
            } else {
                ClipboardDataProcess::update_file_img_size(ofr->types[i].filepath, rw, rh);
                t_datarecord->setImageSize(t_w, t_h);
                t_datarecord->setData(&simageData[0], simageData.size());
                if (t_formatMap.empty()) {
                    int len = 0;
                    t_formatMap.insert(make_pair(ApplicationXQtImageLiteral, string(t_datarecord->getData(len))));
                    t_formatMap.insert(make_pair("TIMESTAMP", std::to_string(lastOfferTime)));
                }
            }

            t_datarecord->setDataType("Image");
        } else if (ClipboardDataProcess::isContains(curFormats, "file")) {
            if (string("x-dfm-copied/file-icons") == string(ofr->types[i].type)) {
                t_datarecord->setData("x-dfm-copied/file-icons", string("x-dfm-copied/file-icons").size());
                t_formatMap.insert(make_pair(string(ofr->types[i].type), ""));
            } else {
                vector<char> t_str = ClipboardDataProcess::readText(ofr->types[i].filepath);
                vector<string> t_urls = ClipboardDataProcess::splitString(t_str, "\n");
                for (size_t k = 0; k < t_urls.size(); k++) {
                    /* code */
                    if (t_urls[k].empty()) {
                        /* code */
                        t_urls.erase(t_urls.begin() + k);
                        k--;
                    }
                }
                if (t_urls.empty()) {
                    delete t_datarecord;
                    t_datarecord = nullptr;
                    continue;
                }
                t_datarecord->setData(&t_str[0], t_str.size());
                t_datarecord->setUri(t_urls);
                t_formatMap.insert(make_pair(string(ofr->types[i].type), string(t_str.begin(), t_str.end())));
            }
            t_datarecord->setDataType("File");
        } else {
            if (ClipboardDataProcess::isContains(curFormats, "text/plain")) {
                vector<char> t_str = ClipboardDataProcess::getLenData(ofr->types[i].filepath, TextSmalllen);
                t_datarecord->setData(&t_str[0], t_str.size());
                int val = static_cast<int>(t_str[0]);
                if (val == 0 && t_str.size() > 1) {
                    log_info("data is all 0!");
                    delete t_clipdata;
                    t_clipdata = nullptr;
                    return -6; // 文本为空删除掉，解决浦发银行flutter问题，规避办法
                }
                t_formatMap.insert(make_pair(string(ofr->types[i].type), string(t_str.begin(), t_str.end())));
                t_datarecord->setDataType("Text");
            } else if (ClipboardDataProcess::isContains(curFormats, "html")) {
                vector<char> t_str = ClipboardDataProcess::getLenData(ofr->types[i].filepath, TextSmalllen);
                t_datarecord->setData(&t_str[0], t_str.size());
                t_formatMap.insert(make_pair(string(ofr->types[i].type), string(t_str.begin(), t_str.end())));
                // t_datarecord->setDataType("Html");
                t_datarecord->setDataType("Text");
            } else {
                // 部分情况下，应用(目前有截图录屏)发送的图片只有一种格式，例如image/png
                // 在判断QMimeData::hasImage()时。因为缺少application/x-qt-image类型导致返回false,这里特殊处理一下
                if (ClipboardDataProcess::isContains(curFormats, "image/png")) {
                    vector<char> imageData = ClipboardDataProcess::readImage(ofr->types[i].filepath);

                    int t_w = 0;
                    int t_h = 0;
                    int rw = 0;
                    int rh = 0;
                    vector<char> simageData = ImageDataProcess::scaleImage(imageData, string(ofr->types[i].type), t_w, t_h, rw, rh);
                    if (simageData.empty()) {
                        delete t_datarecord;
                        t_datarecord = nullptr;
                        continue;
                    }
                    ClipboardDataProcess::update_file_img_size(ofr->types[i].filepath, rw, rh);
                    t_datarecord->setImageSize(t_w, t_h);
                    t_datarecord->setData(&simageData[0], simageData.size());

                    if (t_formatMap.empty()) {
                        ClipDataRecord *vDataRecord = new ClipDataRecord();
                        vDataRecord->setMimeType(ApplicationXQtImageLiteral);

                        vDataRecord->setImageSize(t_datarecord->getImgWidth(), t_datarecord->getImgHeight());
                        int len = 0;
                        char *vSmallData = t_datarecord->getData(len);

                        vDataRecord->setData(vSmallData, len);
                        vDataRecord->setDataType("Image");
                        vDataRecord->setDataPath(t_datarecord->getDataPath());
                        t_clipdata->addRecordData(vDataRecord);
                        t_formatMap.insert(make_pair(ApplicationXQtImageLiteral, string(vSmallData)));
                        t_formatMap.insert(make_pair("TIMESTAMP", std::to_string(lastOfferTime)));
                    }
                    t_datarecord->setDataType("Image");
                }
            }
        }

        t_clipdata->addRecordData(t_datarecord);
    }

    if (t_formatMap.empty()) {
        delete t_clipdata;
        t_clipdata = nullptr;
        return -4;
    }
    //去除文件拷贝过程发送空数据的场景 "File"
    if (t_clipdata->getRecordCount() == 1) {
        if (t_clipdata->getRecordAt(0)->getMimeType() == "x-dfm-copied/file-icons"
                && t_clipdata->getRecordAt(0)->getDataType() == "File") {
            delete t_clipdata;
            t_clipdata = nullptr;
            return -3;
        }
    }
    t_dataProperty->setTimestamp(ClipboardDataProcess::getCurrentTime());
    t_clipdata->setDataState(true);
    t_clipdata->setName(std::to_string(ClipboardDataProcess::getCurrentTime()) + "_clip");
    int index = SystemClipboard::getInstance().addClipData(t_clipdata);
    if (clip->xwl) {
        static_cast<XwlDataBridge *>(clip->xwl)->setClipData(t_clipdata);
    }

    SystemClipboard::getInstance().dataAddProcess(index);
    return 0;
}

void initProtocol(void *ptr)
{
    WaylandClipboard *wClipboard = (WaylandClipboard *)ptr;
    clip = WaylandClip_Init();
    clip->xwl = wClipboard->getXwl();

    clip->display = wl_display_connect(NULL);
    clip->clipDatapath = wClipboard->getPathDir();
    if (!clip->display) {
        fprintf(stderr, "Failed to create display\n");
        return;
    }

    sigset_t mask;
    sigemptyset(&mask);
    sigaddset(&mask, SIGINT);
    sigaddset(&mask, SIGTERM);
    if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1) {
        fprintf(stderr, "Failed to mask signals\n");
        return;
    }

    clean_up_entries = timerfd_create(CLOCK_MONOTONIC, 0);
    struct timespec five_minutes = {.tv_sec = 300};
    struct itimerspec timer = {.it_interval = five_minutes,
               .it_value = five_minutes
    };
    timerfd_settime(clean_up_entries, 0, &timer, NULL);

    watch_signals = signalfd(-1, &mask, 0);
    display_fd = wl_display_get_fd(clip->display);

    struct wl_registry *registry = wl_display_get_registry(clip->display);
    wl_registry_add_listener(registry, &registry_listener, (void *)clip);

    wl_display_roundtrip(clip->display);
    if (!clip->cmng) {
        fprintf(stderr, "wlr-data-control not supported\n");
        return;
    }

    clip->dmng = zwlr_data_control_manager_v1_get_data_device(clip->cmng, clip->seat);

    WaylandClip_Watch(clip);
    wl_display_roundtrip(clip->display);

    clip->lock = false;
    clip->clearflag = true;
    clip->datachange = &WaylandClipDataChange;
    // if (!clip->selection_s->num_types)
    // {
    //     WaylandClip_Get_Selection(clip);
    //     WaylandClip_Sync_Buffers(clip);
    //     // clip->datachange(clip);
    // }
    // WaylandClip_Set_Selection(clip);
}

WaylandClipboard::WaylandClipboard(SystemClipboard *clipboard, char *path)
{
    m_systemclipboard = clipboard;
    m_pathDir = path;
    initXwl();
    initProtocol(this);
}

WaylandClipboard::~WaylandClipboard()
{
    if (m_pid > 0) {
        kill(m_pid, SIGTERM);
        wait(NULL);
    }
    destoryWaylandClipboard(clip);
}
struct waylandclipboard_data {
    WaylandClipboardProtocol *pwayland;
    ClipData *vClip;
};

void sigterm_handler(int signum)
{
    if (signum != SIGTERM)
        return;
    if (g_clip != NULL) {
        pthread_mutex_lock(&g_clip->cond_lock);
        g_clip->lock = false;
        pthread_mutex_unlock(&g_clip->cond_lock);
        // cancel pthread
        void *retval = NULL;
        pthread_cancel(g_clip->dispatch); // cancel
    }
}

void *wayland_data_set(void *arg)
{
    waylandclipboard_data *t_data = (waylandclipboard_data *)arg;
    if (!t_data)
        return NULL;
    Source_Clear(t_data->pwayland->selection_s);
    data_get_source(t_data->vClip, t_data->pwayland->selection_s);
    WaylandClip_Set_Selection(t_data->pwayland);

    while (t_data->pwayland->lock) {
        wl_display_dispatch(t_data->pwayland->display);
        pthread_testcancel();
    }
    return NULL;
}

void WaylandClipboard::setDataToClipboard(ClipData *vClip, bool flag)
{
    ClipDataProperty *vClipProperty = vClip->getProperty();
    int vDataCount = vClip->getRecordCount();
    if (vDataCount < 1 || !vClipProperty)
        return;

    if (flag) {
        if (clip->xwl) {
            static_cast<XwlDataBridge *>(clip->xwl)->setClipData(vClip);
        }
    }

    g_clipDataTop = vClip;
    g_clipTopstate = true;
    return;
    if (m_pid < 0) {
        forkProcessData(vClip, flag);
    } else {
        kill(m_pid, SIGTERM);
        wait(NULL);
        forkProcessData(vClip, flag);
    }
}

void WaylandClipboard::forkProcessData(ClipData *vClip, bool flag)
{
    m_pid = fork();
    if (m_pid < 0) {
        log_error("create fork faild \n");
        exit(EXIT_FAILURE);
    } else if (m_pid == 0) {
        if (clip != NULL) {
            if (clip->lock) {
                // pthread_mutex_lock(&clip->cond_lock);
                // clip->lock = false;
                // pthread_mutex_unlock(&clip->cond_lock);

                // cancel pthread
                void *retval = NULL;
                pthread_cancel(clip->dispatch); // cancel
                pthread_join(clip->dispatch, &retval);
            }
        }
        sigset(SIGTERM, sigterm_handler);
        if (g_clip == NULL) {
            g_clip = WaylandClip_Init();

            g_clip->display = wl_display_connect(NULL);

            struct wl_registry *registry = wl_display_get_registry(g_clip->display);
            wl_registry_add_listener(registry, &registry_listener, (void *)g_clip);

            wl_display_roundtrip(g_clip->display);
            if (!g_clip->cmng) {
                log_error("wlr-data-control not supported\n");
                return;
            }

            g_clip->dmng = zwlr_data_control_manager_v1_get_data_device(g_clip->cmng, g_clip->seat);
            g_clip->lock = true;
        }
        waylandclipboard_data tt;
        tt.pwayland = g_clip;
        tt.vClip = vClip;
        pthread_mutex_init(&g_clip->cond_lock, NULL);
        pthread_create(&g_clip->dispatch, NULL, wayland_data_set, &tt);

        // 等待线程结束
        if (pthread_join(g_clip->dispatch, NULL)) {
            log_error("pthread_join faild\n");
            exit(EXIT_FAILURE);
        }
        WaylandClip_ForkDestroy(g_clip);
        log_info("fork process exit! \n");
        // exit(0); // 子进程结束
        _Exit(0);
    }
}

void WaylandClipboard::clearClipboard()
{
    if (m_XwlDataBrige) {
        m_XwlDataBrige->setClipData(NULL);
    }
    if (clip) {
        wayland_clip_clear_selection(clip);
        Offer_Clear(clip->selection_o);
        wl_display_flush(clip->display);
        clip->clearflag = true;
    }
}

void WaylandClipboard::initConnect()
{
    clip->lock = true;
    pthread_mutex_init(&clip->cond_lock, NULL);
    pthread_create(&clip->dispatch, NULL, wayland_data_process, clip);
}

char *WaylandClipboard::getPathDir()
{
    return m_pathDir;
}

void *WaylandClipboard::getXwl()
{
    return m_XwlDataBrige;
}

void *xwl_loop(void *arg)
{
    XwlDataBridge *t_data = (XwlDataBridge *)arg;
    t_data->eventLoop();
    return NULL;
}

void WaylandClipboard::initXwl()
{
    m_XwlDataBrige = new XwlDataBridge;
    pthread_create(&m_xwldispatch, NULL, xwl_loop, m_XwlDataBrige);
}
