/*
 * Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU  Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see <http://www.gnu.org/licenses/&gt;.
 *
 */


// Warning: order of those include is important.
#include <QDebug>
#include <QApplication>
#include <QResizeEvent>
#include <QPainter>
#include <QBitmap>
#include <QStyle>
#include <QScreen>
#include <QDrag>
#include <QImage>

#include "../panel/ukuipanel.h"
#include "trayicon.h"
#include "xfitman.h"

#include <QtX11Extras/QX11Info>
#include <X11/Xatom.h>
#include <X11/Xutil.h>
#include <X11/extensions/Xcomposite.h>
#include <X11/extensions/Xrender.h>
#include "qmath.h"
#include <QToolButton>
#define XEMBED_EMBEDDED_NOTIFY 0


//适配高分屏
#include<X11/Xlib.h>
#include<X11/keysym.h>
#include<X11/Xutil.h>
#include<X11/extensions/XTest.h>


#define FONT_RENDERING_DPI               "org.ukui.SettingsDaemon.plugins.xsettings"
#define SCALE_KEY                        "scaling-factor"


static bool xError;
#define MIMETYPE "ukui/UkuiTray"

#define CSETTINGS_SCALING "org.ukui.SettingsDaemon.plugins.xsettings"
#define SCALING_FACTOR    "scalingFactor"

#define ORG_UKUI_STYLE            "org.ukui.style"
#define STYLE_NAME                "styleName"
#define STYLE_NAME_KEY_DARK       "ukui-dark"
#define STYLE_NAME_KEY_DEFAULT    "ukui-default"
#define STYLE_NAME_KEY_UKUI       "ukui"
#define STYLE_NAME_KEY_BLACK       "ukui-black"
#define STYLE_NAME_KEY_LIGHT       "ukui-light"
#define STYLE_NAME_KEY_WHITE       "ukui-white"

int windowErrorHandler(Display *d, XErrorEvent *e)
{
    xError = true;
    if (e->error_code != BadWindow) {
        char str[1024];
        XGetErrorText(d, e->error_code,  str, 1024);
        qWarning() << "Error handler" << e->error_code
                   << str;
    }
    return 0;
}


/************************************************

 ************************************************/
TrayIcon::TrayIcon(Window iconId, QSize const & iconSize, QWidget* parent):
    QToolButton(parent),
    mIconId(iconId),
    mWindowId(0),
    mIconSize(iconSize),
    mDamage(0),
    mDisplay(QX11Info::display())
{
    /*
     * NOTE:
     * 如果不保存QX11Info::display()的返回值，ukui-panel会有潜在崩溃问题
     * it's a good idea to save the return value of QX11Info::display().
     * In Qt 5, this API is slower and has some limitations which can trigger crashes.
     * The XDisplay value is actally stored in QScreen object of the primary screen rather than
     * in a global variable. So when the parimary QScreen is being deleted and becomes invalid,
     * QX11Info::display() will fail and cause crash. Storing this value improves the efficiency and
     * also prevent potential crashes caused by this bug.
    */

    traystatus=NORMAL;
    setObjectName("TrayIcon");
    setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

    setAcceptDrops(false);

    QTimer::singleShot(200, [this] { init(); update(); });
    repaint();

    /**/
    QDBusConnection::sessionBus().unregisterService("com.ukui.panel");
    QDBusConnection::sessionBus().registerService("com.ukui.panel");
    QDBusConnection::sessionBus().registerObject("/traybutton/click", this,QDBusConnection :: ExportAllSlots | QDBusConnection :: ExportAllSignals);

    const QByteArray scaling_factor(CSETTINGS_SCALING);
    if(QGSettings::isSchemaInstalled(scaling_factor)) {
        scaling_settings = new QGSettings(scaling_factor);
        qDebug()<<"scaling_settings->get(SCALING_FACTOR).toInt()"<<scaling_settings->get(SCALING_FACTOR).toInt();
    }

    const QByteArray id(ORG_UKUI_STYLE);
    QStringList stylelist;
    stylelist<<STYLE_NAME_KEY_DARK<<STYLE_NAME_KEY_BLACK<<STYLE_NAME_KEY_DEFAULT<<STYLE_NAME_KEY_UKUI;
    if(QGSettings::isSchemaInstalled(id)){
        gsettings = new QGSettings(id);
        if(stylelist.contains(gsettings->get(STYLE_NAME).toString()))
            dark_style=true;
        else
            dark_style=false;
    }
    connect(gsettings, &QGSettings::changed, this, [=] (const QString &key){
        if(key==STYLE_NAME){
            if(stylelist.contains(gsettings->get(STYLE_NAME).toString()))
                dark_style=true;
            else
                dark_style=false;
            repaint();
        }
    });

    const QByteArray System_Palette_id(FONT_RENDERING_DPI);
    if(QGSettings::isSchemaInstalled(System_Palette_id)){
        //this->update();
        System_scale_gsettings = new QGSettings(System_Palette_id);
        scale = System_scale_gsettings->get(SCALE_KEY).toFloat();
        qDebug()<<"scale is "<<scale;

        connect(System_scale_gsettings, &QGSettings::changed, this, [=] (const QString &key){
            if(key == "styleName")
            {
                scale = System_scale_gsettings->get(SCALE_KEY).toFloat();
                qDebug()<<"scale is "<<scale;
                this->update();
            }
        });
    }
}



/************************************************

 ************************************************/
void TrayIcon::init()
{
    Display* dsp = mDisplay;

    XWindowAttributes attr;
    if (! XGetWindowAttributes(dsp, mIconId, &attr))
    {
        deleteLater();
        return;
    }

    //        qDebug() << "New tray icon ***********************************";
    //        qDebug() << "  * window id:  " << hex << mIconId;
            qDebug() << "Plugin-Tray Get Tray App Name :: " << xfitMan().getApplicationName(mIconId);
    //        qDebug() << "  * size (WxH): " << attr.width << "x" << attr.height;
    //        qDebug() << "  * color depth:" << attr.depth;

    unsigned long mask = 0;
    XSetWindowAttributes set_attr;

    Visual* visual = attr.visual;
    set_attr.colormap = attr.colormap;
    set_attr.background_pixel = 0;
    set_attr.border_pixel = 0;
    mask = CWColormap|CWBackPixel|CWBorderPixel;

    const QRect icon_geom = iconGeometry();
    mWindowId = XCreateWindow(dsp, this->winId(), icon_geom.x(), icon_geom.y(), icon_geom.width() * metric(PdmDevicePixelRatio), icon_geom.height() * metric(PdmDevicePixelRatio),
                              0, attr.depth, InputOutput, visual, mask, &set_attr);


    xError = false;
    XErrorHandler old;
    old = XSetErrorHandler(windowErrorHandler);
    XReparentWindow(dsp, mIconId, mWindowId, 0, 0);
    XSync(dsp, false);
    XSetErrorHandler(old);

    if (xError)
    {
        qWarning() << "* Not icon_swallow                     *";
        XDestroyWindow(dsp, mWindowId);
        mWindowId = 0;
        deleteLater();
        return;
    }
    {
        Atom acttype;
        int actfmt;
        unsigned long nbitem, bytes;
        unsigned char *data = 0;
        int ret;

        ret = XGetWindowProperty(dsp, mIconId, xfitMan().atom("_XEMBED_INFO"),
                                 0, 2, false, xfitMan().atom("_XEMBED_INFO"),
                                 &acttype, &actfmt, &nbitem, &bytes, &data);
        if (ret == Success)
        {
            if (data)
                XFree(data);
        }
        else
        {
            qWarning() << "TrayIcon: xembed error";
            XDestroyWindow(dsp, mWindowId);
            deleteLater();
            return;
        }
    }

    {
        XEvent e;
        e.xclient.type = ClientMessage;
        e.xclient.serial = 0;
        e.xclient.send_event = True;
        e.xclient.message_type = xfitMan().atom("_XEMBED");
        e.xclient.window = mIconId;
        e.xclient.format = 32;
        e.xclient.data.l[0] = CurrentTime;
        e.xclient.data.l[1] = XEMBED_EMBEDDED_NOTIFY;
        e.xclient.data.l[2] = 0;
        e.xclient.data.l[3] = mWindowId;
        e.xclient.data.l[4] = 0;
        XSendEvent(dsp, mIconId, false, 0xFFFFFF, &e);
    }

    XSelectInput(dsp, mIconId, StructureNotifyMask);
    mDamage = XDamageCreate(dsp, mIconId, XDamageReportRawRectangles);
    XCompositeRedirectWindow(dsp, mWindowId, CompositeRedirectManual);

    XMapWindow(dsp, mIconId);
    XMapRaised(dsp, mWindowId);

    const QSize req_size{mIconSize * metric(PdmDevicePixelRatio)};
    XResizeWindow(dsp, mIconId, req_size.width(), req_size.height());
}


/************************************************

 ************************************************/
TrayIcon::~TrayIcon()
{
    Display* dsp = mDisplay;
    XSelectInput(dsp, mIconId, NoEventMask);

    if (mDamage)
        XDamageDestroy(dsp, mDamage);

    // reparent to root
    xError = false;
    XErrorHandler old = XSetErrorHandler(windowErrorHandler);

    XUnmapWindow(dsp, mIconId);
    XReparentWindow(dsp, mIconId, QX11Info::appRootWindow(), 0, 0);

    if (mWindowId)
        XDestroyWindow(dsp, mWindowId);
    XSync(dsp, False);
    XSetErrorHandler(old);
}


/************************************************

 ************************************************/
QSize TrayIcon::sizeHint() const
{
    QMargins margins = contentsMargins();
    return QSize(margins.left() + mIconSize.width() + margins.right(),
                 margins.top() + mIconSize.height() + margins.bottom()
                 );
}


/************************************************

 ************************************************/
void TrayIcon::setIconSize(QSize iconSize)
{
    mIconSize = iconSize;

    const QSize req_size{mIconSize * metric(PdmDevicePixelRatio)};
    if (mWindowId)
        xfitMan().resizeWindow(mWindowId, req_size.width(), req_size.height());

    if (mIconId)
        xfitMan().resizeWindow(mIconId, req_size.width(), req_size.height());
}

/*处理　TrayIcon　绘图，点击等事件*/
bool TrayIcon::event(QEvent *event)
{
    if (mWindowId)
    {
        switch (event->type())
        {
        case QEvent::Paint:
            /*必须在draw函数中绘制图标，若在paintEvent中绘制则XGetImage 会出错*/
            draw(static_cast<QPaintEvent*>(event));
            break;

        case QEvent::Move:
        case QEvent::Resize:
        {
            QRect rect = iconGeometry();
            xfitMan().moveWindow(mWindowId, rect.left(), rect.top());
        }
            break;

        case QEvent::MouseButtonPress:
            //            trayButtonPress(static_cast<QMouseEvent*>(event));
            //            break;
            //trayButtonCoordinateMapping(x_panel,y_panel);
//            break;
        case QEvent::MouseButtonRelease:
        case QEvent::MouseButtonDblClick:
            event->accept();
            break;
        case QEvent::ContextMenu:
            //            moveMenu();
            break;
        case QEvent::Enter:
            //            this->setToolTip("右键可选择移入任务栏/收纳");
            break;
        default:
            break;
        }
    }

    return QToolButton::event(event);
}


/************************************************

 ************************************************/
QRect TrayIcon::iconGeometry()
{
    QRect res = QRect(QPoint(0, 0), mIconSize);

    res.moveCenter(QRect(0, 0, width(), height()).center());
    return res;
}

/**
 * @brief needReDraw 判断图标是否需要重新绘制（高亮处理）
 * @return 不需要重新绘制的图标返回值为false
 * 备注：ukui3.1 主题提供两套图标后，任务栏不需要进行重新绘制
 */
bool TrayIcon::needReDraw()
{
    QStringList ignoreAppList;
    ignoreAppList<<"kylin-video";
    if(ignoreAppList.contains(xfitMan().getApplicationName(mIconId))){
        return false;
    }
    return true;
}

/*draw 函数执行的是绘图事件*/
void TrayIcon::draw(QPaintEvent* /*event*/)
{
    Display* dsp = mDisplay;

    XWindowAttributes attr;
    if (!XGetWindowAttributes(dsp, mIconId, &attr))
    {
        qWarning() << "Paint error";
        return;
    }

    QImage image;
    XImage* ximage = XGetImage(dsp, mIconId, 0, 0, attr.width, attr.height, AllPlanes, ZPixmap);
    if(ximage)
    {
        image = QImage((const uchar*) ximage->data, ximage->width, ximage->height, ximage->bytes_per_line,  QImage::Format_ARGB32_Premultiplied);
    }
    else
    {
        qWarning() << "    * Error image is NULL";

        XClearArea(mDisplay, (Window)winId(), 0, 0, attr.width, attr.height, False);
        // for some unknown reason, XGetImage failed. try another less efficient method.
        // QScreen::grabWindow uses XCopyArea() internally.
        image = qApp->primaryScreen()->grabWindow(mIconId).toImage();
    }

    //    qDebug() << "Paint icon **************************************";
    //    qDebug() << "  * XComposite: " << isXCompositeAvailable();
    //    qDebug() << "  * Icon geometry:" << iconGeometry();
    //    qDebug() << "  Icon";
    //    qDebug() << "    * window id:  " << hex << mIconId;
    //    qDebug() << "    * window name:" << xfitMan().getName(mIconId);
    //    qDebug() << "    * size (WxH): " << attr.width << "x" << attr.height;
    //    qDebug() << "    * pos (XxY):  " << attr.x << attr.y;
    //    qDebug() << "    * color depth:" << attr.depth;
    //    qDebug() << "  XImage";
    //    qDebug() << "    * size (WxH):  " << ximage->width << "x" << ximage->height;
    //    switch (ximage->format)
    //    {
    //        case XYBitmap: qDebug() << "    * format:   XYBitmap"; break;
    //        case XYPixmap: qDebug() << "    * format:   XYPixmap"; break;
    //        case ZPixmap:  qDebug() << "    * format:   ZPixmap"; break;
    //    }
    //    qDebug() << "    * color depth:  " << ximage->depth;
    //    qDebug() << "    * bits per pixel:" << ximage->bits_per_pixel;

    QPainter painter(this);
    QRect iconRect = iconGeometry();
    if (image.size() != iconRect.size())
    {
        image = image.scaled(iconRect.size(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
        QRect r = image.rect();
        r.moveCenter(iconRect.center());
        iconRect = r;
    }

    if(needReDraw())
        //        image=HighLightEffect::drawSymbolicColoredPixmap(QPixmap::fromImage(image)).toImage();
        image = drawSymbolicColoredPixmap(QPixmap::fromImage(image)).toImage();
    painter.setRenderHints(QPainter::SmoothPixmapTransform);
    painter.setRenderHints(QPainter::Antialiasing, true);

    painter.drawImage(iconRect, image);

    if(ximage)
        XDestroyImage(ximage);
}

/*关于点击托盘应用的非图标区域实现打开托盘应用*/
void TrayIcon::trayButtonPress(QMouseEvent* /*event*/)
{
    //qDebug() << "    * window name:" << xfitMan().getApplicationName(mIconId);
    /* 需要此点击信号的应用需要做如下绑定
     * QDBusConnection::sessionBus().connect(QString(), QString("/traybutton/click"),  "com.ukui.panel.plugins.tray", "ClickTrayApp", this, SLOT(clientGet(void)));
     * 在槽函数clientGet(void)　中处理接受到的点击信号
     */
    QDBusMessage message =QDBusMessage::createSignal("/traybutton/click", "com.ukui.panel.plugins.tray", "ClickTrayApp");
    message<<xfitMan().getApplicationName(mIconId);
    QDBusConnection::sessionBus().send(message);
}

/*关于点击托盘应用的非图标区域实现打开托盘应用*/
void TrayIcon::trayButtonCoordinateMapping(int x_click,int y_click)//QMouseEvent* /*event*/,
{
    XEvent event;
    Display *dpy = XOpenDisplay(NULL);
    if(dpy == NULL){
        return ;
    }
    /* get info about current pointer position */
    XQueryPointer(dpy, RootWindow(dpy, DefaultScreen(dpy)),
                  &event.xbutton.root, &event.xbutton.window,
                  &event.xbutton.x_root, &event.xbutton.y_root,
                  &event.xbutton.x, &event.xbutton.y,
                  &event.xbutton.state);

    QPoint x_desktop=QCursor::pos();
    qDebug()<<"实际点击的位置"<<x_desktop;

    //现阶段需要根据不同的分辨率进行分析，后期合并
    if (scale == 1){
        int mid_icon_click_w=width()/2;// tray icon position
        int mid_icon_click_h=height()/2;

        qDebug()<<"*************************************";
        qDebug()<<"200  icon position"<<mid_icon_click_w<<mid_icon_click_h;
        qDebug()<<"x_click :   x_click  :"<<x_click<<y_click;
        qDebug()<<"width  :    height  :"<<width()<<height();

        if (x_click<=width()/2&&y_click<height()/2){
            x=x_desktop.x()+qAbs(x_click-mid_icon_click_w);
            y=x_desktop.y()+qAbs(y_click-mid_icon_click_h);
        }else if(x_click>width()/2&&y_click<height()/2){
            x=x_desktop.x()-qAbs(x_click-mid_icon_click_w);
            y=x_desktop.y()+qAbs(y_click-mid_icon_click_h);
        }else if(x_click<width()/2&&y_click>height()/2){
            x=x_desktop.x()+qAbs(x_click-mid_icon_click_w);
            y=x_desktop.y()-qAbs(y_click-mid_icon_click_h);
        }else if (x_click>width()/2&&y_click>=height()/2){
            x=x_desktop.x()-qAbs(x_click-mid_icon_click_w);
            y=x_desktop.y()-qAbs(y_click-mid_icon_click_h);
        }else{
            qDebug()<<"no change click position";
        }
        qDebug()<<"position right_down x  "<<x_desktop.x()<<x_click<<mid_icon_click_w<<x;
        qDebug()<<"position right_down y  "<<x_desktop.y()<<y_click<<mid_icon_click_h<<y;

    }else if(scale == 2){
        int mid_icon_click_w=width()/2;// tray icon position
        int mid_icon_click_h=height()/2;
        qDebug()<<"*************************************";
        qDebug()<<"scale == 1"<<mid_icon_click_w<<mid_icon_click_h;
        qDebug()<<"x_click :   x_click  :"<<x_click<<y_click;
        qDebug()<<"width  :    height  :"<<width()<<height();
        if (x_click<=width()/2&&y_click<height()/2){
            x=x_desktop.x()*2+qAbs(x_click*2-mid_icon_click_w);
            y=x_desktop.y()*2+qAbs(y_click*2-mid_icon_click_h);
        }else if(x_click>width()/2&&y_click<height()/3){
            x=x_desktop.x()*2-qAbs(x_click*2-mid_icon_click_w);
            y=x_desktop.y()*2-qAbs(y_click*2-mid_icon_click_h);
        }else if(x_click<width()/2&&y_click>height()/2){
            x=x_desktop.x()*2+qAbs(x_click*2-mid_icon_click_w);
            y=x_desktop.y()*2-qAbs(y_click*2-mid_icon_click_h);
        }else if (x_click>width()/2&&y_click>=height()/2){
            x=x_desktop.x()*2-qAbs(x_click*2-mid_icon_click_w);
            y=x_desktop.y()*2-qAbs(y_click*2-mid_icon_click_h);
        }else{
            qDebug()<<"no change click position";
        }
        qDebug()<<"position right_down x  "<<x_desktop.x()<<x_click<<mid_icon_click_w<<x;
        qDebug()<<"position right_down y  "<<x_desktop.y()<<y_click<<mid_icon_click_h<<y;
    }else if( 1< scale < 2){
        int mid_icon_click_w=width()/scale;// tray icon position
        int mid_icon_click_h=height()/scale;
        qDebug()<<"*************************************";
        qDebug()<<"  1< scale < 2"<<mid_icon_click_w<<mid_icon_click_h;
        qDebug()<<"x_click :   x_click  scale  ::"<<x_click<<y_click<<scale;
        qDebug()<<"width  :    height  :"<<width()<<height();
        if (x_click<=width()/2&&y_click<height()/2){
            x=x_desktop.x()*scale+qAbs(x_click*scale-mid_icon_click_w);
            y=x_desktop.y()*scale+qAbs(y_click*scale-mid_icon_click_h);
        }else if(x_click>width()/2&&y_click<height()/2){
            x=x_desktop.x()*scale-qAbs(x_click*scale-mid_icon_click_w);
            y=x_desktop.y()*scale-qAbs(y_click*scale-mid_icon_click_h);
        }else if(x_click<width()/2&&y_click>height()/2){
            x=x_desktop.x()*scale+qAbs(x_click*scale-mid_icon_click_w);
            y=x_desktop.y()*scale-qAbs(y_click*scale-mid_icon_click_h);
        }else if (x_click>width()/2&&y_click>=height()/2){
            x=x_desktop.x()*scale-qAbs(x_click*scale-mid_icon_click_w);
            y=x_desktop.y()*scale-qAbs(y_click*scale-mid_icon_click_h);
        }else{
            qDebug()<<"no change click position";
        }
        qDebug()<<"position right_down x  "<<x_desktop.x()<<x_click<<mid_icon_click_w<<x;
        qDebug()<<"position right_down y  "<<x_desktop.y()<<y_click<<mid_icon_click_h<<y;
    }

    XTestFakeMotionEvent(dpy, -1, x, y, 0);
    XTestFakeButtonEvent(dpy, 1, 1, 0);
    XTestFakeButtonEvent(dpy, 1, 0, 0);
    QElapsedTimer t;
    t.start();
    while(t.elapsed()<200);
    XSetInputFocus(mDisplay, mWindowId,RevertToPointerRoot,CurrentTime);
    /* place the mouse where it was */
    XTestFakeMotionEvent(dpy, -1, event.xbutton.x, event.xbutton.y, 0);
    XCloseDisplay(dpy);

}

void TrayIcon::windowDestroyed(Window w)
{
    //damage is destroyed if it's parent window was destroyed
    if (mIconId == w)
        mDamage = 0;
}


/************************************************

 ************************************************/
bool TrayIcon::isXCompositeAvailable()
{
    int eventBase, errorBase;
    return XCompositeQueryExtension(QX11Info::display(), &eventBase, &errorBase );
}

/*enterEvent 和leaveEvent是用来处理traystatus的*/
void TrayIcon::enterEvent(QEvent *)
{
    traystatus=HOVER;
    update();
}

void TrayIcon::leaveEvent(QEvent *)
{
    traystatus=NORMAL;
    update();
}

void TrayIcon::paintEvent(QPaintEvent *)
{
    QStyleOption opt;
    opt.initFrom(this);
    QPainter p(this);

    switch(traystatus)
    {
    case NORMAL:
    {
        //                          p.setBrush(QBrush(QColor(0x00,0xFF,0x00,0x19)));
        p.setPen(Qt::NoPen);
        break;
    }
    case HOVER:
    {
        //p.setBrush(QBrush(QColor(0xff,0xff,0xff,0x1f)));
        p.setPen(Qt::NoPen);
        break;
    }
    case PRESS:
    {
        //p.setBrush(QBrush(QColor(0xff,0xff,0xff,0x0f)));
        p.setPen(Qt::NoPen);
        break;
    }
    }
    p.setRenderHint(QPainter::Antialiasing);  // 反锯齿;
    const QSize req_size{mIconSize * metric(PdmDevicePixelRatio)};
    xfitMan().resizeWindow(mWindowId, req_size.width(), req_size.height());
    p.drawRoundedRect(opt.rect.x(),opt.rect.y(),width(),height(),8,8);
    style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}

QPixmap TrayIcon::drawSymbolicColoredPixmap(const QPixmap &source)
{
    QColor standard (31,32,34);
    QImage img = source.toImage();
    for (int x = 0; x < img.width(); x++) {
        for (int y = 0; y < img.height(); y++) {
            auto color = img.pixelColor(x, y);
            if (color.alpha() > 0) {
                if(dark_style && qAbs(color.red()-standard.red())<20 && qAbs(color.green()-standard.green())<20 && qAbs(color.blue()-standard.blue())<20){
                    color.setRed(255);
                    color.setGreen(255);
                    color.setBlue(255);
                    //                    color.setRgb(255,255,255);
                    img.setPixelColor(x, y, color);
                }
                else{
                    img.setPixelColor(x, y, color);
                }
            }
        }
    }
    return QPixmap::fromImage(img);
}

void TrayIcon::moveMenu()
{

    menu =new QMenu(this);
    menu->setAttribute(Qt::WA_DeleteOnClose);
    QAction *action;
    action = menu->addAction(tr("移入任务栏/收纳"));
    connect(action, &QAction::triggered, [this] { emit iconIsMoving(mIconId);});
    menu->setGeometry(caculateMenuWindowPos(QCursor::pos(), menu->sizeHint()));
    menu->show();
}

void TrayIcon::notifyAppFreeze()
{
    emit notifyTray(mIconId);
}

void TrayIcon::emitIconId()
{
    emit iconIsMoving(mIconId);
}

QRect TrayIcon::caculateMenuWindowPos(const QPoint &absolutePos, const QSize &windowSize)
{
    int x = absolutePos.x(), y = absolutePos.y();

    QRect res(QPoint(x, y), windowSize);

    QRect screen = QApplication::desktop()->screenGeometry(this);
    // NOTE: We cannot use AvailableGeometry() which returns the work area here because when in a
    // multihead setup with different resolutions. In this case, the size of the work area is limited
    // by the smallest monitor and may be much smaller than the current screen and we will place the
    // menu at the wrong place. This is very bad for UX. So let's use the full size of the screen.
    if (res.right() > screen.right())
        res.moveRight(screen.right());

    if (res.bottom() > screen.bottom())
        res.moveBottom(screen.bottom());

    if (res.left() < screen.left())
        res.moveLeft(screen.left());

    if (res.top() < screen.top())
        res.moveTop(screen.top());

    return res;
}

#if 1
void TrayIcon::mouseMoveEvent(QMouseEvent *e)
{
    if (e->button() == Qt::RightButton)
        return;
    if (!(e->buttons() & Qt::LeftButton))
        return;
    if ((e->pos() - mDragStart).manhattanLength() < QApplication::startDragDistance())
        return;

    if (e->modifiers() == Qt::ControlModifier)
    {
        return;
    }
    QDrag *drag = new QDrag(this);
    QIcon ico = icon();
    int size = 16;
    QPixmap img = ico.pixmap(ico.actualSize({size, size}));

    drag->setMimeData(mimeData());
    drag->setPixmap(img);

    drag->setHotSpot(img.rect().bottomRight());


    drag->exec();
    drag->deleteLater();

    QAbstractButton::mouseMoveEvent(e);
}

void TrayIcon::dragMoveEvent(QDragMoveEvent * e)
{
    emit iconIsMoving(mIconId);
    if (e->mimeData()->hasFormat(MIMETYPE))
        e->acceptProposedAction();
    else
        e->ignore();
}

void TrayIcon::dragEnterEvent(QDragEnterEvent *e)
{
    e->acceptProposedAction();
    const TrayButtonMimeData *mimeData = qobject_cast<const TrayButtonMimeData*>(e->mimeData());
    if (mimeData && mimeData->button())
        emit switchButtons(mimeData->button(), this);
    QToolButton::dragEnterEvent(e);
}

QMimeData * TrayIcon::mimeData()
{
    TrayButtonMimeData *mimeData = new TrayButtonMimeData();
    //    QByteArray ba;
    //    mimeData->setData(mimeDataFormat(), ba);
    mimeData->setButton(this);
    return mimeData;
}

void TrayIcon::mousePressEvent(QMouseEvent *e)
{
    if (e->button() == Qt::LeftButton && e->modifiers() == Qt::ControlModifier)
    {
        mDragStart = e->pos();
        return;
    }

    QPoint panel_click= e->pos();
    x_panel=panel_click.x();
    y_panel=panel_click.y();
    trayButtonCoordinateMapping(x_panel,y_panel);

    QToolButton::mousePressEvent(e);
}
#endif
