/*
 * Copyright (C) 2018 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 General Public License as published by
 * the Free Software Foundation; either version 3, 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/>.
 *
**/
#include "fullbackgroundwidget.h"

#include <QGuiApplication>
#include <QSvgRenderer>
#include <QScreen>
#include <QDBusInterface>
#include <QTime>
#include <QDebug>
#include <QPainter>
#include <QPainterPath>
#include <QTimer>
#include <QApplication>
#include <QDesktopWidget>
#include <QCloseEvent>
#include <QDBusPendingReply>
#include <QDBusReply>
#include <QImageReader>
#include "plasma-shell-manager.h"
#include <QX11Info>
#include "lockwidget.h"
#include <X11/Xatom.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
#include <X11/Xutil.h>
#include <X11/XKBlib.h>
#include <X11/extensions/XTest.h>
#include <unistd.h>
#include <sys/types.h>
#include <pwd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/syslog.h>

#include <xcb/xcb.h>
#include "xeventmonitor.h"
#include "monitorwatcher.h"
#include "configuration.h"
#include "screensavermode.h"
#include "screensaverwidget.h"
#include "grab-x11.h"
#include "tabletlockwidget.h"
#include "sessionwatcher.h"
// 实现键盘f1 - f2 的功能键
#include "PhysicalDeviceSet/sounddeviceset.h"
#include "PhysicalDeviceSet/brightnessdeviceset.h"

#include "config.h"

enum {
    SWITCH_TO_LINUX = 0,
    SWITCH_TO_ANDROID = 1,
    BACK_TO_DESKTOP = 2,
    TEST_CONNECTION = 3,
};

QT_BEGIN_NAMESPACE
extern void qt_blurImage(QPainter *p, QImage &blurImage, qreal radius, bool quality, bool alphaOnly, int transposed = 0);
QT_END_NAMESPACE

#define BLUR_RADIUS 300

#define SUBWND_COUNT_MAX  1024

QPixmap scaledPixmap(int width, int height, QString url)
{
    QFile imgFile(url);
    if(!imgFile.exists()){
        qDebug()<< "not find the pixmap file";
        return QPixmap();
    }
    QImage image(url);
    QPixmap pixmap = QPixmap::fromImage(image);
    if(pixmap.isNull()) {
        qDebug() << "pixmap is null";
        QProcess exec;
        QString program("file " + url);
        exec.start(program);
        exec.waitForFinished(1000);
        QString output = exec.readAllStandardOutput();
        qDebug() << output;
        if(output.contains("SVG")){
            qDebug() << "image format is SVG";
            QSvgRenderer render(url);
            QImage image(width, height, QImage::Format_ARGB32);
            image.fill(Qt::transparent);
            QPainter painter(&image);
            render.render(&painter, image.rect());
            pixmap.convertFromImage(image);
        } else if(output.contains("TIFF")) {
            qDebug() << "image format is TIFF";

        }
    }

    return pixmap.scaled(width, height, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
}

int connect_to_switch(const char* path)
{
    int ret;
    int connect_fd;
    struct sockaddr_un srv_addr;

    connect_fd = socket(PF_UNIX,SOCK_STREAM,0);
    if(connect_fd < 0) {

        return -1;
    }

    srv_addr.sun_family=AF_UNIX;
    strcpy(srv_addr.sun_path, path);

    ret = connect(connect_fd, (struct sockaddr*)&srv_addr, sizeof(srv_addr));
    if(ret < 0) {
        perror("cannot connect to the server");
        close(connect_fd);
        return -1;
    }

    return connect_fd;
}

int switch_to_linux(const char* container)
{
    int connect_fd;
    int32_t switch_to = BACK_TO_DESKTOP;

    char path[1024] = {0};
    sprintf(path, "/var/lib/kydroid/%s/sockets/%s", container, "desktop-switch");
    printf("path = %s\n",path);
    connect_fd = connect_to_switch(path);

    if(connect_fd < 0)
        return -1;

    write(connect_fd, &switch_to, sizeof(switch_to));
    close(connect_fd);
    return 0;
}

void x11_get_screen_size(int *width,int *height)
{
    Display* display;

    display = XOpenDisplay(NULL);
    if (display == NULL) {
        fprintf(stderr, "Cannot connect to X server %s/n", "simey:0");
        exit (-1);
    }
    int screen_num;

    screen_num = DefaultScreen(display);

    *width = DisplayWidth(display, screen_num);
    *height = DisplayHeight(display, screen_num);
    XCloseDisplay(display);

}

QPixmap blurPixmap(QPixmap pixmap)
{
    QPainter painter(&pixmap);
    QImage srcImg = pixmap.toImage();
    qt_blurImage(&painter, srcImg, BLUR_RADIUS, false, false);

    //在设置Qt::WA_TranslucentBackground属性后，模糊图片会导致锁屏界面透明
    //因此这里修改image图形的alpha值为255.
    for (int y = 0;y < srcImg.height();++y) {
      QRgb *row = (QRgb*)srcImg.scanLine(y);
      for (int x = 0; x < srcImg.width(); ++x) {
        ((unsigned char*)&row[x])[3] = 255;
      }
    }

    painter.end();
    return QPixmap::fromImage(srcImg);
}

FullBackgroundWidget::FullBackgroundWidget(QWidget *parent)
    : QWidget(parent),
      lockWidget(nullptr),
      //xEventMonitor(new XEventMonitor(this)),
      //monitorWatcher(new MonitorWatcher(this)),
      configuration(Configuration::instance()),
      isLocked(false),
      isPassed(false),
      lockState(false),
      screenStatus(UNDEFINED),
      isBlank(false),
      m_delay(false)
{
    qDebug() << "init - screenStatus: " << screenStatus;
    m_listWndIds.clear();
    setMouseTracking(true);
//    connect(monitorWatcher, &MonitorWatcher::monitorCountChanged,
//            this, &FullBackgroundWidget::onScreenCountChanged);
    QDesktopWidget *desktop = QApplication::desktop();

    connect(desktop, &QDesktopWidget::resized,
            this, &FullBackgroundWidget::onDesktopResized);
//    connect(desktop, &QDesktopWidget::workAreaResized,
//            this, &FullBackgroundWidget::onDesktopResized);
     connect(desktop, &QDesktopWidget::primaryScreenChanged,
            this, &FullBackgroundWidget::onDesktopResized);
    connect(desktop, &QDesktopWidget::screenCountChanged,
            this, &FullBackgroundWidget::onDesktopResized);

//    connect(QApplication::primaryScreen(),&QScreen::geometryChanged, this, &FullBackgroundWidget::onDesktopResized);
//    connect(QApplication::screens().at(0), &QScreen::virtualGeometryChanged, this,&FullBackgroundWidget::onDesktopResized);

    QDBusInterface *iface = new QDBusInterface("org.freedesktop.login1",
                                               "/org/freedesktop/login1",
                                               "org.freedesktop.login1.Manager",
                                               QDBusConnection::systemBus(),
                                               this);
    connect(iface, SIGNAL(PrepareForSleep(bool)), this, SLOT(onPrepareForSleep(bool)));

    QDBusInterface *interfaceScreensaver = new QDBusInterface(
                SS_DBUS_SERVICE,
                SS_DBUS_PATH,
                SS_DBUS_INTERFACE,
                QDBusConnection::sessionBus());

    connect(interfaceScreensaver, SIGNAL(SecondRunParam(QString)),
            this, SLOT(onSecondRunParam(QString)));
// 闲置不会主动锁住
//    QDBusInterface *interfaceLock = new QDBusInterface(
//                SS_DBUS_SERVICE,
//                SS_DBUS_PATH,
//                SS_DBUS_INTERFACE,
//                QDBusConnection::sessionBus());

//    connect(interfaceLock, SIGNAL(SessionLockIdle()),
//            this, SLOT(showLock()));
#ifdef USE_INTEL
    QDBusConnection::systemBus().connect("org.freedesktop.UPower", "/org/freedesktop/UPower", "org.freedesktop.DBus.Properties", "PropertiesChanged",
                                           this, SLOT(propertiesChangedSlot(QString, QMap<QString, QVariant>, QStringList)));
#endif

    init();
    qApp->installNativeEventFilter(this);
    installEventFilter(this);
    QTimer::singleShot(500,this,SLOT(switchToLinux()));

    LogindIntegration *m_logind = new LogindIntegration(this);
    

    connect(m_logind, &LogindIntegration::requestUnlock, this,
        [this]() {
        closeScreensaver();
    });

}

#ifdef USE_INTEL
void FullBackgroundWidget::propertiesChangedSlot(QString property, QMap<QString, QVariant> propertyMap, QStringList propertyList)
{
    Q_UNUSED(property);
    Q_UNUSED(propertyList);
    if (propertyMap.keys().contains("LidIsClosed")) {
        qDebug() <<"LidIsClosed" <<  propertyMap.value("LidIsClosed").toBool();
//        if(!(propertyMap.value("LidIsClosed").toBool()))
//        {
//            m_isSuspend = true;
//        }
    }
}
#endif

void FullBackgroundWidget::switchToLinux()
{
    struct passwd *pwd;
    pwd = getpwuid(getuid());
    char *username = pwd->pw_name;
    int uid = pwd->pw_uid;
    char container[100]= {0};

    sprintf(container,"kydroid2-%d-%s",uid,username);

    switch_to_linux(container);

}

void FullBackgroundWidget::laterActivate()
{
    if (QX11Info::isPlatformX11()) {
        /*在不调用XSetInputFocus接口的情况下，在窗口失去焦点后，activateWindow概率性无法
         * 激活窗口，导致锁屏输入不了密码。
         * 复现方法:锁屏，然后切换到tty，启动终端，文管等窗口抢占锁屏窗口焦点，数次以后必现*/
        XSetInputFocus(QX11Info::display(),this->winId(),RevertToParent,CurrentTime);
    }
    activateWindow();
    raise();
    raiseOtherWnd();
    setFocus();
    if(lockWidget && lockWidget->isVisible()) {
        lockWidget->setFocus();
        lockWidget->onActiveLineedit();//将焦点设置到密码框
    }
    update();
}

void FullBackgroundWidget::laterOtherActivate()
{
    activateWindow();
    raiseOtherWnd();
    //setFocus();
    if(lockWidget && lockWidget->isVisible()) {
        lockWidget->setFocus();
        lockWidget->onActiveLineedit();//将焦点设置到密码框
    }
}

void FullBackgroundWidget::setLockState()
{
    if(lockState == true)
        return ;

    lockState = true;
    QString displayNum = QString(qgetenv("DISPLAY")).replace(":", "").replace(".", "_");
    QString sessionDbus = QString("%1%2").arg(QString(SS_DBUS_SERVICE)).arg(displayNum);
    QDBusInterface *interface = new QDBusInterface(sessionDbus,
                                                      SS_DBUS_PATH,
                                                      SS_DBUS_INTERFACE);
    if (!interface->isValid()) {
        delete interface;
        interface = new QDBusInterface(SS_DBUS_SERVICE,
                                       SS_DBUS_PATH,
                                       SS_DBUS_INTERFACE);
    }
    QDBusMessage msg = interface->call("SetLockState");
    if(msg.type() == QDBusMessage::ErrorMessage)
           qDebug() << msg.errorMessage();
    HideMultiview();
}

bool FullBackgroundWidget::eventFilter(QObject *obj, QEvent *event)
{
    if (!QX11Info::isPlatformX11()) {
        if(event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseMove || event->type() == 7){
            if(screenStatus & SCREEN_SAVER && !isBlank){
                clearScreensavers();
            }
        }
    }
    if(event->type() == QEvent::WindowDeactivate){
         QTimer::singleShot(50,this,SLOT(laterActivate()));
    }else if(event->type() == QEvent::WindowActivate){
	if(QString(qgetenv("XDG_SESSION_TYPE")) == "wayland") {
            PlasmaShellManager::getInstance()->setAppWindowKeepAbove(true);
        }

        QTimer::singleShot(500,this,SLOT(setLockState()));
        QTimer::singleShot(200,this,SLOT(killWindow()));
    }
    return false;
}

void FullBackgroundWidget::killWindow()
{
    if(isStartup && !process){
           process = new QProcess(this);
           process->start("killall screensaver-focus-helper");
    }
}

void FullBackgroundWidget::setIsStartup(bool val)
{
    isStartup = val;
    if (lockWidget) {
        lockWidget->setStartupMode(isStartup);
    }
    Q_EMIT StartupModeChanged(isStartup);
}

bool FullBackgroundWidget::IsStartupMode()
{
    return isStartup;
}

void FullBackgroundWidget::paintEvent(QPaintEvent *event)
{
    if(future.isRunning()){
            qDebug()<<"------------------------------------------------------------等待加载背景完成1";
            future.waitForFinished();
            qDebug()<<"------------------------------------------------------------加载背景完成1";
    }else{
        if(!future.isFinished() && future.isStarted()){
            qDebug()<<"------------------------------------------------------------等待加载背景完成2";
            future.waitForFinished();
            qDebug()<<"------------------------------------------------------------加载背景完成2";
        }
    }

    for(auto screen : QGuiApplication::screens())
    {
       QPainter painter(this);
        if(background.isNull()){
            QColor cor = "#035290";
            painter.setBrush(cor);
            painter.drawRect(screen->geometry());
        } else {
            painter.drawPixmap(screen->geometry(), background);
            QPainterPath path;
            painter.setOpacity(0.25);
            painter.setRenderHint(QPainter::Antialiasing);  // 反锯齿;
            painter.setClipping(true);
            painter.setPen(Qt::transparent);
            path.addRect(this->rect());
            path.setFillRule(Qt::WindingFill);
            painter.setBrush(QColor("#000000"));
            painter.setPen(Qt::transparent);
            painter.drawPath(path);
        }
    }
    return QWidget::paintEvent(event);
}

void FullBackgroundWidget::closeEvent(QCloseEvent *event)
{
    qDebug() << "FullBackgroundWidget::closeEvent";
    if (isStartup)
        setIsStartup(false);
    if(future.isRunning()){
        future.cancel();
        future.waitForFinished();
    }
#ifdef USE_INTEL
    //蓝牙连接后 唤醒信号会有延迟 以防退出时未收到信号导致kwin compositor未resume
    QDBusInterface *interface = new QDBusInterface("org.ukui.KWin",
                                                   "/Compositor",
                                                   "org.ukui.kwin.Compositing",
                                                   QDBusConnection::sessionBus(),
                                                   this);

    if (!interface->isValid()){
        syslog(LOG_DEBUG, "interface error");
        return;
    }
    QDBusMessage msg = interface->call("resume");
    syslog(LOG_DEBUG, "after close resume kwin ");
#endif

    for(auto obj: children())
    {
        QWidget *widget = dynamic_cast<QWidget*>(obj);
        if(widget)
            widget->close();
    }

    if(QX11Info::isPlatformX11()){
        closeGrab();
    }

    return QWidget::closeEvent(event);
}

void FullBackgroundWidget::showEvent(QShowEvent *event)
{
   // XSetWindowAttributes top_attrs;
   // top_attrs.override_redirect = False;
   // XChangeWindowAttributes(QX11Info::display(), this->winId(), CWOverrideRedirect, &top_attrs);
   // XRaiseWindow(QX11Info::display(), this->winId());
  //  raise();

    return QWidget::showEvent(event);
}


bool FullBackgroundWidget::nativeEventFilter(const QByteArray &eventType, void *message, long *result)
{
    if (qstrcmp(eventType, "xcb_generic_event_t") != 0) {
        return false;
    }
    xcb_generic_event_t *event = reinterpret_cast<xcb_generic_event_t*>(message);
    const uint8_t responseType = event->response_type & ~0x80;
    if (responseType == XCB_CONFIGURE_NOTIFY) {
        xcb_configure_notify_event_t *xc = reinterpret_cast<xcb_configure_notify_event_t*>(event);
        if(xc->window == winId()) {
            laterOtherActivate();
            return false;
        }
        XClassHint ch;
        ch.res_name = NULL;
        ch.res_class = NULL;
        XGetClassHint (QX11Info::display(), xc->window, &ch);
        if(QString(ch.res_name) == "ukui-screensaver-dialog") {
            if (ch.res_name)
                XFree(ch.res_name);
            if (ch.res_class)
                XFree(ch.res_class);
            laterOtherActivate();
            return false;
        } else if (isOtherWnd(xc->window)) {
            if (ch.res_name)
                XFree(ch.res_name);
            if (ch.res_class)
                XFree(ch.res_class);
            return false;
        }
        if (ch.res_name)
            XFree(ch.res_name);
        if (ch.res_class)
            XFree(ch.res_class);
        laterActivate();
    } else if(responseType == XCB_MAP_NOTIFY){
        xcb_map_notify_event_t *xm = reinterpret_cast<xcb_map_notify_event_t*>(event);
        if(xm->window == winId()) {
            laterOtherActivate();
            return false;
        }
        XClassHint ch;
        ch.res_name = NULL;
        ch.res_class = NULL;
        XGetClassHint (QX11Info::display(), xm->window, &ch);
        if(QString(ch.res_name) == "ukui-screensaver-dialog") {
            if (ch.res_name)
                XFree(ch.res_name);
            if (ch.res_class)
                XFree(ch.res_class);
            laterOtherActivate();
            return false;
        } else if (isOtherWnd(xm->window)) {
            if (ch.res_name)
                XFree(ch.res_name);
            if (ch.res_class)
                XFree(ch.res_class);
            return false;
        }
        if (ch.res_name)
            XFree(ch.res_name);
        if (ch.res_class)
            XFree(ch.res_class);
        laterActivate();
    } else if (responseType == XCB_DESTROY_NOTIFY) {
        xcb_destroy_notify_event_t *xd = reinterpret_cast<xcb_destroy_notify_event_t*>(event);
        if(isOtherWnd(xd->window)) {
            UnRegisteSubWnd(xd->window);
            return false;
        }
    } else if (responseType == XCB_UNMAP_NOTIFY) {
        xcb_unmap_notify_event_t *xum = reinterpret_cast<xcb_unmap_notify_event_t*>(event);
        if(isOtherWnd(xum->window)) {
            UnRegisteSubWnd(xum->window);
            return false;
        }
    } else if (responseType == XCB_KEY_PRESS) {
//        xcb_key_press_event_t *xc = reinterpret_cast<xcb_key_press_event_t*>(event);
//        qDebug()<<"---------------------XCB_KEY_PRESS:"<<xc->detail;
        //onGlobalKeyPress(xc->detail);
     } else if (responseType == XCB_KEY_RELEASE) {
        xcb_key_release_event_t *xc = reinterpret_cast<xcb_key_release_event_t*>(event);
        onGlobalKeyRelease(xc->detail);
     } else if(responseType == XCB_GE_GENERIC){
        xcb_ge_generic_event_t *xc = reinterpret_cast<xcb_ge_generic_event_t*>(event);
        if(xc->event_type == XCB_BUTTON_PRESS){  //此处获取的是窗口内的点击事件,光标坐标不需要使用，就直接使用QCursor接口获取了
            onGlobalButtonPressed(QCursor::pos().x(), QCursor::pos().y());
        }else if(xc->event_type == XCB_MOTION_NOTIFY){ //此处获取的是窗口内的点击事件,光标坐标不需要使用，就直接使用QCursor接口获取了
            onGlobalButtonDrag(QCursor::pos().x(),QCursor::pos().y());
        }
    }else if (responseType == XCB_BUTTON_PRESS) {   //此处获取的是窗口外的鼠标点击
        xcb_button_press_event_t *xc = reinterpret_cast<xcb_button_press_event_t*>(event);
        int x = xc->root_x;
        int y = xc->root_y;
        onGlobalButtonPressed(x, y);
        qDebug()<<"---------------------XCB_BUTTON_PRESS:"<<x<<","<<y;
     } else if (responseType == XCB_BUTTON_RELEASE) {
     } else if (responseType == XCB_MOTION_NOTIFY) {   //此处获取的是窗口外的鼠标移动
        xcb_motion_notify_event_t *xc = reinterpret_cast<xcb_motion_notify_event_t*>(event);
        int x = xc->root_x;
        int y = xc->root_y;
        onGlobalButtonDrag(x, y);
        qDebug()<<"---------------------XCB_MOTION_NOTIFY:"<<x<<","<<y;
     }
     return false;
}

void FullBackgroundWidget::mouseMoveEvent(QMouseEvent *e)
{
	/*注释掉抓取鼠标后，使用触摸时会出现第一次触摸收不到事件，因此在这里也添加一下*/
    if(screenStatus & SCREEN_SAVER && !isBlank)
    {
        clearScreensavers();
    }

    //onCursorMoved(QCursor::pos()); 
    return QWidget::mouseMoveEvent(e);
}

void FullBackgroundWidget::mousePressEvent(QMouseEvent *e)
{
#ifdef USE_INTEL
    if(screenStatus == SCREEN_LOCK_AND_SAVER)
    {
        ScreenSaver *saver = configuration->getScreensaver();
        if(saver->path == "/usr/lib/ukui-screensaver/ukui-screensaver-default")
               return ;
        clearScreensavers();
    }
#else
     /*注释掉抓取鼠标后，使用触摸时会出现第一次触摸收不到事件，因此在这里也添加一下*/
    if(screenStatus & SCREEN_SAVER && !isBlank)
    {
        clearScreensavers();
    }
#endif
}

void FullBackgroundWidget::init()
{
/*捕获键盘，如果捕获失败，则可能是由于弹出菜单项已经捕获，那么模拟一次esc按键来退出菜单，如果仍捕获失败，则放弃锁屏，避免密码无法输入*/
    if(QX11Info::isPlatformX11()){
        if(establishGrab())
            qDebug()<<"establishGrab : true";
        else {
            qDebug()<<"establishGrab : false";
            /*检测当前是否存在弹出菜单，只有存在弹出菜单时，才模拟按键esc*/
            if(checkHasPopupMenu()){
                XTestFakeKeyEvent(QX11Info::display(), XKeysymToKeycode(QX11Info::display(),XK_Escape), True, 1);
                XTestFakeKeyEvent(QX11Info::display(), XKeysymToKeycode(QX11Info::display(),XK_Escape), False, 1);
                XFlush(QX11Info::display());
                sleep(1);
            }
            HideMultiview();
            if(!establishGrab())
            {
                exit(1);
            }
        }

        XWindowAttributes rootAttr;
        XGetWindowAttributes(QX11Info::display(), QX11Info::appRootWindow(), &rootAttr);
        XSelectInput( QX11Info::display(), QX11Info::appRootWindow(),
                      SubstructureNotifyMask|rootAttr.your_event_mask );

    }

    qDebug()<<"----------------------------------------------------------------开始异步调用";
    future = QtConcurrent::run([=](){
        QImageReader reader;
        reader.setFileName(configuration->getBackground());
        reader.setAutoTransform(true);
        reader.setDecideFormatFromContent(true);
        //reader.setScaledSize(QApplication::primaryScreen()->size());
        background = QPixmap::fromImageReader(&reader);

        if(!background.isNull()){
            background = blurPixmap(background);
        }
    });

    if(QX11Info::isPlatformX11()){
        setWindowFlags(Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint
                   | Qt::X11BypassWindowManagerHint);
    }else{
        setWindowFlags(Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint);
    }

    /*x100下会出现黑色小方块问题，设置此属性时正常*/
    setAttribute(Qt::WA_TranslucentBackground);

    // 监听session信号
//    smInterface = new QDBusInterface(SM_DBUS_SERVICE,
//                                     SM_DBUS_PATH,
//                                     SM_DBUS_INTERFACE,
//                                     QDBusConnection::sessionBus());
//    connect(smInterface, SIGNAL(StatusChanged(uint)),
//            this, SLOT(onSessionStatusChanged(uint)));

//    int totalWidth = 0;
//    int totalHeight = 0;
//    for(auto screen : QGuiApplication::screens())
//    {
//        totalWidth += screen->geometry().width();
//        totalHeight += screen->geometry().height();
//    }
//    setGeometry(0, 0, totalWidth, totalHeight);
    QDesktopWidget *desktop = QApplication::desktop();
    setGeometry(desktop->geometry());
   
#ifdef USE_INTEL
    SoundDeviceSet::instance();
#endif
}

void FullBackgroundWidget::onCursorMoved(const QPoint &pos)
{
    if(!lockWidget)
    {
        return;
    }
    bool chkInOneScreen = false;
    for(auto screen : QGuiApplication::screens())
    {
        if(screen == qApp->primaryScreen()){
            qInfo()<<"LockWidget:"<<screen->geometry()<<lockWidget->geometry();
            lockWidget->hide();
            lockWidget->setGeometry(screen->geometry());
            lockWidget->show();
            chkInOneScreen = true;
            break;
        }
    }
    if (!chkInOneScreen) {
        for(auto screen : QGuiApplication::screens()) {
            if(!screen){
                /*避免切换时闪烁*/
                qInfo()<<"LockWidget:"<<screen->geometry()<<lockWidget->geometry()<<","<<screen;
                lockWidget->hide();
                lockWidget->setGeometry(screen->geometry());
                lockWidget->show();
                chkInOneScreen = true;
                break;
            }
        }
    }
}

void FullBackgroundWidget::lock()
{
    showLockWidget();
    if(lockWidget){
        lockWidget->show();
        lockWidget->startAuth();
    }
#ifndef USE_INTEL
    inhibit();
#endif
}

void FullBackgroundWidget::showLock()
{
    screenStatus = (ScreenStatus)(screenStatus | SCREEN_LOCK);
    //qDebug() << "showLockWidget - screenStatus: " << screenStatus;
}

void FullBackgroundWidget::showLockWidget()
{
#ifdef USE_INTEL
    screenStatus = /*(ScreenStatus)(screenStatus | SCREEN_LOCK)*/SCREEN_LOCK;
#else
    screenStatus = (ScreenStatus)(screenStatus | SCREEN_LOCK);
#endif
    qDebug() << "showLockWidget - screenStatus: " << screenStatus;

    if(!lockWidget)
    {
#ifdef USE_INTEL
        lockWidget = new TabletLockWidget(this);
        connect(lockWidget, &TabletLockWidget::closed,
                this, &FullBackgroundWidget::close);
        connect(lockWidget, &TabletLockWidget::screenSaver,
                this, [=] {
            showScreensaver();
        });
        connect(lockWidget, &TabletLockWidget::blackSaver,
                this, [=] {
            onShowBlackBackGround();
        });
#else
        lockWidget = new LockWidget(this);
        lockWidget->setStartupMode(isStartup);
        connect(lockWidget, &LockWidget::closed,
                this, &FullBackgroundWidget::close);
        connect(lockWidget, &LockWidget::keyGlobalRelease,
                this, &FullBackgroundWidget::onGlobalKeyRelease);
#endif
    }
    onCursorMoved(QCursor::pos());
    lockWidget->setFocus();
    if(QX11Info::isPlatformX11() ){
        XSetInputFocus(QX11Info::display(),this->winId(),RevertToParent,CurrentTime);
    }
    activateWindow();
    repaint();
}

void FullBackgroundWidget::onSecondRunParam(QString strParam)
{
    qDebug()<<"onSecondRunParam:"<<strParam;
    if (strParam == "SessionIdle") {
        showScreensaver();
    } else if (strParam == "SleepLock") {
        showLock();
    } else if (strParam == "CloseLock") {
        showLock();
    }
}

void FullBackgroundWidget::showScreensaver(bool isPreview/* = false*/)
{ 
    if(screenStatus & SCREEN_SAVER){
        if (!isPreview && !(screenStatus & SCREEN_LOCK)) {
            // 延迟启动锁屏
            delayLockScreen();
        }
    	return ;
    }
#ifdef USE_INTEL
    screenStatus = /*(ScreenStatus)(screenStatus | SCREEN_SAVER)*/SCREEN_LOCK_AND_SAVER;
#else
    screenStatus = (ScreenStatus)(screenStatus | SCREEN_SAVER);
#endif
    m_isAlreadyShowSaver = true;
    qDebug() << "showScreensaver - screenStatus: " << screenStatus;

    for(auto screen : QGuiApplication::screens())
    {
        ScreenSaver *saver = configuration->getScreensaver();
        /*锁屏设置的Qt::WA_TranslucentBackground属性会导致第三方屏保变得透明，因此在使用第三方屏保时
	 * 取消该属性，清除屏保时再设置回来*/
	if(saver->path != "/usr/lib/ukui-screensaver/ukui-screensaver-default")
	{
	    setAttribute(Qt::WA_TranslucentBackground,false);	
	}

        ScreenSaverWidget *saverWidget = new ScreenSaverWidget(saver, this);
        qDebug() << " new ScreenSaverWidget";
        widgetXScreensaverList.push_back(saverWidget);
        //深色模式有一像素的白边，所以主屏幕向左，向右移一个像素点;这种操作后，外显上方仍旧会有一个像素的白边，暂时不对外显做偏移处理
        if(screen == qApp->primaryScreen()) {
            saverWidget->setGeometry(screen->geometry().x()-1, screen->geometry().y()-1,
                                     screen->geometry().width()+1, screen->geometry().height()+1);
        } else {
            saverWidget->setGeometry(screen->geometry());
        }

    }
    setCursor(Qt::BlankCursor);

    //显示屏保时，停止认证（主要针对生物识别）
    if(lockWidget)
    {
        lockWidget->stopAuth();
        lockWidget->hide();
    }
    if (!isPreview && !(screenStatus & SCREEN_LOCK)) {
        // 延迟启动锁屏
        delayLockScreen();
    }
}

void FullBackgroundWidget::clearScreensavers()
{
    stopDelayLockScreen();
#ifdef USE_INTEL
    screenStatus = /*(ScreenStatus)(screenStatus & ~SCREEN_SAVER)*/SCREEN_LOCK;
#else
    screenStatus = (ScreenStatus)(screenStatus & ~SCREEN_SAVER);
#endif
    for(auto widget : widgetXScreensaverList)
    {
        widget->close();
    }
    widgetXScreensaverList.clear();
    setAttribute(Qt::WA_TranslucentBackground,true);
    qDebug() << "clearScreensavers - screenStatus: " << screenStatus;

    unsetCursor();
    if(screenStatus == UNDEFINED)
    {
        close();
    }
    else
    {
        lock();
    }
}

int FullBackgroundWidget::onSessionStatusChanged(uint status)
{
    qDebug() << "session status changed: " << status;
    if(status != SESSION_IDLE)
    {
        //当前session没有处于空闲状态
        return -1;
    }
    qDebug() << "onSessionStatusChanged - screenStatus: " << screenStatus;

    if(configuration->idledelay() == -1)
    {
        return -1;
    }
#ifdef USE_INTEL
    if(screenStatus == SCREEN_LOCK_AND_SAVER)
#else
    if(screenStatus & SCREEN_SAVER)
#endif
    {
        return -1;
    }
#ifdef USE_INTEL
    else if(screenStatus == SCREEN_LOCK)
#else
    else if(screenStatus & SCREEN_LOCK)
#endif
    {
        showScreensaver();
    }
    else if(screenStatus == UNDEFINED)
    {
#ifdef USE_INTEL
        //显示锁屏和屏保
        showLockWidget();
        showScreensaver();
#else
        //显示屏保
        showScreensaver();
#endif
    }
    return 0;
}

void FullBackgroundWidget::delayLockScreen()
{
    if (!m_timerLock) {
        m_timerLock = new QTimer(this);
        connect(m_timerLock, &QTimer::timeout, this, &FullBackgroundWidget::onLockScreenTimeout);
    }
    qDebug()<<"LockTimeout:"<<configuration->locktimeout();
    if (configuration->locktimeout() != -1) {
        stopDelayLockScreen();
        m_timerLock->start(configuration->locktimeout()*1000);
    }
}

void FullBackgroundWidget::stopDelayLockScreen()
{
    if (m_timerLock && m_timerLock->isActive()) {
        m_timerLock->stop();
    }
}

void FullBackgroundWidget::onLockScreenTimeout()
{
    qDebug()<<"onLockScreenTimeout:"<<configuration->lockWhenXScreensaverActivated();
    if (configuration->lockWhenXScreensaverActivated()) {
        showLock();
    }
    m_timerLock->stop();
}

void FullBackgroundWidget::onBlankScreensaver(int nDelay/* = 0*/, bool hasLock/* = true*/)
{
    if (hasLock) {
        showLockWidget();
        screenStatus = (ScreenStatus)(screenStatus | SCREEN_SAVER | SCREEN_LOCK);
    } else {
        screenStatus = (ScreenStatus)(screenStatus | SCREEN_SAVER);
    }
    qDebug() << "showScreensaver - screenStatus: " << screenStatus << nDelay;

    for(auto screen : QGuiApplication::screens())
    {
        ScreenSaver *saver = configuration->getScreensaver();
        saver->mode = SaverMode(SAVER_BLANK_ONLY);
        ScreenSaverWidget *saverWidget = new ScreenSaverWidget(saver, this);
        widgetXScreensaverList.push_back(saverWidget);
        saverWidget->setGeometry(screen->geometry());
    }
    setCursor(Qt::BlankCursor);
    isBlank = true;

    if (0 == nDelay) {
        /*在进行压力测试时，可能会出现锁屏界面启动极慢，导致在睡眠之前调用了锁屏，但
        * 锁屏没来得及绑定睡眠唤醒信号，导致唤醒后，锁屏界面没有收到信号从而一直显示黑屏的问题。
        * 因此这里在进入黑色屏保时，通过后台接口，获取一次当前是否应该显示黑色屏保状态*/
        QString displayNum = QString(qgetenv("DISPLAY")).replace(":", "").replace(".", "_");
        QString sessionDbus = QString("%1%2").arg(QString(SS_DBUS_SERVICE)).arg(displayNum);
        QDBusInterface *interface = new QDBusInterface(sessionDbus,
                                                          SS_DBUS_PATH,
                                                          SS_DBUS_INTERFACE);
        if (!interface->isValid()) {
            delete interface;
            interface = new QDBusInterface(SS_DBUS_SERVICE,
                                           SS_DBUS_PATH,
                                           SS_DBUS_INTERFACE);
        }

        QDBusReply<bool> stateReply = interface->call("GetBlankState");
        if(!stateReply.isValid()){
            return ;
        }

        if(!stateReply){
            isBlank = false;
            clearScreensavers();
        }
    } else {
        QTimer::singleShot(nDelay, this, [=](){
            if (isBlank) {
                isBlank = false;
                clearScreensavers();
            }
        });
    }
}

void FullBackgroundWidget::onScreensaver()
{
      showLockWidget();
      showScreensaver();
}

void FullBackgroundWidget::onGlobalKeyPress(const quint8 &key)
{
#ifdef USE_INTEL
    qDebug() << "onGlobalKeyPress " << key << "screenStatus " << screenStatus;

    if(m_delay)
    {
        qDebug() << "it is delay time ,ignore";
        return;
    }

    if(!key.isEmpty() && (screenStatus == SCREEN_LOCK_AND_SAVER))
    {
        clearScreensavers();
    }/*else{
       lockWidget->startAuth();
        inhibit();
    }*/
//    if(screenStatus == SCREEN_LOCK)
//    {
//        checkNumLock();
//        int keyValue = numberMatch(key);;
//        if (keyValue >= 0 && keyValue <= 10 )
//        {
//            lockWidget->RecieveKey(keyValue);
//        }
//    }
#else

#endif
}

void FullBackgroundWidget::onGlobalKeyRelease(int key)
{
//    if(key == "Caps_Lock")
//    {
//        lockWidget->capsLockChanged();
//    }
#ifdef USE_INTEL

    // 声音、亮度等调整
    // 取消声音快捷键设置，由settings-deamon控制   有一个bug，音量为零时再按静音键，静音指示灯会熄灭，可解决，但是不用锁屏做了
//    if(key == "XF86AudioRaiseVolume")
//    {
//        SoundDeviceSet::instance()->setValue(SoundDeviceSet::instance()->getValue() + 5);
//    }
//    else if(key == "XF86AudioLowerVolume")
//    {
//        SoundDeviceSet::instance()->setValue(SoundDeviceSet::instance()->getValue() - 5);
//    }
//    else if(key == "XF86AudioMute")
//    {
//        SoundDeviceSet::instance()->setMute(!(SoundDeviceSet::instance()->getIsMute()));
//    }
//    else

    if (key == "XF86MonBrightnessUp") // 亮度调整
    {
        //qDebug() << "up";
        BrightnessDeviceSet* pBrightness = BrightnessDeviceSet::instance();
        pBrightness->setValue(pBrightness->getValue() + 5);
    }
    else if (key == "XF86MonBrightnessDown")
    {
        //qDebug() << "down";
        BrightnessDeviceSet* pBrightness = BrightnessDeviceSet::instance();
        pBrightness->setValue(pBrightness->getValue() - 5);
    }
    else if (key == "XF86RFKill") // 飞行模式
    {
        // 键盘上的飞行模式实体键 生效，不需要在登录界面进行设置
    }
    else if (key == "") // num_lock
    {
        // 键盘上的num_lock生效、不需要登录界面进行管理
    }
#else
    if (key == 65) { // "Space"
        if (lockWidget && lockWidget->isVisible()) {/*keyReleaseEvent有时候监听不到Space的按键事件 原因未知
                            把Space按键放到nativeEventFilter里面*/
            lockWidget->key_enter_release(Qt::Key_Space);
        }
    } else if (key == Qt::Key_Escape && screenStatus == SCREEN_LOCK) { // "escape"
        bool canShow = true;
        if (lockWidget && !lockWidget->exitSubWidget())
            canShow = false;
        if (configuration && configuration->idledelay() == -1)
            canShow = false;
        if (!m_isAlreadyShowSaver)
            canShow = false;
        if (canShow)
            showScreensaver();
    } else if (screenStatus & SCREEN_SAVER && !isBlank) {
        clearScreensavers();	
    }
#endif
}

void FullBackgroundWidget::onGlobalButtonDrag(int xPos, int yPos)
{
#ifdef USE_INTEL
    if(screenStatus == SCREEN_LOCK_AND_SAVER)
    {
        ScreenSaver *saver = configuration->getScreensaver();
        if(saver->path == "/usr/lib/ukui-screensaver/ukui-screensaver-default")
               return ;
        clearScreensavers();
    }
#else
    if(screenStatus & SCREEN_SAVER && !isBlank)
    {
        ScreenSaver *saver = configuration->getScreensaver();
        if(isPassed || saver->path != "/usr/lib/ukui-screensaver/ukui-screensaver-default"){
            clearScreensavers();
        }
        isPassed = true;
    }
#endif
}

void FullBackgroundWidget::onGlobalButtonPressed(int xPos, int yPos)
{
#ifndef USE_INTEL
    if(screenStatus & SCREEN_SAVER && !isBlank)
    {
        clearScreensavers();
    }
#endif
}

void FullBackgroundWidget::closeScreensaver()
{
    if(screenStatus & SCREEN_SAVER){
    	clearScreensavers();
    }

    if(screenStatus & SCREEN_LOCK){
    	if(lockWidget){
    	    	lockWidget->stopAuth();
		lockWidget->close();
    	}
    }

    close();
}

void FullBackgroundWidget::onScreenCountChanged(int)
{
#ifdef USE_INTEL
    QDesktopWidget *desktop = QApplication::desktop();
    setGeometry(desktop->geometry());
    //repaint();
    update();
    clearScreensavers();
#else
    QDesktopWidget *desktop = QApplication::desktop();
    setGeometry(desktop->geometry());
    //repaint();
    if(screenStatus & SCREEN_SAVER)
    {
        clearScreensavers();
    }
    update();
#endif
}


void FullBackgroundWidget::onDesktopResized()
{
#ifdef USE_INTEL
    qDebug() << "[FullBackgroundWidget] [onDesktopResized]";
    QDesktopWidget *desktop = QApplication::desktop();
    if(NULL == desktop)
    {
        qWarning() << " get desktop size failed";
        return;
    }
    setGeometry(desktop->geometry());
    if(lockWidget)
        onCursorMoved(cursor().pos());
//    clearScreensavers();
   //repaint();
    update();
    if(screenStatus == SCREEN_LOCK_AND_SAVER)
    {
        clearScreensavers();
        showScreensaver();
    }
#else
    QDesktopWidget *desktop = QApplication::desktop();
    setGeometry(desktop->geometry());
    if(lockWidget)
        onCursorMoved(QCursor::pos());
    if(screenStatus & SCREEN_SAVER)
    {
        clearScreensavers();
    }
    //repaint();
    update();
#endif
    
    if(QString(qgetenv("XDG_SESSION_TYPE")) == "wayland") {
        PlasmaShellManager::getInstance()->setPos(this->windowHandle(),QPoint(0,0));
    }
}

void FullBackgroundWidget::laterInhibit(bool val)
{
	if(val){
		inhibit();
	}else{
		uninhibit();
	}
}

void FullBackgroundWidget::laterStartAuth()
{
    if (lockWidget)
        lockWidget->startAuth();
    inhibit();
}

void FullBackgroundWidget::onPrepareForSleep(bool sleep)
{
    ///系统休眠时，会关闭总线，导致设备不可用，发生错误
    ///在系统休眠之前停止认证，在系统唤醒后重新开始认证
    qDebug()<<"onPrepareForSleep:"<<sleep;
    if(sleep)
    {
        if(lockWidget)
            lockWidget->stopAuth();
        uninhibit();
    }
    else
    {
        if(screenStatus & SCREEN_SAVER)
        {
            isBlank = false;
            clearScreensavers();
        }else{
            repaint();
            if(lockWidget)
                lockWidget->startAuth();
            inhibit();
        }
    }
}

void FullBackgroundWidget::inhibit()
{
    if (m_inhibitFileDescriptor.isValid()) {
        return;
    }

    QDBusMessage message = QDBusMessage::createMethodCall("org.freedesktop.login1",
                                                          "/org/freedesktop/login1",
                                                          "org.freedesktop.login1.Manager",
                                                          QStringLiteral("Inhibit"));
    message.setArguments(QVariantList({QStringLiteral("sleep"),
                                       "Screen Locker",
                                       "Ensuring that the screen gets locked before going to sleep",
                                       QStringLiteral("delay")}));
    QDBusPendingReply<QDBusUnixFileDescriptor> reply = QDBusConnection::systemBus().call(message);
    if (!reply.isValid()) {
        return;
    }
    reply.value().swap(m_inhibitFileDescriptor);
}

void FullBackgroundWidget::uninhibit()
{
    if (!m_inhibitFileDescriptor.isValid()) {
        return;
    }
    m_inhibitFileDescriptor = QDBusUnixFileDescriptor();
}

/**
 * @brief FullBackgroundWidget::getPaddingPixmap
 * @param pixmap 需要填充的图像
 * @param width  容器宽度
 * @param height 容器高度
 * @return
 */
QPixmap FullBackgroundWidget::getPaddingPixmap(QPixmap pixmap, int width, int height)
{
    if (pixmap.isNull() || pixmap.width() == 0 || pixmap.height() == 0)
    {
        return QPixmap();
    }

    bool useHeight;
    float scaled = 0.0;
    QPixmap scaledPixmap;
    QPixmap paddingPixmap;
    qint64 rw = qint64(height) * qint64(pixmap.width()) / qint64(pixmap.height());

    useHeight = (rw >= width);
    if (useHeight) {
        scaled = float(height) / float(pixmap.height());
        scaledPixmap = pixmap.scaled(pixmap.width() * scaled, height);
        paddingPixmap = scaledPixmap.copy((pixmap.width() * scaled - width) / 2 , 0, width, height);
    } else {
        scaled = float(width) / float(pixmap.width());
        scaledPixmap = pixmap.scaled(width, pixmap.height() * scaled);
        paddingPixmap = scaledPixmap.copy(0 , (pixmap.height() * scaled - height) / 2,width, height);
    }

    return paddingPixmap;
}

int FullBackgroundWidget::RegisteSubWnd(quint64 uWndId)
{
    if (!m_listWndIds.contains(uWndId) && m_listWndIds.size() < SUBWND_COUNT_MAX) {
        m_listWndIds.append(uWndId);
        qDebug()<<"RegisterSubWnd:"<<uWndId;
        QTimer::singleShot(50,this,SLOT(laterActivate()));
        return m_listWndIds.size();
    } else {
        return -1;
    }
}

int FullBackgroundWidget::UnRegisteSubWnd(quint64 uWndId)
{
    if (m_listWndIds.contains(uWndId)) {
        m_listWndIds.removeAll(uWndId);
        qDebug()<<"UnRegisterSubWnd:"<<uWndId;
        QTimer::singleShot(50,this,SLOT(laterActivate()));
        return m_listWndIds.size();
    } else {
        return -1;
    }
}

QList<quint64> FullBackgroundWidget::GetSubWndIds()
{
    return m_listWndIds;
}

void FullBackgroundWidget::raiseOtherWnd()
{
    //qDebug()<<"raiseOtherWnd----:"<<m_listWndIds.size();
    
    if(!QX11Info::isPlatformX11())
	return ;

    for (auto wndId : m_listWndIds) {
        XRaiseWindow(QX11Info::display(), wndId);
        XFlush(QX11Info::display());
    }
}

bool FullBackgroundWidget::isOtherWnd(int wndId)
{
    return m_listWndIds.contains(wndId);
}

#ifdef USE_INTEL
void FullBackgroundWidget::onShowBlackBackGround()
{
    screenStatus = SCREEN_BLACK;
    qDebug() << "showBlackBackGround - screenStatus: " << screenStatus;

    for(auto screen : QGuiApplication::screens())
    {
//        BlackWidget *blackWidget = new BlackWidget(this);
//        qDebug() << " new BlackWidget";
//        widgetBlackList.push_back(blackWidget);
        ScreenSaver *saver = configuration->getScreensaver();
      saver->mode = SaverMode(SAVER_BLANK_ONLY);
      ScreenSaverWidget *saverWidget = new ScreenSaverWidget(saver, this);
      widgetBlackList.push_back(saverWidget);
      saverWidget->setGeometry(screen->geometry());

        //深色模式有一像素的白边，所以主屏幕向左，向右移一个像素点;这种操作后，外显上方仍旧会有一个像素的白边，暂时不对外显做偏移处理
        if(screen == qApp->primaryScreen()) {
            saverWidget->setGeometry(screen->geometry().x()-1, screen->geometry().y()-1,
                                     screen->geometry().width()+1, screen->geometry().height()+1);
        } else {
            saverWidget->setGeometry(screen->geometry());
        }


    }
    setCursor(Qt::BlankCursor);
}
#endif

bool FullBackgroundWidget::initMultiviewDbus()
{
    if (m_dbusIfMultiview) {
        return true;
    }
    m_dbusIfMultiview = new QDBusInterface("org.ukui.KWin",
                                           "/MultitaskView",
                                           "org.ukui.KWin.MultitaskView",
                                           QDBusConnection::sessionBus(),
                                           this);

    if (!m_dbusIfMultiview || !m_dbusIfMultiview->isValid()){
        qWarning()<<"org.ukui.KWin.MultitaskView interface error!";
        return false;
    }
    return true;
}

bool FullBackgroundWidget::isMultiviewHidden()
{
    if (initMultiviewDbus()) {
        QDBusReply<bool> reply = m_dbusIfMultiview->call("isHidden");
        if(!reply.isValid()) {
            qWarning() << "isHidden error:" << reply.error();
            return true;
        }
        return reply.value();
    }
    return true;
}

void FullBackgroundWidget::HideMultiview()
{
    if (initMultiviewDbus()) {
        QDBusMessage result = m_dbusIfMultiview->call("hide");
        if(result.type() == QDBusMessage::ErrorMessage) {
            qWarning() << "HideMultiview error:" << result.errorMessage();
        }
    }
}

void FullBackgroundWidget::ShowMultiview()
{
    if (initMultiviewDbus()) {
        QDBusMessage result = m_dbusIfMultiview->call("show");
        if(result.type() == QDBusMessage::ErrorMessage) {
            qWarning() << "HideMultiview error:" << result.errorMessage();
        }
    }
}
