kylin-display-switch/0000755000175000017500000000000014107351027013566 5ustar fengfengkylin-display-switch/kylin-display-switch.pro0000644000175000017500000000021014100733566020376 0ustar fengfengTEMPLATE = subdirs CONFIG += ordered SUBDIRS = \ daemon \ kds \ mkt \ registerdbus \ daemon2 kylin-display-switch/man/0000755000175000017500000000000014107351027014341 5ustar fengfengkylin-display-switch/man/emdaemon.10000644000175000017500000000051014107351027016204 0ustar fengfeng.\"Man Page for Emdaemon .TH Emdaemon 1 "18 August 2021" "UKUI Desktop Environment" .SH "NAME" Emdaemon \- Shortcut key daemon .SH "SYNOPSIS" .B emdaemon .SH "DESCRIPTION" OSD Daemon1 applications .SH "AUTHORS" .SS This Manual Page has been written for the UKUI Desktop Environment by: sundagao (2021) kylin-display-switch/man/mktip.10000644000175000017500000000046014107351027015547 0ustar fengfeng.\"Man Page for Mktip .TH Mktip 1 "18 August 2021" "UKUI Desktop Environment" .SH "NAME" Mktip \- Hotkey status .SH "SYNOPSIS" .B mktip .SH "DESCRIPTION" OSD Hotkey status .SH "AUTHORS" .SS This Manual Page has been written for the UKUI Desktop Environment by: sundagao (2021) kylin-display-switch/man/kmdaemon.10000644000175000017500000000050714107351027016220 0ustar fengfeng.\"Man Page for Kmdaemon .TH Kmdaemon 1 "18 August 2021" "UKUI Desktop Environment" .SH "NAME" Kmdaemon \-Shortcut key daemon .SH "SYNOPSIS" .B kmdaemon .SH "DESCRIPTION" OSD Daemon2 applications .SH "AUTHORS" .SS This Manual Page has been written for the UKUI Desktop Environment by: sundagao (2021) kylin-display-switch/man/launchdbus.10000644000175000017500000000050614107351027016554 0ustar fengfeng.\"Man Page for Launchdbus .TH Launchdbus 1 "18 August 2021" "UKUI Desktop Environment" .SH "NAME" Launchdbus \- Dbus interface .SH "SYNOPSIS" .B launchdbus .SH "DESCRIPTION" OSD dbus interface .SH "AUTHORS" .SS This Manual Page has been written for the UKUI Desktop Environment by: sundagao (2021) kylin-display-switch/man/kydisplayswitch.10000644000175000017500000000060114107351027017653 0ustar fengfeng.\"Man Page for Kydisplayswitch .TH Kydisplay 1 "18 August 2021" "UKUI Desktop Environment" .SH "NAME" Kydisplayswitch \- Gui tool for display switching .SH "SYNOPSIS" .B kydisplayswitch .SH "DESCRIPTION" Kydisplayswitch is Gui tool for display switching .SH "AUTHORS" .SS This Manual Page has been written for the UKUI Desktop Environment by: sundagao (2021) kylin-display-switch/shared/0000755000175000017500000000000014100733566015041 5ustar fengfengkylin-display-switch/shared/qtsingleapplication/0000755000175000017500000000000014100733566021113 5ustar fengfengkylin-display-switch/shared/qtsingleapplication/qtsingleapplication.h0000644000175000017500000000422114100733566025335 0ustar fengfeng/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ****************************************************************************/ #include QT_FORWARD_DECLARE_CLASS(QSharedMemory) //namespace SharedTools { class QtLocalPeer; class QtSingleApplication : public QApplication { Q_OBJECT public: QtSingleApplication(const QString &id, int &argc, char **argv); ~QtSingleApplication(); bool isRunning(qint64 pid = -1); void setActivationWindow(QWidget* aw, bool activateOnMessage = true); QWidget* activationWindow() const; bool event(QEvent *event); QString applicationId() const; void setBlock(bool value); bool sendMessage(const QString &message, int timeout = 5000, qint64 pid = -1); void activateWindow(); Q_SIGNALS: void messageReceived(const QString &message, QObject *socket); void fileOpenRequest(const QString &file); private: QString instancesFileName(const QString &appId); qint64 firstPeer; QSharedMemory *instances; QtLocalPeer *pidPeer; QWidget *actWin; QString appId; bool block; }; //} // namespace SharedTools kylin-display-switch/shared/qtsingleapplication/qtsingleapplication.pri0000644000175000017500000000067114100733566025705 0ustar fengfengINCLUDEPATH += $$PWD DEPENDPATH += $$PWD HEADERS += $$PWD/qtsingleapplication.h $$PWD/qtlocalpeer.h SOURCES += $$PWD/qtsingleapplication.cpp $$PWD/qtlocalpeer.cpp QT *= network widgets gotqtlockedfile = $$find(HEADERS, .*qtlockedfile.h) isEmpty(gotqtlockedfile):include(../qtlockedfile/qtlockedfile.pri) win32:contains(TEMPLATE, lib):contains(CONFIG, shared) { DEFINES += QT_QTSINGLEAPPLICATION_EXPORT=__declspec(dllexport) } kylin-display-switch/shared/qtsingleapplication/qtsingleapplication.cpp0000644000175000017500000001333114100733566025672 0ustar fengfeng/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ****************************************************************************/ #include "qtsingleapplication.h" #include "qtlocalpeer.h" #include #include #include #include #include //namespace SharedTools { static const int instancesSize = 1024; static QString instancesLockFilename(const QString &appSessionId) { const QChar slash(QLatin1Char('/')); QString res = QDir::tempPath(); if (!res.endsWith(slash)) res += slash; return res + appSessionId + QLatin1String("-instances"); } QtSingleApplication::QtSingleApplication(const QString &appId, int &argc, char **argv) : QApplication(argc, argv), firstPeer(-1), pidPeer(0) { this->appId = appId; const QString appSessionId = QtLocalPeer::appSessionId(appId); // This shared memory holds a zero-terminated array of active (or crashed) instances instances = new QSharedMemory(appSessionId, this); actWin = 0; block = false; // First instance creates the shared memory, later instances attach to it const bool created = instances->create(instancesSize); if (!created) { if (!instances->attach()) { qWarning() << "Failed to initialize instances shared memory: " << instances->errorString(); delete instances; instances = 0; return; } } // QtLockedFile is used to workaround QTBUG-10364 QtLockedFile lockfile(instancesLockFilename(appSessionId)); lockfile.open(QtLockedFile::ReadWrite); lockfile.lock(QtLockedFile::WriteLock); qint64 *pids = static_cast(instances->data()); if (!created) { // Find the first instance that it still running // The whole list needs to be iterated in order to append to it for (; *pids; ++pids) { if (firstPeer == -1 && isRunning(*pids)) firstPeer = *pids; } } // Add current pid to list and terminate it *pids++ = QCoreApplication::applicationPid(); *pids = 0; pidPeer = new QtLocalPeer(this, appId + QLatin1Char('-') + QString::number(QCoreApplication::applicationPid())); connect(pidPeer, &QtLocalPeer::messageReceived, this, &QtSingleApplication::messageReceived); pidPeer->isClient(); lockfile.unlock(); } QtSingleApplication::~QtSingleApplication() { if (!instances) return; const qint64 appPid = QCoreApplication::applicationPid(); QtLockedFile lockfile(instancesLockFilename(QtLocalPeer::appSessionId(appId))); lockfile.open(QtLockedFile::ReadWrite); lockfile.lock(QtLockedFile::WriteLock); // Rewrite array, removing current pid and previously crashed ones qint64 *pids = static_cast(instances->data()); qint64 *newpids = pids; for (; *pids; ++pids) { if (*pids != appPid && isRunning(*pids)) *newpids++ = *pids; } *newpids = 0; lockfile.unlock(); } bool QtSingleApplication::event(QEvent *event) { if (event->type() == QEvent::FileOpen) { QFileOpenEvent *foe = static_cast(event); emit fileOpenRequest(foe->file()); return true; } return QApplication::event(event); } bool QtSingleApplication::isRunning(qint64 pid) { if (pid == -1) { pid = firstPeer; if (pid == -1) return false; } QtLocalPeer peer(this, appId + QLatin1Char('-') + QString::number(pid, 10)); return peer.isClient(); } bool QtSingleApplication::sendMessage(const QString &message, int timeout, qint64 pid) { if (pid == -1) { pid = firstPeer; if (pid == -1) return false; } QtLocalPeer peer(this, appId + QLatin1Char('-') + QString::number(pid, 10)); return peer.sendMessage(message, timeout, block); } QString QtSingleApplication::applicationId() const { return appId; } void QtSingleApplication::setBlock(bool value) { block = value; } void QtSingleApplication::setActivationWindow(QWidget *aw, bool activateOnMessage) { actWin = aw; if (!pidPeer) return; if (activateOnMessage) connect(pidPeer, &QtLocalPeer::messageReceived, this, &QtSingleApplication::activateWindow); else disconnect(pidPeer, &QtLocalPeer::messageReceived, this, &QtSingleApplication::activateWindow); } QWidget* QtSingleApplication::activationWindow() const { return actWin; } void QtSingleApplication::activateWindow() { if (actWin) { actWin->setWindowState(actWin->windowState() & ~Qt::WindowMinimized); actWin->raise(); actWin->activateWindow(); } } //} // namespace SharedTools kylin-display-switch/shared/qtsingleapplication/qtlocalpeer.cpp0000644000175000017500000001365214100733566024141 0ustar fengfeng/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ****************************************************************************/ #include "qtlocalpeer.h" #include #include #include #if defined(Q_OS_WIN) #include #include typedef BOOL(WINAPI*PProcessIdToSessionId)(DWORD,DWORD*); static PProcessIdToSessionId pProcessIdToSessionId = 0; #endif #if defined(Q_OS_UNIX) #include #include #endif //namespace SharedTools { static const char ack[] = "ack"; QString QtLocalPeer::appSessionId(const QString &appId) { QByteArray idc = appId.toUtf8(); quint16 idNum = qChecksum(idc.constData(), idc.size()); //### could do: two 16bit checksums over separate halves of id, for a 32bit result - improved uniqeness probability. Every-other-char split would be best. QString res = QLatin1String("qtsingleapplication-") + QString::number(idNum, 16); #if defined(Q_OS_WIN) if (!pProcessIdToSessionId) { QLibrary lib(QLatin1String("kernel32")); pProcessIdToSessionId = (PProcessIdToSessionId)lib.resolve("ProcessIdToSessionId"); } if (pProcessIdToSessionId) { DWORD sessionId = 0; pProcessIdToSessionId(GetCurrentProcessId(), &sessionId); res += QLatin1Char('-') + QString::number(sessionId, 16); } #else res += QLatin1Char('-') + QString::number(::getuid(), 16); #endif return res; } QtLocalPeer::QtLocalPeer(QObject *parent, const QString &appId) : QObject(parent), id(appId) { if (id.isEmpty()) id = QCoreApplication::applicationFilePath(); //### On win, check if this returns .../argv[0] without casefolding; .\MYAPP == .\myapp on Win socketName = appSessionId(id); server = new QLocalServer(this); QString lockName = QDir(QDir::tempPath()).absolutePath() + QLatin1Char('/') + socketName + QLatin1String("-lockfile"); lockFile.setFileName(lockName); lockFile.open(QIODevice::ReadWrite); } bool QtLocalPeer::isClient() { if (lockFile.isLocked()) return false; if (!lockFile.lock(QtLockedFile::WriteLock, false)) return true; if (!QLocalServer::removeServer(socketName)) qWarning("QtSingleCoreApplication: could not cleanup socket"); bool res = server->listen(socketName); if (!res) qWarning("QtSingleCoreApplication: listen on local socket failed, %s", qPrintable(server->errorString())); QObject::connect(server, &QLocalServer::newConnection, this, &QtLocalPeer::receiveConnection); return false; } bool QtLocalPeer::sendMessage(const QString &message, int timeout, bool block) { if (!isClient()) return false; QLocalSocket socket; bool connOk = false; for (int i = 0; i < 2; i++) { // Try twice, in case the other instance is just starting up socket.connectToServer(socketName); connOk = socket.waitForConnected(timeout/2); if (connOk || i) break; int ms = 250; #if defined(Q_OS_WIN) Sleep(DWORD(ms)); #else struct timespec ts = {ms / 1000, (ms % 1000) * 1000 * 1000}; nanosleep(&ts, NULL); #endif } if (!connOk) return false; QByteArray uMsg(message.toUtf8()); QDataStream ds(&socket); ds.writeBytes(uMsg.constData(), uMsg.size()); bool res = socket.waitForBytesWritten(timeout); res &= socket.waitForReadyRead(timeout); // wait for ack res &= (socket.read(qstrlen(ack)) == ack); if (block) // block until peer disconnects socket.waitForDisconnected(-1); return res; } void QtLocalPeer::receiveConnection() { QLocalSocket* socket = server->nextPendingConnection(); if (!socket) return; // Why doesn't Qt have a blocking stream that takes care of this shait??? while (socket->bytesAvailable() < static_cast(sizeof(quint32))) { if (!socket->isValid()) // stale request return; socket->waitForReadyRead(1000); } QDataStream ds(socket); QByteArray uMsg; quint32 remaining; ds >> remaining; uMsg.resize(remaining); int got = 0; char* uMsgBuf = uMsg.data(); //qDebug() << "RCV: remaining" << remaining; do { got = ds.readRawData(uMsgBuf, remaining); remaining -= got; uMsgBuf += got; //qDebug() << "RCV: got" << got << "remaining" << remaining; } while (remaining && got >= 0 && socket->waitForReadyRead(2000)); //### error check: got<0 if (got < 0) { qWarning() << "QtLocalPeer: Message reception failed" << socket->errorString(); delete socket; return; } // ### async this QString message = QString::fromUtf8(uMsg.constData(), uMsg.size()); socket->write(ack, qstrlen(ack)); socket->waitForBytesWritten(1000); emit messageReceived(message, socket); // ##(might take a long time to return) } //} // namespace SharedTools kylin-display-switch/shared/qtsingleapplication/qtlocalpeer.h0000644000175000017500000000356114100733566023604 0ustar fengfeng/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ****************************************************************************/ #include #include #include #include //namespace SharedTools { class QtLocalPeer : public QObject { Q_OBJECT public: explicit QtLocalPeer(QObject *parent = 0, const QString &appId = QString()); bool isClient(); bool sendMessage(const QString &message, int timeout, bool block); QString applicationId() const { return id; } static QString appSessionId(const QString &appId); Q_SIGNALS: void messageReceived(const QString &message, QObject *socket); protected: void receiveConnection(); QString id; QString socketName; QLocalServer* server; QtLockedFile lockFile; }; //} // namespace SharedTools kylin-display-switch/shared/qtsingleapplication/README.txt0000644000175000017500000000043214100733566022610 0ustar fengfengThis is the src directory of the QtSingleApplication solution integrated over from addons/main/utils/qtsingleapplication/src . namespace.patch was applied to introduce the SharedTools namespace. It additionally requires the QtLockedFile solution. History: 16.05.2008 Integrated kylin-display-switch/shared/qtsingleapplication/namespace.patch0000644000175000017500000000600414100733566024070 0ustar fengfeng --- qtlocalpeer.cpp 1970-01-01 01:00:00.000000000 +++ qtlocalpeer.cpp 2008/05/16 10:36:53.000000000 @@ -13,6 +13,8 @@ #include #endif +namespace SharedTools { + const char* QtLocalPeer::ack = "ack"; QtLocalPeer::QtLocalPeer(QObject* parent, const QString &appId) @@ -139,3 +141,5 @@ delete socket; emit messageReceived(message); // ##(might take a long time to return) } + +} --- qtlocalpeer.h 1970-01-01 01:00:00.000000000 +++ qtlocalpeer.h 2008/05/16 10:36:53.000000000 @@ -1,9 +1,11 @@ + #include #include #include #include +namespace SharedTools { class QtLocalPeer : public QObject { @@ -31,3 +33,5 @@ private: static const char* ack; }; + +} // SharedTools --- qtsingleapplication.cpp 1970-01-01 01:00:00.000000000 +++ qtsingleapplication.cpp 2008/05/16 10:36:53.000000000 @@ -3,6 +3,8 @@ #include "qtlocalpeer.h" #include +namespace SharedTools { + void QtSingleApplication::sysInit(const QString &appId) { actWin = 0; @@ -95,3 +97,5 @@ actWin->activateWindow(); } } + +} --- qtsingleapplication.h 1970-01-01 01:00:00.000000000 +++ qtsingleapplication.h 2008/05/16 10:36:53.000000000 @@ -1,6 +1,8 @@ #include +namespace SharedTools { + class QtLocalPeer; class QtSingleApplication : public QApplication @@ -47,3 +49,5 @@ QtLocalPeer *peer; QWidget *actWin; }; + +} --- qtsingleapplication.pri 1970-01-01 01:00:00.000000000 +++ qtsingleapplication.pri 2008/05/16 10:36:53.000000000 @@ -6,7 +6,7 @@ QT *= network gotqtlockedfile = $$find(HEADERS, .*qtlockedfile.h) -isEmpty(gotqtlockedfile):include(../../qtlockedfile/src/qtlockedfile.pri) +isEmpty(gotqtlockedfile):include(../qtlockedfile/qtlockedfile.pri) win32:contains(TEMPLATE, lib):contains(CONFIG, shared) { --- qtsinglecoreapplication.cpp 1970-01-01 01:00:00.000000000 +++ qtsinglecoreapplication.cpp 2008/05/16 10:36:53.000000000 @@ -2,6 +2,7 @@ #include "qtsinglecoreapplication.h" #include "qtlocalpeer.h" +namespace SharedTools { QtSingleCoreApplication::QtSingleCoreApplication(int &argc, char **argv) : QCoreApplication(argc, argv) @@ -36,3 +37,4 @@ return peer->applicationId(); } +} --- qtsinglecoreapplication.h 1970-01-01 01:00:00.000000000 +++ qtsinglecoreapplication.h 2008/05/16 10:36:53.000000000 @@ -1,6 +1,8 @@ #include +namespace SharedTools { + class QtLocalPeer; class QtSingleCoreApplication : public QCoreApplication @@ -25,3 +27,5 @@ private: QtLocalPeer* peer; }; + +} --- qtsinglecoreapplication.pri 1970-01-01 01:00:00.000000000 +++ qtsinglecoreapplication.pri 2008/05/16 10:36:53.000000000 @@ -6,7 +6,7 @@ QT *= network gotqtlockedfile = $$find(HEADERS, .*qtlockedfile.h) -isEmpty(gotqtlockedfile):include(../../qtlockedfile/src/qtlockedfile.pri) +isEmpty(gotqtlockedfile):include(../qtlockedfile/qtlockedfile.pri) win32:contains(TEMPLATE, lib):contains(CONFIG, shared) { kylin-display-switch/shared/qtlockedfile/0000755000175000017500000000000014100733566017507 5ustar fengfengkylin-display-switch/shared/qtlockedfile/qtlockedfile.h0000644000175000017500000000427614100733566022337 0ustar fengfeng/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ****************************************************************************/ #pragma once #include #if defined(Q_OS_WIN) # if !defined(QT_QTLOCKEDFILE_EXPORT) && !defined(QT_QTLOCKEDFILE_IMPORT) # define QT_QTLOCKEDFILE_EXPORT # elif defined(QT_QTLOCKEDFILE_IMPORT) # if defined(QT_QTLOCKEDFILE_EXPORT) # undef QT_QTLOCKEDFILE_EXPORT # endif # define QT_QTLOCKEDFILE_EXPORT __declspec(dllimport) # elif defined(QT_QTLOCKEDFILE_EXPORT) # undef QT_QTLOCKEDFILE_EXPORT # define QT_QTLOCKEDFILE_EXPORT __declspec(dllexport) # endif #else # define QT_QTLOCKEDFILE_EXPORT #endif //namespace SharedTools { class QT_QTLOCKEDFILE_EXPORT QtLockedFile : public QFile { public: enum LockMode { NoLock = 0, ReadLock, WriteLock }; QtLockedFile(); QtLockedFile(const QString &name); ~QtLockedFile(); bool lock(LockMode mode, bool block = true); bool unlock(); bool isLocked() const; LockMode lockMode() const; private: #ifdef Q_OS_WIN Qt::HANDLE m_semaphore_hnd; Qt::HANDLE m_mutex_hnd; #endif LockMode m_lock_mode; }; //} // namespace SharedTools kylin-display-switch/shared/qtlockedfile/qtlockedfile_unix.cpp0000644000175000017500000000523114100733566023725 0ustar fengfeng/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ****************************************************************************/ #include "qtlockedfile.h" #include #include #include #include //namespace SharedTools { bool QtLockedFile::lock(LockMode mode, bool block) { if (!isOpen()) { qWarning("QtLockedFile::lock(): file is not opened"); return false; } if (mode == NoLock) return unlock(); if (mode == m_lock_mode) return true; if (m_lock_mode != NoLock) unlock(); struct flock fl; fl.l_whence = SEEK_SET; fl.l_start = 0; fl.l_len = 0; fl.l_type = (mode == ReadLock) ? F_RDLCK : F_WRLCK; int cmd = block ? F_SETLKW : F_SETLK; int ret = fcntl(handle(), cmd, &fl); if (ret == -1) { if (errno != EINTR && errno != EAGAIN) qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno)); return false; } m_lock_mode = mode; return true; } bool QtLockedFile::unlock() { if (!isOpen()) { qWarning("QtLockedFile::unlock(): file is not opened"); return false; } if (!isLocked()) return true; struct flock fl; fl.l_whence = SEEK_SET; fl.l_start = 0; fl.l_len = 0; fl.l_type = F_UNLCK; int ret = fcntl(handle(), F_SETLKW, &fl); if (ret == -1) { qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno)); return false; } m_lock_mode = NoLock; remove(); return true; } QtLockedFile::~QtLockedFile() { if (isOpen()) unlock(); } //} // namespace SharedTools kylin-display-switch/shared/qtlockedfile/qtlockedfile_win.cpp0000644000175000017500000001403314100733566023537 0ustar fengfeng/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ****************************************************************************/ #include "qtlockedfile.h" #include #include //namespace SharedTools { #define SEMAPHORE_PREFIX "QtLockedFile semaphore " #define MUTEX_PREFIX "QtLockedFile mutex " #define SEMAPHORE_MAX 100 static QString errorCodeToString(DWORD errorCode) { QString result; char *data = 0; FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 0, errorCode, 0, (char*)&data, 0, 0); result = QString::fromLocal8Bit(data); if (data != 0) LocalFree(data); if (result.endsWith(QLatin1Char('\n'))) result.truncate(result.length() - 1); return result; } bool QtLockedFile::lock(LockMode mode, bool block) { if (!isOpen()) { qWarning("QtLockedFile::lock(): file is not opened"); return false; } if (mode == m_lock_mode) return true; if (m_lock_mode != 0) unlock(); if (m_semaphore_hnd == 0) { QFileInfo fi(*this); QString sem_name = QString::fromLatin1(SEMAPHORE_PREFIX) + fi.absoluteFilePath().toLower(); m_semaphore_hnd = CreateSemaphoreW(0, SEMAPHORE_MAX, SEMAPHORE_MAX, (TCHAR*)sem_name.utf16()); if (m_semaphore_hnd == 0) { qWarning("QtLockedFile::lock(): CreateSemaphore: %s", errorCodeToString(GetLastError()).toLatin1().constData()); return false; } } bool gotMutex = false; int decrement; if (mode == ReadLock) { decrement = 1; } else { decrement = SEMAPHORE_MAX; if (m_mutex_hnd == 0) { QFileInfo fi(*this); QString mut_name = QString::fromLatin1(MUTEX_PREFIX) + fi.absoluteFilePath().toLower(); m_mutex_hnd = CreateMutexW(NULL, FALSE, (TCHAR*)mut_name.utf16()); if (m_mutex_hnd == 0) { qWarning("QtLockedFile::lock(): CreateMutex: %s", errorCodeToString(GetLastError()).toLatin1().constData()); return false; } } DWORD res = WaitForSingleObject(m_mutex_hnd, block ? INFINITE : 0); if (res == WAIT_TIMEOUT) return false; if (res == WAIT_FAILED) { qWarning("QtLockedFile::lock(): WaitForSingleObject (mutex): %s", errorCodeToString(GetLastError()).toLatin1().constData()); return false; } gotMutex = true; } for (int i = 0; i < decrement; ++i) { DWORD res = WaitForSingleObject(m_semaphore_hnd, block ? INFINITE : 0); if (res == WAIT_TIMEOUT) { if (i) { // A failed nonblocking rw locking. Undo changes to semaphore. if (ReleaseSemaphore(m_semaphore_hnd, i, NULL) == 0) { qWarning("QtLockedFile::unlock(): ReleaseSemaphore: %s", errorCodeToString(GetLastError()).toLatin1().constData()); // Fall through } } if (gotMutex) ReleaseMutex(m_mutex_hnd); return false; } if (res != WAIT_OBJECT_0) { if (gotMutex) ReleaseMutex(m_mutex_hnd); qWarning("QtLockedFile::lock(): WaitForSingleObject (semaphore): %s", errorCodeToString(GetLastError()).toLatin1().constData()); return false; } } m_lock_mode = mode; if (gotMutex) ReleaseMutex(m_mutex_hnd); return true; } bool QtLockedFile::unlock() { if (!isOpen()) { qWarning("QtLockedFile::unlock(): file is not opened"); return false; } if (!isLocked()) return true; int increment; if (m_lock_mode == ReadLock) increment = 1; else increment = SEMAPHORE_MAX; DWORD ret = ReleaseSemaphore(m_semaphore_hnd, increment, 0); if (ret == 0) { qWarning("QtLockedFile::unlock(): ReleaseSemaphore: %s", errorCodeToString(GetLastError()).toLatin1().constData()); return false; } m_lock_mode = QtLockedFile::NoLock; remove(); return true; } QtLockedFile::~QtLockedFile() { if (isOpen()) unlock(); if (m_mutex_hnd != 0) { DWORD ret = CloseHandle(m_mutex_hnd); if (ret == 0) { qWarning("QtLockedFile::~QtLockedFile(): CloseHandle (mutex): %s", errorCodeToString(GetLastError()).toLatin1().constData()); } m_mutex_hnd = 0; } if (m_semaphore_hnd != 0) { DWORD ret = CloseHandle(m_semaphore_hnd); if (ret == 0) { qWarning("QtLockedFile::~QtLockedFile(): CloseHandle (semaphore): %s", errorCodeToString(GetLastError()).toLatin1().constData()); } m_semaphore_hnd = 0; } } //} // namespace SharedTools kylin-display-switch/shared/qtlockedfile/qtlockedfile.cpp0000644000175000017500000001110714100733566022661 0ustar fengfeng/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ****************************************************************************/ #include "qtlockedfile.h" //namespace SharedTools { /*! \class QtLockedFile \brief The QtLockedFile class extends QFile with advisory locking functions. A file may be locked in read or write mode. Multiple instances of \e QtLockedFile, created in multiple processes running on the same machine, may have a file locked in read mode. Exactly one instance may have it locked in write mode. A read and a write lock cannot exist simultaneously on the same file. The file locks are advisory. This means that nothing prevents another process from manipulating a locked file using QFile or file system functions offered by the OS. Serialization is only guaranteed if all processes that access the file use QtLockedFile. Also, while holding a lock on a file, a process must not open the same file again (through any API), or locks can be unexpectedly lost. The lock provided by an instance of \e QtLockedFile is released whenever the program terminates. This is true even when the program crashes and no destructors are called. */ /*! \enum QtLockedFile::LockMode This enum describes the available lock modes. \value ReadLock A read lock. \value WriteLock A write lock. \value NoLock Neither a read lock nor a write lock. */ /*! Constructs an unlocked \e QtLockedFile object. This constructor behaves in the same way as \e QFile::QFile(). \sa QFile::QFile() */ QtLockedFile::QtLockedFile() : QFile() { #ifdef Q_OS_WIN m_semaphore_hnd = 0; m_mutex_hnd = 0; #endif m_lock_mode = NoLock; } /*! Constructs an unlocked QtLockedFile object with file \a name. This constructor behaves in the same way as \e QFile::QFile(const QString&). \sa QFile::QFile() */ QtLockedFile::QtLockedFile(const QString &name) : QFile(name) { #ifdef Q_OS_WIN m_semaphore_hnd = 0; m_mutex_hnd = 0; #endif m_lock_mode = NoLock; } /*! Returns \e true if this object has a in read or write lock; otherwise returns \e false. \sa lockMode() */ bool QtLockedFile::isLocked() const { return m_lock_mode != NoLock; } /*! Returns the type of lock currently held by this object, or \e QtLockedFile::NoLock. \sa isLocked() */ QtLockedFile::LockMode QtLockedFile::lockMode() const { return m_lock_mode; } /*! \fn bool QtLockedFile::lock(LockMode mode, bool block = true) Obtains a lock of type \a mode. If \a block is true, this function will block until the lock is acquired. If \a block is false, this function returns \e false immediately if the lock cannot be acquired. If this object already has a lock of type \a mode, this function returns \e true immediately. If this object has a lock of a different type than \a mode, the lock is first released and then a new lock is obtained. This function returns \e true if, after it executes, the file is locked by this object, and \e false otherwise. \sa unlock(), isLocked(), lockMode() */ /*! \fn bool QtLockedFile::unlock() Releases a lock. If the object has no lock, this function returns immediately. This function returns \e true if, after it executes, the file is not locked by this object, and \e false otherwise. \sa lock(), isLocked(), lockMode() */ /*! \fn QtLockedFile::~QtLockedFile() Destroys the \e QtLockedFile object. If any locks were held, they are released. */ //} // namespace SharedTools kylin-display-switch/shared/qtlockedfile/qtlockedfile.pri0000644000175000017500000000047614100733566022700 0ustar fengfengINCLUDEPATH += $$PWD DEPENDPATH += $$PWD HEADERS += $$PWD/qtlockedfile.h SOURCES += $$PWD/qtlockedfile.cpp unix:SOURCES += $$PWD/qtlockedfile_unix.cpp win32:SOURCES += $$PWD/qtlockedfile_win.cpp win32:contains(TEMPLATE, lib):contains(CONFIG, shared) { DEFINES += QT_QTLOCKEDFILE_EXPORT=__declspec(dllexport) } kylin-display-switch/shared/qtlockedfile/README.txt0000644000175000017500000000041514100733566021205 0ustar fengfengThis is the src directory of the QtLockedFile solution integrated over from addons/main/utils/qtlockedfile/src . namespace.patch was applied to introduce the SharedTools namespace. It is required by the QtSingleApplication solution. History: 16.05.2008 Integrated kylin-display-switch/shared/qtlockedfile/namespace.patch0000644000175000017500000000246214100733566022470 0ustar fengfeng --- qtlockedfile.cpp 1970-01-01 01:00:00.000000000 +++ qtlockedfile.cpp 2008/05/16 10:51:19.000000000 @@ -1,5 +1,7 @@ #include "qtlockedfile.h" +namespace SharedTools { + /*! \class QtLockedFile @@ -123,3 +125,5 @@ Destroys the \e QtLockedFile object. If any locks were held, they are released. */ + +} --- qtlockedfile.h 1970-01-01 01:00:00.000000000 +++ qtlockedfile.h 2008/05/16 10:51:19.000000000 @@ -19,6 +19,8 @@ # define QT_QTLOCKEDFILE_EXPORT #endif +namespace SharedTools { + class QT_QTLOCKEDFILE_EXPORT QtLockedFile : public QFile { public: @@ -41,4 +43,6 @@ LockMode m_lock_mode; }; +} + #endif --- qtlockedfile_unix.cpp 1970-01-01 01:00:00.000000000 +++ qtlockedfile_unix.cpp 2008/05/16 10:51:19.000000000 @@ -5,6 +5,8 @@ #include "qtlockedfile.h" +namespace SharedTools { + bool QtLockedFile::lock(LockMode mode, bool block) { if (!isOpen()) { @@ -73,3 +75,4 @@ unlock(); } +} --- qtlockedfile_win.cpp 1970-01-01 01:00:00.000000000 +++ qtlockedfile_win.cpp 2008/05/16 10:51:19.000000000 @@ -2,6 +2,8 @@ #include #include +namespace SharedTools { + #define SEMAPHORE_PREFIX "QtLockedFile semaphore " #define MUTEX_PREFIX "QtLockedFile mutex " #define SEMAPHORE_MAX 100 @@ -168,3 +170,4 @@ } } +} kylin-display-switch/kylin-display-switch-daemon.desktop0000644000175000017500000000041014100733566022512 0ustar fengfeng[Desktop Entry] Name=Kylin Display Switch Daemon Name[zh_CN]=麒麟显示切换守护进程 Comment=Kylin Display Switch Daemon Comment[zh_CN]=麒麟显示切换守护进程 Exec=/usr/bin/kmdaemon StartupNotify=false Terminal=false Type=Application NoDisplay=true kylin-display-switch/utils/0000755000175000017500000000000014100733566014733 5ustar fengfengkylin-display-switch/utils/mappingtable.cpp0000644000175000017500000000043014100733566020077 0ustar fengfeng#include "mappingtable.h" MappingTable::MappingTable(QObject *parent) : QObject(parent) { metaTipIcon = QMetaEnum::fromType(); } QString MappingTable::keyCodeToString(int code){ return metaTipIcon.valueToKey(code); //未匹配到则返回空 } kylin-display-switch/utils/mappingtable.h0000644000175000017500000000157014100733566017552 0ustar fengfeng#ifndef MAPPINGTABLE_H #define MAPPINGTABLE_H #include #include enum { CAMERAKEY = 212, FLIGHTKEY = 238, MICROPHONEKEY = 248, SCREENKEY = 431, TOUCHPADKEY = 530, TOUCHPADONKEY = 531, TOUCHPADOFFKEY = 532, SCREENLOCKKEY = 689, }; class MappingTable : public QObject { Q_OBJECT public: explicit MappingTable(QObject *parent = nullptr); public: QString keyCodeToString(int code); public: QMetaEnum metaTipIcon; enum MTIKey{ CapslockOn, // 0 CapslockOff, NumlockOn, // 2 NumlockOff, TouchpadOn, // 4 TouchpadOff, MicrophoneOn, // 6 MicrophoneOff, CameraOn, // 8 CameraOff, FlightOn, // 10 FlightOff, WlanOn, // 12 WlanOff, HandleKeys, }; Q_ENUM(MTIKey) }; #endif // MAPPINGTABLE_H kylin-display-switch/utils/utils.pri0000644000175000017500000000020414100733566016603 0ustar fengfengSOURCES += \ $$PWD/mappingtable.cpp \ HEADERS += \ $$PWD/mappingtable.h \ INCLUDEPATH += \ $$PWD \ kylin-display-switch/mkt/0000755000175000017500000000000014107351661014365 5ustar fengfengkylin-display-switch/mkt/widget.h0000644000175000017500000000312214100733566016020 0ustar fengfeng/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, 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, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef WIDGET_H #define WIDGET_H #include #include #include #include #include #include #include "mappingtable.h" namespace Ui { class Widget; } class Widget : public QWidget { Q_OBJECT public: explicit Widget(QWidget *parent = 0); ~Widget(); public: void setupComponent(); void setMKTgeometry(); private: Ui::Widget *ui; private: void createTrayIcon(); QSystemTrayIcon *trayIcon; private: QTimer * pTimer; MappingTable * pMappingTable; QDBusInterface * iface; private: void flightToggleClick(); public slots: void showTipsOnDesktop(int index); void refreshTrayIcon(); }; #endif // WIDGET_H kylin-display-switch/mkt/main.cpp0000644000175000017500000000400014100733566016010 0ustar fengfeng/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, 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, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "widget.h" #include #include #include "qtsingleapplication.h" #include int getCurrentScreenWidth(){ Display * pDis = XOpenDisplay(0); if (NULL == pDis){ return 0; } Screen * pScreen = DefaultScreenOfDisplay(pDis); if (NULL == pScreen){ return 0; } int width = pScreen->width; XCloseDisplay(pDis); return width; } int main(int argc, char *argv[]) { if (getCurrentScreenWidth() > 2560){ QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); } QString id = QString("mkt" + QLatin1String(getenv("DISPLAY"))); QtSingleApplication app(id, argc, argv); if (app.isRunning()){ // app.sendMessage("hello world!"); return 0; /* EXIT_SUCCESS */ } QTranslator qtTranslator; qtTranslator.load(QString(":/%1").arg(QLocale::system().name())); app.installTranslator(&qtTranslator); Widget w; // QObject::connect(&app, &QtSingleApplication::messageReceived, &w, &Widget::msgReceiveAnotherOne); w.show(); w.hide(); return app.exec(); } kylin-display-switch/mkt/mkt.pro0000644000175000017500000000243014100733566015702 0ustar fengfeng#------------------------------------------------- # # Project created by QtCreator 2020-11-12T15:38:52 # #------------------------------------------------- QT += core gui dbus greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = mktip TEMPLATE = app # The following define makes your compiler emit warnings if you use # any feature of Qt which as been marked as deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS include (../shared/qtsingleapplication/qtsingleapplication.pri) include (../utils/utils.pri) LIBS += -lX11 -lgsettings-qt # You can also make your code fail to compile if you use deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 target.source += $$TARGET target.path = /usr/bin INSTALLS += \ target \ SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h FORMS += \ widget.ui RESOURCES += \ res/img.qrc TRANSLATIONS += \ res/zh_CN.ts \ kylin-display-switch/mkt/res/0000755000175000017500000000000014100733566015157 5ustar fengfengkylin-display-switch/mkt/res/img/0000755000175000017500000000000014100733566015733 5ustar fengfengkylin-display-switch/mkt/res/img/CameraOn.png0000644000175000017500000000440414100733566020130 0ustar fengfengPNG  IHDRff9bIDATxKYǟ}mmIf"v^4"37ą.J2 uDl,TܽА(Bobًq2$B&9 5jԨQFct>*3z"XNeJ@BkQXZ@U VG>'.|JPZt15(ؑ+10>Kb&h;FmޯGpԠ|jZ?fc؃pvaadM ';GZCFOYeZ8 Qspe]F[@88'bB<5@'Q-PO`:0v,F {`\4zf\pJTgFd8Si VR0ikBLLsB4m@"XV8YP0fcRQ0&ՙryAST:rT*A8nrG(J$M$I]$JY>߷D"'T*D1y 0^_<;0py뽾./,<|.RTK$o|o#L46v{X, !P(b؋++c lX,nP0-ѣ_~ð%\{l[ϵ =7 I(?n4736v{EOnbU=ZWn.a>)NgTke,85ztbXn.Q0u՗ gɵ\.W*r|08D"񆂩e}_ߥP<d<\r:gL~.R\{ީ:k$]Bb/Ԯ#I^{<`xW^ BO1 ?O\nrZ>p_XxBO(J҄.+&7Xw:l"ryG6^oWU^ P.:RTQC{}Q7!Oh.>1'-0)?^_Ժv.ZP^ßk%kR^@lYrպFP0L(MzmBFFWXoӖlɵWsWr6U)r4{ -0k<o O|9~CmV7ʶQMo5ZBOX}kq<4Z;Q0*2>0F:y|j7};K/=g{[q]Ҍ<<z -EzD$`X\T*+ʿ<4=:T>4] \>T.V*qp`P~H4Lkd~ a=(wh4zt( w)w)4<<_4mۡt FEzq0y"}Xik`tyX}qU 㸣m{ckJ tz #vO90 j`NtXqI0*b@_ ̉XdFOYd,Pt*`v76{agu;6{nleNX[((3r86(ɎtQQo Vĺn5J8V8$&G"# bu(<@;X*BٻL!\(Euтcc&vQ6ZPtPJ$5!)u#ژpJ jPtG H6P>Ujj[5^À(MّzMZ7iu2'LO>5jԨQFfO=~tOPIENDB`kylin-display-switch/mkt/res/img/TouchpadOn.png0000644000175000017500000000215114100733566020504 0ustar fengfengPNG  IHDRff9b0IDATxj9IIg$M cc ,Ji/аV y䖋Caa:{VTĖy/ҌbX,VQDzUzDL G$в;e6Vm w:6bdq{TdP/*jό9OZQ|[/ @QqB(;yzr(GX '> z2E3 Ƣy*$HM篰xX„V.=c 7=/ QVMhh]~M?2u=DX5~>",3@gM6 KݸȰX5Qa~mcR7.=V?[A˞n\z<̇yNӃ%r0YfU¬f a7yƥ@/ a0B0''ds6VBj6ݎ7''^ŒF/ϧөhr%L&?.// Ͽvl}j<ݾ}Kg8|Z`양!C0! aC0!Lj0! aC0! aFzFhFíLDFDFDƬ+Wd뛪p/ _*a8\Zea a0BC!Fh#4 af0H% \$^[p?6DGq +i7_@ZSM[ROV'bX,ԑ?IENDB`kylin-display-switch/mkt/res/img/WlanOn.png0000644000175000017500000000417014100733566017641 0ustar fengfengPNG  IHDRff9b?IDATxOhW6qJ M"_4P)&PCO!Żk0. vبV\EkbE8'[-UiݱddBXӃ5tFVdfyn73p8p'^k0Tȝ,(ȿ58T7(ʪ[o N9Yu7(hIBR4tƷzy .qHM u:$ HR9BR^jot]([A|9K=A;J }=b8)ZmIP*ZvNNMU!8LGr'@"ADJ(0P8 Th;tHT5s XLeb@Fl;;t@U#?18*wǕl_b;}NLSސJހ3MMSXLeb4bU5jbj#fÙJLVdG@+wǕh(,F`1 E5bn555d2aV-VaT2|1??ljjBc15jms@4]fh4vVk`0) 4x|w4=:sFGǻh6gGǻ==go; *P(`{S`0Ae,..p\mU\u|{qqgTR0tvrc1"L^#B B{ߟ< ;yݻG|d25c1*+[8ָo1ʉo?yn<_iobHPo/3LeYaTonJ-OWTjeY6d{{j1N>ǪYҚ-t{{J5ϱXZphztVbnfV:l=^p8c&%,Zmήizt6)Z[[U*'1˷:Kh*t:_WkZۜNkngY}$k_DQW)avڳp<ŷ.frT:^̹sLξ""ElӞ,˲|>XLRb/R~6[X,rBn;vۥZ1F?(_ؼrXL9s/b/bX~R4y<P`17or9`1 Q(XBb P(,F`1 Q(XBbJ+Sa#aܝW*a$"fUë|M8 сب#z)Lҥ @r'Ai"@ >t:F9$#8@t:ATxݢNG^Yʉ0V1|9 *G;7JdRP)]Pjr+$ ~N'D R$<@|AhJ Cq on—"uU#&Gj$оE]N$b @E5THݤ`!A$>G8B}"$E1rPI:H5[_TﯘɥQNP9YXe~Ch_1!@qBd:8p8?Z@q QIENDB`kylin-display-switch/mkt/res/img/WlanOff.png0000644000175000017500000000411614100733566017777 0ustar fengfengPNG  IHDRff9bIDATxOI{ZKXx 4BBjDr40Sx %J ~Y"x?qoYvyog3A 4hР:YqB"bR#)Z 7)jXT"nMN%Y tkכbQr ))!m:^og O7t&!HQ9RRj_tڃC :! _i(/ ,=0@9$V=j}p 9u#-`XT{ŰE"Y#-a?d0 dl ;O:pɵN*:1mZ#7'i(*478M.%FGbK;N:%bj#IR1ՉHTֈKOg*&1u+*Ud7@vIpbH!*PBbeĘLw&&&wcxN&Sxeg4;u˞+-R1Y>^XHz{^*-Db[*~S6\Y1> UZ^-%ԱjpjْDPq͖ o)ddjwùۑ^<(ȕxL\Y}ed[vKߺHY}N:-B<,N4;z<C2bbR׏/~%;Y>N^EJK}䉰Ա:;p_I9M!eWFsr."l\yԱG2D"uHdd Ա0TJ8 #{^P<,۾266i\";[P(>zѣbQPl;2n9cO̙}mJV5q͙}\](IHA "|prtH,[Jf_CRj ,H6*sZRIA' wT FwwF=om_hT^UŰlJ__+WjT ;Oh5.t%v*lr٧%.=s ~.'}Z5L?}G~@Aԙ~A\Bb!*PBb!*PBb!*P-^X\H/+E.+ޗaW0g2bv/5).H^!0 sB^J̙.aڃ@Wa1_I̙4_3 R{0HA3X,GJ$GOb!RR -G,D_)(>E5+ Q\ U,W5!7I8Z=p .g"̅pn 8LRF- ̥3L`F@8@02`$ Hf+iqlPfYVM,g 97 eڶm~e۶mY!"bjN>?JM,?JM,3Ţ+AqƲ]DZVr/\.V-%_mnZƱf{|UFD,͝^X4wMU`JZ=FDgV/z~BD|&Gb}I&4+u`,巍FۗǠhJە2Y=^d2w{rq}}u:}yɩ7v`krrj(<爧8KIT(a`,,,u;ƕ>o>H35?./1ƞ׻D S(ox$ `ļ|         }C_H S*mW^iLSRS*mWv9H1#iF!IC0`$Mahaz"mVz9P6+ޗ1㻨;/k3{3)!s yM>~ cci y/3.ΘMԃ [psf䇌/ Y\2㹜9 5Mchy<PQQQQQQQQO+{x 7xMXyL Ư/d+r 4))h2PXCJ]=>$)ISDQB܇\=Pjd)zӹZ^rI- gzDQl{0x(- Ct:^t:apr c4[6@$I~#ŋKfl)RQt(OCB,5<2h[ ?`) 5fX88,Ka[(lU0;}S6qarYىRS`qjg f˙ &giwy8a𐢃zdYDxSDD"7;hn>p#|L(DDU|>_ |Y1 L6]SUUM$WAzv)xYAD 偕#ev`rh4On"">{6'(Dm;إ4(җ SWW1blosUXl.H07\T% Re!g8k&"" y<.ka="b8?L0嫦\QX<]SÖPjGܹ(fff;>K0\t'I p311EDL$ cccc3LSG "&dgg/熆.0###;KDׯ#`6oڮ(% "NOOE06?xeu[T?yxI06 !">xr~~~1#ggDĖ[ڿ}*0&rʕDę1[[[oYɓGGG'~wmK}}}lhei/ bY#lQc1֭E!"vu5g#n> b'R)d2י>u"l6&U O޽{/'IDD K0UUϞ=w;cONNN#"NMM-я`V8 W^1ۿwL0/ N۱ah 0p0";w<+vbr pa;.`` 1i !NC0`8 p4G/fG/JWcJ +6;kD}&g݌הG,z  |hQ?!o 3_%'L0KxCţv/q#c p9K7@a%Ewn}咎-c9g8.HNL7ΝNEOJYHŲWad5z',i^#1k?` N0Fq-#0-P`{=e[05f8XAZBo~gB 3E UHBhAq>ek_x]>@hh0=l#04m4M`zXK`$\.O$~]FD,FEwzM,62/?#bܫ%*mC` C`L/PO`yȼXKhhx2>ӒXbXC`ڸX,~@DL&~"WWR3DBP"0m˭ "f2o([Yѷs..J/_-N|_DTj&C`87MDD~\Fg?ƘL,1&'˫koE815u%"iy} \6DD|c|im#dƾ[,$0.ִtR,v^"?"bR*Ӧ<:7;5"bV%ӯZVCD}Zf ytN&4nI&_r;B$f'B˭R3YGӡA` !0C`G`?u:䣣 9::"0dkƧ&0>5 Ok0b`z"-Vz90R+u\ޗn1XQ#UUoԉ[30v8Xp7bVu`"m+,Yc& +$'G/` ap"m8 '(0[c@ĜEvY' [nE p쀄d+a+A8vIkE g8v@VHm|]젂j{n@CVbx=b @nFn7_)y]Y}]$D"H?{>ТIENDB`kylin-display-switch/mkt/res/img/FlightOff.png0000644000175000017500000000416714100733566020321 0ustar fengfengPNG  IHDRff9b>IDATxOIǟSn7 H0 ^0wJ(| Uӊ-vjŤpˡȲ.Ka<ٝy>}f晙F5jԨQTU洳H1fVȯk\D UX33 q(W@J]G-(#@\:a,8&,''}>d+=(^:RqY8c?`X3Hp`0^i'* `e?8ni+n6 D^:?pde@0Zӕ']plݾc L5ctIx`3jlCNWt!ovFc0uv L ,8F(!JXF 7`vݜ/ 㿯!$I(dM;2lDvvUs DP(<-@u}$}/y>P8 ;Ir*5?'Y5fj*$75lB陏IN;u`_!I>NPf}BH[[O>M"1$OLd>}4W8pIŋWñ5$o0'N\} u#Q.'~BH{zz^8 `8/NW: ; J:[F 0gBL^1]<'p1g͂ s/l<($Vѱ$U`byx8:<^퍿0Yf>$ e23I+ Dȩ$jMLd>́>$ݵ[ZZb$ O422!IN$-G/w<|0DN=еϖVGϪ#DtBy38.BH-[`bYo=6GXF455f(Q+xؚ2~GX F<)X;y<`,8,-"_43j8Sr"1<66ŤW+m[P5[z7ZF:wEcc#W8p;i}-=544Zv^oouNYNVӧ۟7Px^ught-\NP3x]nZu`C` i}(R*^ŀ/ZZu`8|@"SOl'   MYgg 2띿wFčKI.RUA5\Eq(M"1( ~ߝ@)0a})RB2ytY)ieMONNiںPfi ,uuuӅr zliyj}k|"hC鋺,EJnVm襛1cU%[پF##tᯯ+ϑ-1d<-TޣI30D(գ~xP@#X93cqrW)]H};K URHWioGB,[ī|1[X)!T `C* iLE^-˲.0qJ>1j6Q&;T8I| ׏+ՙ)@ ŶWaG6!_%2*?xAm/0kp<a15&u0hE1R%vHUo3(0UKRRP]X G*^p}@@}m|` UPf VȨњ ہ5՟3*TU洳\|jԨQF5jc(^~IENDB`kylin-display-switch/mkt/res/img/MicrophoneOff.png0000644000175000017500000000330614100733566021201 0ustar fengfengPNG  IHDRff9bIDATxKIkD%p(SpdC  j)x(@)Df{Hng7Q3ui|ff44444444{!ӝ2;+( y5+zkH+g\^ 6TvI1ސQExׄN !j쵢L<Q pDPGGBwHQ!q @Rk ~ 70 ָ1xDT01 An9`Fߎ]3'q+ Q̭-?`n\/F`6@ogffťR|n0eT>/Ng>>@hZ1ҋMK̀:e̴ cVǵg]n1Z[{u#\\LM=ǟ#Q33 -:m` T` A0f`#s02`legn,64-Qc̴UCrMlo\0fZY1}Lk{{t;JNgꌙ)Ba1ۯ0e/Z+Ң( LPX4MLkaaLB ҉=]:8Tׯ @++/Jkݔ>#eeA=`(DFknKB?H0j9[gNד}MK4-QK&'?olnnW*kP5ZZ5~rzÏC+j|PX<^]]? |AruuPXgqBv"8jDAvPaݷq^Pe&Apف '0b8N@vHxmp9AUN݀Hb7/@^"7}4gC 5ptGCCCCCCCC឵k2IENDB`kylin-display-switch/mkt/res/img/TouchpadOff.png0000644000175000017500000000214414100733566020644 0ustar fengfengPNG  IHDRff9b+IDATxQkJW65L RKwވ(gGV "Amы͸q.η{o@:X,bXé=FUŒ16ȇ=HeiZ[a.3-+==G (HP@FY<ϋJs)J/y^|ȲF8>Gi>2]^)2]xE8QJ؋!-Ja V/b/Ԥi-[c/X$_l)U|2T mn{`{m/0ZӴHbO\z$XtMP?og+OfTDZ'.=v ?¼E LYkn!L70+og/Lg7mwd)nFB#4L&uUHHY\OGW a&˲<78 sxWUݼyx"c?xnnӣnA1]2b#aC0! aC0 @0! aC0! aBHaf0neB0B0B0Wd+UUuRyW0YUg7_*a18ѕ$<KCa0BC!Fh#4 a0BnN_ngt篳L+U sy<_4mc8󌍓a%;UӘzy6JOa]XH q@I@&yb̀g%4$Xt էs۵݆hqLl>ņ0Aֆ8> fg㛓 C q\ _ȅk6G /io4܁շ4_L5 ph٨X^|bX,}7T ,cIENDB`kylin-display-switch/mkt/res/img/CameraOff.png0000644000175000017500000000433014100733566020264 0ustar fengfengPNG  IHDRff9bIDATxOYh-]`b ; ib,hՈ&ۻ]m06++jqgpf1UqVklq/8fxwa 眇|8@1bĈ#FWeFYdSk)u fj@Ru:A %mJG9(%@ jȀt( M7n(tr8?ppP;уc9|m 8)Z7z0&r #ܲу`Vv [nmW^v6 P(?,n^-pΛ]ptln/kq l]1kt. pLh}wFwb8 R0݁a5ro!`w8S0=ѬP莛]`c0&cR80>SDbTp~I>zV(Bg/NRa$ Bv6pź(݈lv8 o0+ne2?[g j8h{hh{+ mOM9L@ Eh &FN&g}]A_%9ܣ62Ӈ&&Ca+;bދaosG(MLLGf8=1YYY (?RR_҇L/ND]Jssbq*M7 . H<ݗzM*4mQ,5_02kgXj U<آiˏXj0I/?Ҵ{#x%F>v&[k7 ϋ5Q,5p9@~ |LM iڽ+KJl<2Y= eia8H7Ue4Y^^IJceR.k։n'a#+PX/4 BMy|wHpzo|α|>c=x?Lv?.p`^w+m'U^w+,?βъJh;>F%Q- `O U`AF y VEQY@S5zjθXKW` hgK0E{v.x^,`^ ^_e`́hYRԨY0K.t/edrr2$IF˷K/ fF-5*CG~ ӧO6t`bO""!A4-ݛ@Dbq80333;v󲲍fggi;u`""Q?ۻw,ˈǎJSWy'"dRyK7WST6׀).^XU98HL?.)L+B "իdCÇoݺ5Jkܹ{Dąu.,,, ";ww \F LEEE[ooP,bx{O}z-+ҧV-czڵhC)805DbClﮬ<+I 5u1098\[Db!2 S]]ӞPS|]y1)!ʢl)#8.]wo!"̾;_30&D|ٱHiZnWx|L(Џ800\͛ap?E6mieY$I K[nb[hs=cOͱcf;y$xׁ!i~" K[ `>,]h;A4ן4 q iL^^d. %j3oWe;W5aהKVp /,Ye p'y [ǽB'zزQQgp|Ɏ$ΟQ"2y2>PB*,Q" %$- Dz'0/hC8F ǓI0)F>e-hG,FEXA7(x I.%R"Ap 3~( Bo"ij b30('nene1˖!IҢW"llNB<Ϝ" !k,vw@ؔ5}  :0`C_cՌuiy`?kln] Y]`3}N:8p93 U E0Ձq+kق`r`jӰ@Y7vw j;0Ápxr#|#,+{pxrcx8`l۳Lm*J`a%E"M%X vNnVVGFF_Dl͆`"MJU-٪@z*%)UHdj4PÁuE%[8 =l6WP\}N˃ '7(Uhtr2bpe ;Z/JUm~' !YG_|U6F0 RA0΃z>=}g;w<6J鴼l =G0(RӁ| hip<;۔O~Z^ڭ[wZ,6`Jbo:&`e )ٝr`LF˲J>M\2̃c{/%_> 9XTղ'[A0ptRUM|VjЍ!0^o -Iޕx|zRUK& V_`zlǷ*{M6LQعTJi@@^LعL#4c3>Qj%>^p^/fǖL pvڥ| xY\oߎm)ovgrB7N"Ys7;j`WZ.04meP~$# 33wSjJ=}?YK4ƀW;JU-se'193[NJvq<6B0 p*é B0 p*é j6zz0Mz/+-^KwUxZi1d >Sb-WBl=+EQ 9>E7s(N7"`C_́\BdAʸ\~ isV$MA2xESA2(f!`p=/ّR<%y[T?XmOa#7C2Ȫ s(=`Jb[Lz6g1BE󬱂 ҃j%}]-`1b҃j%A04 61 ue -`!MTdժ2kv(z+V1"@Ƭ*n:Rt:hhhhhhhhhE){ZIENDB`kylin-display-switch/mkt/res/img/NumlockOff.png0000644000175000017500000000266314100733566020513 0ustar fengfengPNG  IHDRff9bzIDATxOFk!>jQW7"CBT47%N*jWX aQ^MJ)@4"! <}Wwl) U,Y"Muk!@"\ iz t "1&! G ȗrC y_ӌ5BȎB/fy".@⸡\S妪у#KTUM ![Cb Z8, ESe^ EQ桳P¸͖1u7K$2kf8D1^9C /ì-0!&Y㺷@/az{26Q=ά2;.{`ܗK_&gEw\u80}xmhOQ &sY ̥3 f`/&@q @0a$$ɃL&(OUm[lUc~Da|if G1bYlpd7/T*}M6K҇\Q>]+hf G]omlT?$=/OFm[laD"y`YM˪5 Sm7-kzL&߰z+7}F.~F&3K~jV*>7]oaJXlzJ#̀B_}ey x;Tg~<*JX\>a8Je+pρ30KKvU(|{j/.m*O -SSQht 7ځ0N޻7@&CۮEI`L}?Fx~:}ͣG_g `Ba[a<|8vqxB{000000000#g;Fv = JFRRiDʾ;zTߕ} SRS*-TJ%a$ H4#iF ^&rX!f ^S'@lyMӾ?r5t̹K@'İDlq" / !Uу!KTUߌFe7iiڂꛄ#xݢi ;cⵌ gX7q3ӝ>k(]}8 tX$CS ;ox5,Ni D,l(fQ|n}xD3X0$n(thX0aAC<E31q/ ;"кPa _/Q +,0\x_jeJ`caaaaaaaa[UoIENDB`kylin-display-switch/mkt/res/img.qrc0000644000175000017500000000120014100733566016433 0ustar fengfeng img/CapslockOff.png img/CapslockOn.png img/NumlockOff.png img/NumlockOn.png img/TouchpadOn.png img/TouchpadOff.png img/MicrophoneOn.png img/MicrophoneOff.png img/CameraOff.png img/CameraOn.png img/FlightOff.png img/FlightOn.png zh_CN.qm img/WlanOn.png img/WlanOff.png kylin-display-switch/mkt/res/zh_CN.ts0000644000175000017500000000047014100733566016531 0ustar fengfeng Widget Airplane Mode 飞行模式 kylin-display-switch/mkt/res/zh_CN.qm0000644000175000017500000000012214100733566016512 0ustar fengfeng Widget 0 0 75 75 75 75 75 75 MKT 0 0 0 0 0 0 kylin-display-switch/mkt/widget.cpp0000644000175000017500000001516114107351661016360 0ustar fengfeng/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, 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, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "widget.h" #include "ui_widget.h" #include #include #include #include #include #include #include #define PANEL_SCHEMA "org.ukui.panel.settings" #define PANEL_SIZE_KEY "panelsize" #define POSBOTTOM 50 Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui->setupUi(this); setWindowFlags(Qt::FramelessWindowHint | Qt::ToolTip); setAttribute(Qt::WA_TranslucentBackground, true); pMappingTable = new MappingTable; iface = new QDBusInterface("org.ukui.kds", \ "/", \ "org.ukui.kds.interface", \ QDBusConnection::systemBus()); setupComponent(); // createTrayIcon(); pTimer = new QTimer(this); pTimer->setInterval(2500); connect(pTimer, &QTimer::timeout, this, [=]{ pTimer->stop(); this->hide(); }); connect(QApplication::desktop(), &QDesktopWidget::resized, this, [=]{ setMKTgeometry(); }); connect(QApplication::desktop(), &QDesktopWidget::screenCountChanged, this, [=]{ setMKTgeometry(); }); connect(QApplication::desktop(), &QDesktopWidget::primaryScreenChanged, this, [=]{ setMKTgeometry(); }); QDBusConnection::systemBus().connect(QString(), QString(), "org.ukui.kds.interface", "signalShowTips", this, SLOT(showTipsOnDesktop(int))); QDBusConnection::systemBus().connect(QString(), QString(), "org.ukui.kds.interface", "signalRfkillStatusChanged", this, SLOT(refreshTrayIcon())); } Widget::~Widget() { delete ui; delete pMappingTable; } void Widget::setMKTgeometry(){ const QByteArray id(PANEL_SCHEMA); int pSize = 0; if (QGSettings::isSchemaInstalled(id)){ QGSettings * settings = new QGSettings(id); pSize = settings->get(PANEL_SIZE_KEY).toInt(); delete settings; } QScreen * pScreen = QGuiApplication::screens().at(0); QRect rect = pScreen->geometry(); if (pSize){ move(rect.right() - (rect.width() * 1 / 4), (rect.bottom() + 1) - pSize - height()); } else { move(rect.right() - (rect.width() * 1 / 4), (rect.bottom() + 1) - POSBOTTOM - height()); } } void Widget::setupComponent(){ setMKTgeometry(); for (int i = 0; i < MappingTable::HandleKeys; i++){ QString funWord = pMappingTable->keyCodeToString(i); QString logoStr = QString(":/img/%1.png").arg(funWord); QFrame * baseFrame = new QFrame; QVBoxLayout * mainVerLayout = new QVBoxLayout(baseFrame); mainVerLayout->setSpacing(0); mainVerLayout->setMargin(0); QLabel * logoLabel = new QLabel(baseFrame); logoLabel->setScaledContents(true); logoLabel->setPixmap(QPixmap(logoStr)); mainVerLayout->addWidget(logoLabel); baseFrame->setLayout(mainVerLayout); ui->stackedWidget->addWidget(baseFrame); } } void Widget::createTrayIcon(){ QDBusReply reply = iface->call("getCurrentFlightMode"); /* 未获取到当前飞行模式状态 */ if (!reply.isValid()) return; int current = reply.value(); /* 获取飞行模式出错 | 计算机没有无线设备 */ if (current == -1) return; trayIcon = new QSystemTrayIcon; if (current){ trayIcon->setIcon(QIcon::fromTheme("airplane-mode-symbolic")); } else { trayIcon->setIcon(QIcon::fromTheme("airplane-mode-closed-symbolic")); } trayIcon->setVisible(true); trayIcon->setToolTip(tr("Airplane Mode")); connect(trayIcon, &QSystemTrayIcon::activated, this, [=](QSystemTrayIcon::ActivationReason reason){ switch (reason) { case QSystemTrayIcon::Trigger: flightToggleClick(); break; case QSystemTrayIcon::DoubleClick: break; case QSystemTrayIcon::MiddleClick: break; default: ; } }); } void Widget::showTipsOnDesktop(int index){ this->hide(); ui->stackedWidget->setCurrentIndex(index); this->show(); pTimer->start(); } void Widget::refreshTrayIcon(){ QDBusReply reply = iface->call("getCurrentFlightMode"); /* 未获取到当前飞行模式状态 */ if (!reply.isValid()) return; int current = reply.value(); /* 获取飞行模式出错 | 计算机没有无线设备 */ if (current == -1) return; if (current){ trayIcon->setIcon(QIcon::fromTheme("airplane-mode-symbolic")); } else { trayIcon->setIcon(QIcon::fromTheme("airplane-mode-closed-symbolic")); } } void Widget::flightToggleClick(){ QDBusReply reply = iface->call("getCurrentFlightMode"); if (reply.isValid()){ int current = reply.value(); if (current == -1){ // qWarning("Error Occur When Get Current FlightMode"); return; } QDBusReply reply2 = iface->call("toggleFlightMode", !current); if (reply.isValid()){ QString result = reply2.value(); if (result == QString("blocked")){ // qDebug("Enable Flight Mode!\n"); trayIcon->setIcon(QIcon::fromTheme("airplane-mode-symbolic")); showTipsOnDesktop(MappingTable::FlightOn); } else if (result == QString("unblocked")){ // qDebug("Disable Flight Mode!\n"); trayIcon->setIcon(QIcon::fromTheme("airplane-mode-closed-symbolic")); showTipsOnDesktop(MappingTable::FlightOff); } else { // qWarning("%s", result.toLatin1().data()); } } else { // qWarning("Toggle Flight Mode Failed!"); } } else { // qWarning("Get Current FlightMode Failed!"); } } kylin-display-switch/daemon/0000755000175000017500000000000014107351020015022 5ustar fengfengkylin-display-switch/daemon/kmdaemon.cpp0000644000175000017500000005537414107351020017337 0ustar fengfeng/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, 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, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "kmdaemon.h" #include #include #include #include #include #include #include #define UKCCOSD_SCHEMA "org.ukui.control-center.osd" #define KYCCOSD_SCHEMA "org.kylin.control-center.osd" #define KDSOSD_SCHEMA "org.ukui.kds.osd" #define UK_TOUCHPAD_SCHEMA "org.ukui.peripherals-touchpad" #define KY_TOUCHPAD_SCHEMA "org.mate.peripherals-touchpad" #define UK_KEYBOARD_SCHEMA "org.ukui.peripherals-keyboard" #define UK_POWERMANAGER_SCHEMA "org.ukui.power-manager" #define KY_POWERMANAGER_SCHEMA "org.mate.power-manager" #define SHOW_TIP_KEY "show-lock-tip" #define RUNNING_KEY "running" #define TP_ENABLE_KEY "touchpad-enabled" #define MP_ENABLE_KEY "microphone" #define CAPSLOCK_STATUS_KEY "capslock-state" #define NUMLOCK_STATUS_KEY "numlock-state" #define BRIGHTNESS_KEY "brightness-ac" #define SCREENOPENVALUE 99 #define SCREENCLOSEVALUE 0 Display * display; KMDaemon::KMDaemon() { thrd = new QThread; kmt = new KeyMonitorThread; iface = new QDBusInterface("org.ukui.kds", \ "/", \ "org.ukui.kds.interface", \ QDBusConnection::systemBus()); ifaceScreenSaver = new QDBusInterface("org.ukui.ScreenSaver", \ "/", \ "org.ukui.ScreenSaver", \ QDBusConnection::sessionBus()); modifyKeyPressed = false; stInstalled = true; kbInstalled = false; const QByteArray id(UKCCOSD_SCHEMA); const QByteArray idd(KYCCOSD_SCHEMA); const QByteArray iid(KDSOSD_SCHEMA); if (QGSettings::isSchemaInstalled(id)){ settings = new QGSettings(id); } else if (QGSettings::isSchemaInstalled(idd)){ settings = new QGSettings(idd); } else if (QGSettings::isSchemaInstalled(iid)){ settings = new QGSettings(iid); } else { stInstalled = false; } //X data init display = XOpenDisplay(0); const QByteArray id2(UK_KEYBOARD_SCHEMA); if (QGSettings::isSchemaInstalled(id2)){ kbInstalled = true; kbGSettings = new QGSettings(id2); connect(kbGSettings, &QGSettings::changed, this, [=](QString key){ if (stInstalled && !settings->get(SHOW_TIP_KEY).toBool()){ qWarning("MediaKey Tip is Closed\n"); return; } if (ifaceScreenSaver->isValid()){ QDBusReplyreply = ifaceScreenSaver->call("GetLockState"); if (reply.isValid()){ if (reply.value()){ qWarning("MediaKey Tip is Closed because ScreenLock\n"); return; } } } if (QString::compare(key, "capslockState") == 0){ bool current = kbGSettings->get(CAPSLOCK_STATUS_KEY).toBool(); if (current){ iface->call("emitShowTipsSignal", MappingTable::CapslockOn); } else { iface->call("emitShowTipsSignal", MappingTable::CapslockOff); } } else if (QString::compare(key, "numlockState") == 0){ bool current = QString::compare(kbGSettings->get(NUMLOCK_STATUS_KEY).toString(), QString("on")) == 0; if (current){ iface->call("emitShowTipsSignal", MappingTable::NumlockOn); } else { iface->call("emitShowTipsSignal", MappingTable::NumlockOff); } } }); } else { capslockStatus = false; numlockStatus = false; } QDBusReply reply = iface->call("getCameraDeviceEnable"); if (reply.isValid()){ int current = reply.value(); if (current == -1) cameraEnableStatus = true; else{ cameraEnableStatus = current ? true : false; } } keyboardLightInit(); const QByteArray idtp(UK_TOUCHPAD_SCHEMA); //KeyCode 比 正常键值大 8,原因未知 connect(kmt, &KeyMonitorThread::keyPress, this, [=](KeySym mks, KeyCode mkc){ Q_UNUSED(mkc) // qDebug() << "key press:" << mkc - 8; // if (!iface->isValid()){ // qCritical() << "Create Client Interface Failed When execute chage: " << QDBusConnection::systemBus().lastError(); // return; // } if (mks == XKB_KEY_XF86TouchpadOn){ //更新gsettings if (QGSettings::isSchemaInstalled(idtp)){ QGSettings * st = new QGSettings(idtp); st->set(TP_ENABLE_KEY, true); delete st; } iface->call("emitShowTipsSignal", MappingTable::TouchpadOn); } else if (mks == XKB_KEY_XF86TouchpadOff){ //更新gsettings if (QGSettings::isSchemaInstalled(idtp)){ QGSettings * st = new QGSettings(idtp); st->set(TP_ENABLE_KEY, false); delete st; } iface->call("emitShowTipsSignal", MappingTable::TouchpadOff); } else if (mks == XKB_KEY_XF86RFKill){ QDBusReply reply = iface->call("getCurrentFlightMode"); if (reply.isValid()){ int current = reply.value(); if (current != -1){ if (current){ iface->call("emitShowTipsSignal", MappingTable::FlightOn); } else { iface->call("emitShowTipsSignal", MappingTable::FlightOff); } } } } else if (mks == XKB_KEY_XF86WebCam){ cameraEnableStatus = !cameraEnableStatus; if (cameraEnableStatus) iface->call("emitShowTipsSignal", MappingTable::CameraOn); else iface->call("emitShowTipsSignal", MappingTable::CameraOff); } else if (mks == XKB_KEY_XF86AudioMicMute){ // qDebug() << "mic mute"; } else if (mks == XKB_KEY_XF86WLAN){ wlanToggle(); } if (mks == XK_Super_L || mks== XK_Super_R){ modifyKeyPressed = true; } else if (mks == XK_p){ if (modifyKeyPressed){ // qDebug("Win + P Pressed!\n"); // QProcess process; // QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); // env.insert("DISPLAY", ":0"); // process.setProcessEnvironment(env); // process.startDetached("/usr/bin/kydisplayswitch"); } else { iface->call("emitCloseApp"); } } else if (mks == XKB_KEY_XF86Display){ /* Do Nothing, Just Not CloseApp*/ }else if (mks == XK_KP_Enter || mks == XK_Return){ iface->call("emitMakeClicked"); } else if (mks == XK_Up || mks == XK_KP_Up) { iface->call("emitLastOption"); } else if (mks == XK_Down || mks == XK_KP_Down) { iface->call("emitNextOption"); } else if (mks == XK_Caps_Lock){ capslockStatus = !capslockStatus; if (stInstalled && !settings->get(SHOW_TIP_KEY).toBool()){ qWarning("MediaKey Tip is Closed\n"); return; } if (ifaceScreenSaver->isValid()){ QDBusReplyreply = ifaceScreenSaver->call("GetLockState"); if (reply.isValid()){ if (reply.value()){ qWarning("MediaKey Tip is Closed because ScreenLock\n"); return; } } } /* usd的键盘GSettings已安装,使用gsettings来触发,这里直接返回 */ if (kbInstalled) return; if (capslockStatus){ iface->call("emitShowTipsSignal", MappingTable::CapslockOn); } else { iface->call("emitShowTipsSignal", MappingTable::CapslockOff); } } else if (mks == XK_Num_Lock){ numlockStatus = !numlockStatus; if (stInstalled && !settings->get(SHOW_TIP_KEY).toBool()){ qWarning("MediaKey Tip is Closed\n"); return; } if (ifaceScreenSaver->isValid()){ QDBusReplyreply = ifaceScreenSaver->call("GetLockState"); if (reply.isValid()){ if (reply.value()){ qWarning("MediaKey Tip is Closed because ScreenLock\n"); return; } } } /* usd的键盘GSettings已安装,使用gsettings来触发,这里直接返回 */ if (kbInstalled) return; if (numlockStatus){ iface->call("emitShowTipsSignal", MappingTable::NumlockOn); } else { iface->call("emitShowTipsSignal", MappingTable::NumlockOff); } } else { iface->call("emitCloseApp"); } }, Qt::QueuedConnection); connect(kmt, &KeyMonitorThread::keyRelease, this, [=](KeySym mks, KeyCode mkc){ Q_UNUSED(mkc) // qDebug() << "key release:" << mkc - 8; if (mks == XK_Super_L || mks== XK_Super_R){ modifyKeyPressed = false; } }, Qt::QueuedConnection); connect(kmt, &KeyMonitorThread::buttonPress, this, [=] (int x, int y) { iface->call("emitButtonClicked", x, y); }, Qt::QueuedConnection); connect(kmt, &KeyMonitorThread::jobComplete, this, [=]{ thrd->quit(); //退出事件循环 thrd->wait(); //释放资源 }); connect(thrd, &QThread::started, kmt, &KeyMonitorThread::run); connect(thrd, &QThread::finished, kmt, &KeyMonitorThread::deleteLater); //绑定特殊 QDBusConnection::systemBus().connect(QString(), QString(), "org.ukui.kds.interface", "signalMediaKeyTrans", this, SLOT(mediaKeyManager(int))); } KMDaemon::~KMDaemon() { kmt->callJobComplete(); delete iface; delete ifaceScreenSaver; if (stInstalled) delete settings; if (kbInstalled) delete kbGSettings; } void KMDaemon::begin(){ kmt->moveToThread(thrd); thrd->start(); } void KMDaemon::keyboardLightInit(){ airplanModeKeyLightInit(); disableCameraKeyLightInit(); } void KMDaemon::airplanModeKeyLightInit(){ QDBusReply reply = iface->call("getCurrentFlightMode"); if (!reply.isValid()){ return; } int current = reply.value(); if (current == -1){ return; } /* 设置飞行模式键盘灯 */ QDBusReply reply2 = iface->call("setAirplaneModeKeyboardLight", current); if (!reply2.isValid()){ // qWarning("Set AirplaneMode Keyboardlight Failed"); } } void KMDaemon::disableCameraKeyLightInit(){ QDBusReply cReply = iface->call("getCameraDeviceEnable"); if (!cReply.isValid()){ return; } int result = cReply.value(); if (result == -1){ return; } /* 设置禁用摄像头键盘灯 */ QDBusReply cReply2 = iface->call("setCameraKeyboardLight", result ? false : true); if (!cReply2.isValid()){ // qWarning("Set Camera Keyboardlight Failed"); } } /* * OBSOLETE */ bool KMDaemon::getCurrentCapslockStatus(){ Bool state; static Atom CapsLock = XInternAtom(display, "Caps Lock", False); XkbGetNamedIndicator(display, CapsLock, NULL, &state, NULL, NULL); return state; } /* * OBSOLETE */ bool KMDaemon::getCurrentNumlockStatus(){ Bool state; static Atom NumLock = XInternAtom(display, "Num Lock", False); XkbGetNamedIndicator(display, NumLock, NULL, &state, NULL, NULL); return state; } void KMDaemon::mediaKeyManager(int code){ switch (code) { case TOUCHPADKEY: qDebug("Key Received %d!\n", TOUCHPADKEY); touchpadToggle(); break; case TOUCHPADONKEY: qDebug("Key Received %d!\n", TOUCHPADONKEY); touchpadToggle2(true); break; case TOUCHPADOFFKEY: qDebug("Key Received %d!\n", TOUCHPADOFFKEY); touchpadToggle2(false); break; case MICROPHONEKEY: qDebug("Key Received %d!\n", MICROPHONEKEY); microphoneToggle(); break; case CAMERAKEY: qDebug("Key Received %d!\n", CAMERAKEY); cameraToggle(); break; case FLIGHTKEY: qDebug("Key Received %d!\n", FLIGHTKEY); flightToggle(); break; case SCREENKEY: qDebug("Key Received %d!\n", SCREENKEY); screenToggle(); break; case SCREENLOCKKEY: qDebug("Key Received %d!\n", SCREENLOCKKEY); screenLock(); break; default: break; } } void KMDaemon::touchpadToggle(){ XDeviceInfo *deviceinfos; int n_devices; int realformat; unsigned long nitems, bytes_after; unsigned char *data; deviceinfos = XListInputDevices (display, &n_devices); if (deviceinfos == NULL){ qCritical("XListInputDevices is NULL!\n"); return; } for (int i = 0; i < n_devices; i++){ XDevice * device; Atom realtype, prop; XDeviceInfo deviceinfo = deviceinfos[i]; if (deviceinfo.type != XInternAtom (display, XI_TOUCHPAD, False)){ if (deviceinfo.type == XInternAtom(display, XI_MOUSE, False) && strstr(deviceinfo.name, "PS\/2")){ } else { continue; } } prop = XInternAtom (display, "Device Enabled", False); if (!prop) continue; device = XOpenDevice (display, deviceinfo.id); if (!device) continue; if (XGetDeviceProperty (display, device, prop, 0, 1, False, XA_INTEGER, &realtype, &realformat, &nitems, &bytes_after, &data) == Success) { // if (QString(deviceinfo.name).contains("USB Optical Mouse")) // continue; qDebug("Get Input name:%s; id: %d!\n", deviceinfo.name, (int)deviceinfo.id); if (nitems == 1){ // data[0] = (data[0] == 0) ? 1 : 0; const QByteArray id(UK_TOUCHPAD_SCHEMA); if (data[0] == 1){ QString cmd = QString("xinput disable %1").arg(QString::number((int)deviceinfo.id)); qDebug("Disable Input Device %s\n", deviceinfo.name); system(cmd.toLatin1().data()); //更新gsettings if (QGSettings::isSchemaInstalled(id)){ QGSettings * st = new QGSettings(id); st->set(TP_ENABLE_KEY, false); delete st; } iface->call("emitShowTipsSignal", MappingTable::TouchpadOff); } else { QString cmd = QString("xinput enable %1").arg(QString::number((int)deviceinfo.id)); qDebug("Enable Input Device %s\n", deviceinfo.name); system(cmd.toLatin1().data()); //更新gsettings if (QGSettings::isSchemaInstalled(id)){ QGSettings * st = new QGSettings(id); st->set(TP_ENABLE_KEY, true); delete st; } iface->call("emitShowTipsSignal", MappingTable::TouchpadOn); } // XChangeDeviceProperty(display, device, prop, XA_INTEGER, realformat, PropModeReplace, data, nitems); } XFree(data); } XCloseDevice (display, device); } if (deviceinfos != NULL) XFreeDeviceList (deviceinfos); } void KMDaemon::touchpadToggle2(bool enable){ const QByteArray id(UK_TOUCHPAD_SCHEMA); const QByteArray idd(KY_TOUCHPAD_SCHEMA); if (QGSettings::isSchemaInstalled(id)){ QGSettings * st = new QGSettings(id); st->set(TP_ENABLE_KEY, enable); if (enable){ qDebug("Enable Touchpad By UK GSettings!\n"); iface->call("emitShowTipsSignal", MappingTable::TouchpadOn); } else { qDebug("Disable Touchpad By UK GSettings!\n"); iface->call("emitShowTipsSignal", MappingTable::TouchpadOff); } delete st; } else if (QGSettings::isSchemaInstalled(idd)){ QGSettings * st = new QGSettings(idd); st->set(TP_ENABLE_KEY, enable); if (enable){ qDebug("Enable Touchpad By KY GSettings!\n"); iface->call("emitShowTipsSignal", MappingTable::TouchpadOn); } else { qDebug("Disable Touchpad By KY GSettings!\n"); iface->call("emitShowTipsSignal", MappingTable::TouchpadOff); } delete st; } else { qWarning("Touchpad GSettings is not install!"); } } void KMDaemon::microphoneToggle(){ const QByteArray id(KDSOSD_SCHEMA); if (QGSettings::isSchemaInstalled(id)){ QGSettings * st = new QGSettings(id); bool current = st->get(MP_ENABLE_KEY).toBool(); st->set(MP_ENABLE_KEY, !current); if (current){ qDebug("Disable Microphone!\n"); iface->call("emitShowTipsSignal", MappingTable::MicrophoneOff); } else { qDebug("Enable Microphone!\n"); iface->call("emitShowTipsSignal", MappingTable::MicrophoneOn); } } } void KMDaemon::cameraToggle(){ QDBusReply reply = iface->call("getCameraBusinfo"); if (reply.isValid()){ QString businfo = reply.value(); QDBusReply reply2 = iface->call("toggleCameraDevice", businfo); if (reply2.isValid()){ QString result = reply2.value(); if (result == QString("binded")){ qDebug("Enable Camera Device!\n"); iface->call("setCameraKeyboardLight", false); iface->call("emitShowTipsSignal", MappingTable::CameraOn); } else if (result == QString("unbinded")){ qDebug("Disable Camera Device!\n"); iface->call("setCameraKeyboardLight", true); iface->call("emitShowTipsSignal", MappingTable::CameraOff); } else { qWarning("%s", result.toLatin1().data()); } } else { qWarning("Toggle Camera device Failed!"); } } else { qWarning("Get Camera Businfo Failed!"); } } void KMDaemon::flightToggle(){ QDBusReply reply = iface->call("getCurrentFlightMode"); if (reply.isValid()){ int current = reply.value(); if (current == -1){ qWarning("Error Occur When Get Current FlightMode"); return; } QDBusReply reply2 = iface->call("toggleFlightMode", !current); if (reply2.isValid()){ QString result = reply2.value(); if (result == QString("blocked")){ qDebug("Enable Flight Mode!\n"); iface->call("setAirplaneModeKeyboardLight", true); iface->call("emitShowTipsSignal", MappingTable::FlightOn); } else if (result == QString("unblocked")){ qDebug("Disable Flight Mode!\n"); iface->call("setAirplaneModeKeyboardLight", false); iface->call("emitShowTipsSignal", MappingTable::FlightOff); } else { qWarning("%s", result.toLatin1().data()); } } else { qWarning("Toggle Flight Mode Failed!"); } } else { qWarning("Get Current FlightMode Failed!"); } } void KMDaemon::wlanToggle(){ QDBusReply reply = iface->call("getCurrentWlanMode"); if (reply.isValid()){ int current = reply.value(); if (current == -1){ qWarning("Error Occur When Get Current WlanMode"); return; } bool status = current ? true : false; QDBusReply reply2 = iface->call("toggleWlanMode", !status); if (reply2.isValid()){ QString result = reply2.value(); if (result == QString("blocked")){ qDebug("Disable Wlan Mode!\n"); iface->call("emitShowTipsSignal", MappingTable::WlanOff); } else if (result == QString("unblocked")){ qDebug("Enable Wlan Mode!\n"); iface->call("emitShowTipsSignal", MappingTable::WlanOn); } else { qWarning("%s", result.toLatin1().data()); } } else { qWarning("Toggle Wlan Mode Failed!"); } } } void KMDaemon::screenLock(){ QFileInfo lock1("/usr/bin/mate-screensaver-command"); QFileInfo lock2("/usr/bin/ukui-screensaver-command"); QString cmd; if (lock1.isExecutable()){ cmd = QString("mate-screensaver-command --lock"); } else if (lock2.isExecutable()){ cmd = QString("ukui-screensaver-command -l"); } else { cmd = QString(""); } if (!cmd.isEmpty()) system(cmd.toLatin1().data()); } void KMDaemon::screenToggle(){ const QByteArray id(UK_POWERMANAGER_SCHEMA); const QByteArray idd(KY_POWERMANAGER_SCHEMA); if (QGSettings::isSchemaInstalled(id)){ QGSettings * st1 = new QGSettings(id); int value = st1->get(BRIGHTNESS_KEY).toInt(); if (value == SCREENCLOSEVALUE){ st1->set(BRIGHTNESS_KEY, SCREENOPENVALUE); } else { st1->set(BRIGHTNESS_KEY, SCREENCLOSEVALUE); } delete st1; } else if (QGSettings::isSchemaInstalled(idd)){ QGSettings * st1 = new QGSettings(idd); int value = st1->get(BRIGHTNESS_KEY).toInt(); if (value == SCREENCLOSEVALUE){ st1->set(BRIGHTNESS_KEY, SCREENOPENVALUE); } else { st1->set(BRIGHTNESS_KEY, SCREENCLOSEVALUE); } delete st1; } else { qWarning("Touchpad GSettings is not install!"); } } kylin-display-switch/daemon/main.cpp0000644000175000017500000000426714100733566016477 0ustar fengfeng/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, 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, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include #include "kmdaemon.h" #include #include #include #include void outputMessage(QtMsgType type, const QMessageLogContext &context, const QString &msg){ Q_UNUSED(context) //加锁 static QMutex mutex; mutex.lock(); QByteArray localMsg = msg.toLocal8Bit(); QString strMsg(""); switch (type) { case QtDebugMsg: strMsg = QString("Debug:"); break; case QtWarningMsg: strMsg = QString("Warning:"); break; case QtCriticalMsg: strMsg = QString("Critical:"); break; case QtFatalMsg: strMsg = QString("Fatal:"); break; } //设置输出信息格式 QString strDateTime = QDateTime::currentDateTime().toString("M d hh:mm:ss"); QString strMessage = QString("%1\t%2 %3").arg(strDateTime).arg(strMsg).arg(localMsg.constData()); //输出信息至文件中 QFile file("/tmp/kmdaemon.log"); file.open(QIODevice::ReadWrite | QIODevice::Append); QTextStream stream(&file); stream << strMessage << "\r\n"; file.flush(); file.close(); //解锁 mutex.unlock(); } int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); qInstallMessageHandler(outputMessage); KMDaemon daemon; daemon.begin(); return a.exec(); } kylin-display-switch/daemon/keymonitorthread.cpp0000644000175000017500000001041614100733566021134 0ustar fengfeng/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, 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, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "keymonitorthread.h" #include KeyMonitorThread::KeyMonitorThread(QObject *parent) : QThread(parent) { display = XOpenDisplay(0); if (display == 0) { qCritical("unable to open display\n"); return; } } KeyMonitorThread::~KeyMonitorThread() { } void KeyMonitorThread::run(){ // Display* display = XOpenDisplay(0); // if (display == 0) { // fprintf(stderr, "unable to open display\n"); // return; // } // Receive from ALL clients, including future clients. XRecordClientSpec clients = XRecordAllClients; XRecordRange* range = XRecordAllocRange(); if (range == 0) { qCritical("unable to allocate XRecordRange\n"); return; } // Receive KeyPress, KeyRelease, ButtonPress, ButtonRelease and MotionNotify events. memset(range, 0, sizeof(XRecordRange)); range->device_events.first = KeyPress; range->device_events.last = MotionNotify; // And create the XRECORD context. XRecordContext context = XRecordCreateContext(display, 0, &clients, 1, &range, 1); if (context == 0) { qCritical("XRecordCreateContext failed\n"); return; } XFree(range); XSync(display, True); Display* display_datalink = XOpenDisplay(0); if (display_datalink == 0) { qCritical("unable to open second display\n"); return; } if (!XRecordEnableContext(display_datalink, context, callback, (XPointer) this)) { qCritical("XRecordEnableContext() failed\n"); return; } } void KeyMonitorThread::callback(XPointer ptr, XRecordInterceptData* data) { ((KeyMonitorThread *) ptr)->handleRecordEvent(data); } void KeyMonitorThread::handleRecordEvent(XRecordInterceptData* data) { if (data->category == XRecordFromServer) { xEvent * event = (xEvent *)data->data; KeySym keySym = XKeycodeToKeysym(display, event->u.u.detail, 0); KeyCode keyCode = XKeysymToKeycode(display, keySym); switch (event->u.u.type) { case ButtonPress: if (filterWheelEvent(event->u.u.detail)) { emit buttonPress( event->u.keyButtonPointer.rootX, event->u.keyButtonPointer.rootY); } break; // case MotionNotify: // if (isPress) { // emit buttonDrag( // event->u.keyButtonPointer.rootX, // event->u.keyButtonPointer.rootY); // } // break; // case ButtonRelease: // if (filterWheelEvent(event->u.u.detail)) { // isPress = false; // emit buttonRelease( // event->u.keyButtonPointer.rootX, // event->u.keyButtonPointer.rootY); // } // break; case KeyPress: // emit keyPress(((unsigned char*) data->data)[1]); emit keyPress(keySym, keyCode); break; case KeyRelease: // emit keyRelease(((unsigned char*) data->data)[1]); emit keyRelease(keySym, keyCode); break; default: break; } } fflush(stdout); XRecordFreeData(data); } bool KeyMonitorThread::filterWheelEvent(int detail) { return detail != WheelUp && detail != WheelDown && detail != WheelLeft && detail != WheelRight; } void KeyMonitorThread::callJobComplete(){ emit jobComplete(); } kylin-display-switch/daemon/keymonitorthread.h0000644000175000017500000000347214100733566020605 0ustar fengfeng/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, 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, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef KEYMONITORTHREAD_H #define KEYMONITORTHREAD_H #include #include #include // Virtual button codes that are not defined by X11. #define Button1 1 #define Button2 2 #define Button3 3 #define WheelUp 4 #define WheelDown 5 #define WheelLeft 6 #define WheelRight 7 #define XButton1 8 #define XButton2 9 class KeyMonitorThread : public QThread { Q_OBJECT public: explicit KeyMonitorThread(QObject *parent = 0); ~KeyMonitorThread(); public: void run(); void callJobComplete(); signals: void keyPress(KeySym keysym, KeyCode keyCode); void keyRelease(KeySym keysym, KeyCode keyCode); void buttonPress(int x, int y); void jobComplete(); protected: bool filterWheelEvent(int detail); static void callback(XPointer trash, XRecordInterceptData* data); void handleRecordEvent(XRecordInterceptData *); private: Display * display; }; #endif // KEYMONITORTHREAD_H kylin-display-switch/daemon/daemon.pro0000644000175000017500000000210114100733566017015 0ustar fengfengQT += core dbus QT -= gui CONFIG += link_pkgconfig CONFIG += c++11 PKGCONFIG += xcb xcb-util TARGET = kmdaemon #CONFIG += console #CONFIG -= app_bundle TEMPLATE = app LIBS += -lX11 -lXi -lXtst -lgsettings-qt include (../utils/utils.pri) target.source += $$TARGET target.path = /usr/bin INSTALLS += \ target \ SOURCES += main.cpp \ keymonitorthread.cpp \ kmdaemon.cpp # The following define makes your compiler emit warnings if you use # any feature of Qt which as been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if you use deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 FORMS += HEADERS += \ keymonitorthread.h \ kmdaemon.h kylin-display-switch/daemon/kmdaemon.h0000644000175000017500000000404614107351020016772 0ustar fengfeng#ifndef KMDAEMON_H /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, 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, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #define KMDAEMON_H #include #include #include #include #include #include #include #include "mappingtable.h" #include "keymonitorthread.h" class KMDaemon : public QObject { Q_OBJECT public: explicit KMDaemon(); ~KMDaemon(); public: void begin(); public: bool getCurrentCapslockStatus(); bool getCurrentNumlockStatus(); void touchpadToggle(); void touchpadToggle2(bool enable); void microphoneToggle(); void cameraToggle(); void flightToggle(); void wlanToggle(); void screenLock(); void screenToggle(); void keyboardLightInit(); void airplanModeKeyLightInit(); void disableCameraKeyLightInit(); private: QThread * thrd; KeyMonitorThread * kmt; QDBusInterface * iface; QDBusInterface * ifaceScreenSaver; private: bool modifyKeyPressed; bool capslockStatus; bool numlockStatus; bool cameraEnableStatus; QGSettings * settings; QGSettings * kbGSettings; bool stInstalled; bool kbInstalled; public slots: void mediaKeyManager(int code); }; #endif // KMDAEMON_H kylin-display-switch/daemon2/0000755000175000017500000000000014107351625015117 5ustar fengfengkylin-display-switch/daemon2/eventmonitorthread.cpp0000644000175000017500000001205114100733566021544 0ustar fengfeng/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, 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, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "eventmonitorthread.h" #include #include #include #include extern "C" { //#include //#include //#include #include #include #include #define DEVS_FILE "/proc/bus/input/devices" } EventMonitorThread::EventMonitorThread(QMap keyword) : _keyword(keyword) { } EventMonitorThread::~EventMonitorThread(){ } void EventMonitorThread::run(){ QString threadText = QStringLiteral("@0x%1").arg(quintptr(QThread::currentThreadId()), 16, 16, QLatin1Char('0')); // qDebug("thread %s begin!", threadText.toLatin1().data()); // QMap::iterator it0 = _keyword.begin(); // for (; it0 != _keyword.end(); it0++){ // qDebug("this thread's key is: '%s'", it0.value().toLatin1().data()); // } int fd; struct input_event ie; //获取EventX QString eventFile = ""; QFile * readFile = new QFile(DEVS_FILE); if (!readFile->open(QIODevice::ReadOnly | QIODevice::Text)){ qWarning("Open Devices File '%s' Failed!", DEVS_FILE); readFile->close(); return; } else { QTextStream stream(readFile); QString alldevicesInfo = stream.readAll(); QStringList devicesInfo = alldevicesInfo.split("\n\n"); QList flags; for (QString deviceInfo : devicesInfo){ flags.clear(); flags.append(true); QStringList lines = deviceInfo.split("\n", QString::SkipEmptyParts); for (QString line : lines){ QMap::iterator it = _keyword.begin(); for (; it != _keyword.end(); it++){ if (line.startsWith(it.key()) ){ if (line.contains(it.value())){ flags.append(true); } else { flags.append(false); } } } if (line.startsWith("H: Handlers=")){ QString options = line.split("=").at(1); for (QString option : options.split(" ", QString::SkipEmptyParts)){ if (option.startsWith("event")){ eventFile = "/dev/input/" + option; } } } foreach (bool flag, flags) { if (!flag){ // goto nexttime; eventFile = ""; } } } //nexttime: if (!eventFile.isEmpty()) break; } readFile->close(); } qDebug("Dev EventX is %s\n", eventFile.toLatin1().data()); if (eventFile.isEmpty()){ qWarning("Dev EventX is Empty!\n"); return; } QByteArray ba = eventFile.toLatin1(); fd = open(ba.data(),O_RDONLY); if (fd <0 ) { qWarning("Open Event File '%s' Failed!", eventFile.toLatin1().data()); return; } QTime pressTime(0, 0, 0, 0); QTime releaseTime(0, 0, 0, 0); QTime longPressTime(0, 0, 0, 0); while (1) { if (read(fd, &ie, sizeof(ie))){ if (ie.type == 1){ if (ie.value == 1) pressTime = QTime::currentTime(); if (ie.value == 0) releaseTime = QTime::currentTime(); if (ie.value == 2) longPressTime = QTime::currentTime(); // qDebug("presstime: %s", pressTime.toString("hh:mm").toLatin1().data()); // qDebug("releaseTime: %s", releaseTime.toString("hh:mm").toLatin1().data()); if (pressTime.secsTo(QTime(0, 0, 0, 0)) != 0 && releaseTime.secsTo(QTime(0, 0, 0, 0)) != 0){ emit eventMeet(ie.code); pressTime = QTime(0, 0, 0, 0); releaseTime = QTime(0, 0, 0, 0); longPressTime = QTime(0, 0, 0, 0); } } } } close(fd); //线程结束 callJobComplete(); } void EventMonitorThread::callJobComplete(){ emit jobComplete(); } kylin-display-switch/daemon2/eventmonitorthread.h0000644000175000017500000000246014100733566021214 0ustar fengfeng/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, 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, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef EVENTMONITORTHREAD_H #define EVENTMONITORTHREAD_H #include #include class EventMonitorThread : public QObject { Q_OBJECT public: explicit EventMonitorThread(QMap keyword); ~EventMonitorThread(); public: void run(); void callJobComplete(); private: QMap _keyword; Q_SIGNALS: void eventMeet(int code); void jobComplete(); }; #endif // EVENTMONITORTHREAD_H kylin-display-switch/daemon2/main.cpp0000644000175000017500000000424214100733566016552 0ustar fengfeng/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, 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, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include #include #include #include #include #include "emdaemon.h" void outputMessage(QtMsgType type, const QMessageLogContext &context, const QString &msg){ Q_UNUSED(context) //加锁 static QMutex mutex; mutex.lock(); QByteArray localMsg = msg.toLocal8Bit(); QString strMsg(""); switch (type) { case QtDebugMsg: strMsg = QString("Debug:"); break; case QtWarningMsg: strMsg = QString("Warning:"); break; case QtCriticalMsg: strMsg = QString("Critical:"); break; case QtFatalMsg: strMsg = QString("Fatal:"); break; } //设置输出信息格式 QString strDateTime = QDateTime::currentDateTime().toString("M d hh:mm:ss"); QString strMessage = QString("%1\t%2 %3").arg(strDateTime).arg(strMsg).arg(localMsg.constData()); //输出信息至文件中 QFile file("/tmp/emdaemon.log"); file.open(QIODevice::ReadWrite | QIODevice::Append); QTextStream stream(&file); stream << strMessage << "\r\n"; file.flush(); file.close(); //解锁 mutex.unlock(); } int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); qInstallMessageHandler(outputMessage); EMDaemon daemon; return a.exec(); } kylin-display-switch/daemon2/daemon2.pro0000644000175000017500000000213514100733566017170 0ustar fengfengQT += core dbus QT -= gui CONFIG += link_pkgconfig CONFIG += c++11 TARGET = emdaemon #CONFIG += console #CONFIG -= app_bundle TEMPLATE = app #PKGCONFIG += gio-2.0 \ # gio-unix-2.0 \ LIBS += -lX11 -lXi target.source += $$TARGET target.path = /usr/bin INSTALLS += \ target \ SOURCES += main.cpp \ emdaemon.cpp \ eventmonitorthread.cpp \ rfkillmonitorthread.cpp # The following define makes your compiler emit warnings if you use # any feature of Qt which as been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if you use deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 HEADERS += \ emdaemon.h \ eventmonitorthread.h \ rfkillmonitorthread.h kylin-display-switch/daemon2/emdaemon.h0000644000175000017500000000256314107066301017055 0ustar fengfeng/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, 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, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef EMDAEMON_H #define EMDAEMON_H #include #include #include #include #include #include "eventmonitorthread.h" #include "rfkillmonitorthread.h" class EMDaemon : public QObject { Q_OBJECT public: explicit EMDaemon(); ~EMDaemon(); private: // QThread * thrd; // EventMonitorThread * emt; QThread * thrd2; RfkillMonitorthread * rmt; QDBusInterface * iface; QList emts; }; #endif // EMDAEMON_H kylin-display-switch/daemon2/emdaemon.cpp0000644000175000017500000000574714107351625017425 0ustar fengfeng/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, 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, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "emdaemon.h" #include #include EMDaemon::EMDaemon() { iface = new QDBusInterface("org.ukui.kds", \ "/", \ "org.ukui.kds.interface", \ QDBusConnection::systemBus()); QMap keyWord1; QMap keyWord2; QMap keyWord3; keyWord1.insert("N: Name", "2 keyboard"); // keyWord1.insert("P: Phys", "input0"); keyWord2.insert("N: Name", "Hotkey"); keyWord3.insert("N: Name", "SCI_EVT"); QList> filters; filters.append(keyWord1); filters.append(keyWord2); filters.append(keyWord3); for (QMap k : filters){ QThread * thrd = new QThread; EventMonitorThread * emt = new EventMonitorThread(k); emts.append(emt); connect(emt, &EventMonitorThread::eventMeet, this, [=](int code){ iface->call("emitMediaKeyTrans", code); }, Qt::QueuedConnection); connect(emt, &EventMonitorThread::jobComplete, this, [=]{ thrd->quit(); //退出事件循环 thrd->wait(); //释放资源 }); connect(thrd, &QThread::started, emt, &EventMonitorThread::run); connect(thrd, &QThread::finished, emt, &EventMonitorThread::deleteLater); emt->moveToThread(thrd); thrd->start(); } //rfkill monitor start thrd2 = new QThread; rmt = new RfkillMonitorthread; connect(rmt, &RfkillMonitorthread::statusChanged, this, [=]{ iface->call("emitRfkillStatusChanged"); }, Qt::QueuedConnection); connect(rmt, &RfkillMonitorthread::jobComplete, this, [=]{ thrd2->quit(); thrd2->wait(); }); connect(thrd2, &QThread::started, rmt, &RfkillMonitorthread::run); connect(thrd2, &QThread::finished, rmt, &RfkillMonitorthread::deleteLater); rmt->moveToThread(thrd2); thrd2->start(); } EMDaemon::~EMDaemon(){ for (EventMonitorThread * emt : emts){ emt->callJobComplete(); } rmt->callJobComplete(); delete iface; } kylin-display-switch/daemon2/rfkillmonitorthread.cpp0000644000175000017500000000452414107066301021705 0ustar fengfeng/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, 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, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "rfkillmonitorthread.h" #include #include #include #include #include struct rfkill_event { __u32 idx; __u8 type; __u8 op; __u8 soft, hard; }; #define RFKILL_EVENT_SIZE_V1 8 RfkillMonitorthread::RfkillMonitorthread() { } RfkillMonitorthread::~RfkillMonitorthread(){ } void RfkillMonitorthread::run(){ struct rfkill_event event; struct pollfd p; ssize_t len; int fd, n; fd = open("/dev/rfkill", O_RDONLY); if (fd < 0) { qCritical("Can not open RFKILL control device!\n"); return; } memset(&p, 0, sizeof(p)); p.fd = fd; p.events = POLLIN | POLLHUP; while (1) { n = poll(&p, 1, -1); if (n < 0) { qWarning("Failed to poll RFKILL control device!\n"); break; } if (n == 0) { continue; } len = read(fd, &event, sizeof(event)); if (len < 0) { qWarning("Reading of RFKILL events failed!\n"); break; } if (len != RFKILL_EVENT_SIZE_V1){ qDebug("Wrong size of RFKILL event!\n"); continue; } qDebug("idx %u type %u op %u soft %u hard %u\n", event.idx, event.type, event.op, event.soft, event.hard); emit statusChanged(); fflush(stdout); } close(fd); //线程结束 callJobComplete(); } void RfkillMonitorthread::callJobComplete(){ emit jobComplete(); } kylin-display-switch/daemon2/rfkillmonitorthread.h0000644000175000017500000000231414107066301021345 0ustar fengfeng/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, 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, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef RFKILLMONITORTHREAD_H #define RFKILLMONITORTHREAD_H #include class RfkillMonitorthread : public QObject { Q_OBJECT public: RfkillMonitorthread(); ~RfkillMonitorthread(); public: void run(); void callJobComplete(); Q_SIGNALS: void statusChanged(); void jobComplete(); }; #endif // RFKILLMONITORTHREAD_H kylin-display-switch/kylin-display-switch-mkt.desktop0000644000175000017500000000037714100733566022056 0ustar fengfeng[Desktop Entry] Name=Kylin Display Switch MKT Name[zh_CN]=麒麟显示切换按键提示 Comment=Kylin Display Switch MKT Comment[zh_CN]=麒麟显示切换按键提示 Exec=/usr/bin/mktip StartupNotify=false Terminal=false Type=Application NoDisplay=true kylin-display-switch/registerdbus/0000755000175000017500000000000014107351020016261 5ustar fengfengkylin-display-switch/registerdbus/classrealize.h0000644000175000017500000000547214107351020021123 0ustar fengfeng/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, 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, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef CLASSREALIZE_H #define CLASSREALIZE_H #include #include #include #include class ClassRealize : public QObject { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.ukui.kds.interface") public: explicit ClassRealize(); ~ClassRealize(); public: bool isVirtualWlan(QString dp); signals: Q_SCRIPTABLE void debug0(QString); Q_SCRIPTABLE void signalShowTips(int index); Q_SCRIPTABLE void signalNextOption(); Q_SCRIPTABLE void signalLastOption(); Q_SCRIPTABLE void signalCloseApp(); Q_SCRIPTABLE void signalMakeClicked(); Q_SCRIPTABLE void signalButtonClicked(int x, int y); Q_SCRIPTABLE void signalMediaKeyTrans(int code); Q_SCRIPTABLE void signalRfkillStatusChanged(); public slots: Q_SCRIPTABLE void exitService(); Q_SCRIPTABLE QString helloWorld(); Q_SCRIPTABLE void helloWorldWithSignal(); Q_SCRIPTABLE void emitShowTipsSignal(int index); Q_SCRIPTABLE void emitNextOption(); Q_SCRIPTABLE void emitLastOption(); Q_SCRIPTABLE void emitCloseApp(); Q_SCRIPTABLE void emitMakeClicked(); Q_SCRIPTABLE void emitButtonClicked(int x, int y); Q_SCRIPTABLE void emitMediaKeyTrans(int code); Q_SCRIPTABLE void emitRfkillStatusChanged(); Q_SCRIPTABLE QString getCameraBusinfo(); Q_SCRIPTABLE int getCameraDeviceEnable(); Q_SCRIPTABLE QString toggleCameraDevice(QString businfo); Q_SCRIPTABLE int setCameraKeyboardLight(bool lightup); Q_SCRIPTABLE int getCurrentFlightMode(); Q_SCRIPTABLE QList getStatusBeforeFlightModeEnable(); Q_SCRIPTABLE QString setSingleFlightMode(int type); Q_SCRIPTABLE QString toggleFlightMode(bool enable); Q_SCRIPTABLE int setAirplaneModeKeyboardLight(bool lightup); Q_SCRIPTABLE int getCurrentWlanMode(); Q_SCRIPTABLE QString toggleWlanMode(bool enable); Q_SCRIPTABLE int getCurrentBluetoothMode(); Q_SCRIPTABLE QString toggleBluetoothMode(bool enable); }; #endif // CLASSREALIZE_H kylin-display-switch/registerdbus/registerdbus.pro0000644000175000017500000000222314100733566021520 0ustar fengfengQT += core dbus QT -= gui CONFIG += c++11 CONFIG += link_pkgconfig TARGET = registerdbus CONFIG -= app_bundle TEMPLATE = app TARGET = launchdbus DESTDIR = . target.source += $$TARGET target.path = /usr/bin service.files += conf/org.ukui.kds.service service.path = /usr/share/dbus-1/system-services/ conffile.files += conf/org.ukui.kds.conf conffile.path = /etc/dbus-1/system.d/ INSTALLS += \ target \ service \ conffile SOURCES += main.cpp \ classrealize.cpp # The following define makes your compiler emit warnings if you use # any feature of Qt which as been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if you use deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 HEADERS += \ classrealize.h kylin-display-switch/registerdbus/main.cpp0000644000175000017500000000331014100733566017722 0ustar fengfeng/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, 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, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include #include #include #include #include "classrealize.h" int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); app.setOrganizationName("Kylin Team"); app.setApplicationName("kds-comunication"); QDBusConnection systemBus = QDBusConnection::systemBus(); if (!systemBus.registerService("org.ukui.kds")){ qCritical() << "QDbus register service failed reason:" << systemBus.lastError(); exit(1); } if (!systemBus.registerObject("/", new ClassRealize(), QDBusConnection::ExportAllSlots | QDBusConnection::ExportAllSignals)){ qCritical() << "QDbus register object failed reason:" << systemBus.lastError(); exit(2); } // ClassRealize daemon; // qDebug() << daemon.getCameraDeviceEnable(); return app.exec(); } kylin-display-switch/registerdbus/classrealize.cpp0000755000175000017500000003642014107351020021456 0ustar fengfeng/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, 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, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include #include #include #include "classrealize.h" extern "C" { #include #include #include #define RFKILL_EVENT_SIZE_V1 8 #define VIRTUAL_PATH "/sys/devices/virtual/ieee80211" const char * getRFkillType(__u32 idx); const char * getRFkillName(__u32 idx); struct rfkill_event { __u32 idx; __u8 type; __u8 op; __u8 soft, hard; }; enum rfkill_operation { RFKILL_OP_ADD = 0, RFKILL_OP_DEL, RFKILL_OP_CHANGE, RFKILL_OP_CHANGE_ALL, }; enum rfkill_type { RFKILL_TYPE_ALL = 0, RFKILL_TYPE_WLAN, RFKILL_TYPE_BLUETOOTH, RFKILL_TYPE_UWB, RFKILL_TYPE_WIMAX, RFKILL_TYPE_WWAN, RFKILL_TYPE_GPS, RFKILL_TYPE_FM, RFKILL_TYPE_NFC, NUM_RFKILL_TYPES, }; } ClassRealize::ClassRealize() { } ClassRealize::~ClassRealize(){ } void ClassRealize::exitService(){ qApp->exit(0); } QString ClassRealize::helloWorld(){ return "hello world!"; } void ClassRealize::helloWorldWithSignal(){ emit debug0("hello world"); } void ClassRealize::emitShowTipsSignal(int index){ emit signalShowTips(index); } void ClassRealize::emitNextOption(){ emit signalNextOption(); } void ClassRealize::emitLastOption(){ emit signalLastOption(); } void ClassRealize::emitCloseApp(){ emit signalCloseApp(); } void ClassRealize::emitMakeClicked(){ emit signalMakeClicked(); } void ClassRealize::emitButtonClicked(int x, int y){ emit signalButtonClicked(x, y); } void ClassRealize::emitMediaKeyTrans(int code){ emit signalMediaKeyTrans(code); } void ClassRealize::emitRfkillStatusChanged(){ emit signalRfkillStatusChanged(); } QString ClassRealize::getCameraBusinfo(){ QString path = QString("/sys/bus/usb/devices/"); QDir dir(path); if (!dir.exists()){ return QString(); } dir.setFilter(QDir::Dirs); dir.setSorting(QDir::Name); QFileInfoList fileinfoList = dir.entryInfoList(); for(QFileInfo fileinfo : fileinfoList){ if (fileinfo.fileName() == "." || fileinfo.fileName() == ".."){ continue; } if (fileinfo.fileName().contains(":")){ continue; } if (fileinfo.fileName().startsWith("usb")){ continue; } // qDebug() << "" << fileinfo.fileName() << fileinfo.absoluteFilePath(); QDir subdir(fileinfo.absoluteFilePath()); subdir.setFilter(QDir::Files); QFileInfoList fileinfoList2 = subdir.entryInfoList(); for (QFileInfo fileinfo2 : fileinfoList2){ if (fileinfo2.fileName() == "product"){ QFile pfile(fileinfo2.absoluteFilePath()); if (!pfile.open(QIODevice::ReadOnly | QIODevice::Text)) return QString(); QTextStream pstream(&pfile); QString output = pstream.readAll(); // qDebug() << "output: " << output; if (output.contains("camera", Qt::CaseInsensitive)){ return fileinfo.fileName(); } } } } return QString(); } int ClassRealize::getCameraDeviceEnable(){ QString businfo = getCameraBusinfo(); if (businfo.isEmpty()){ char * cmd = "lsusb -t | grep 'Driver=uvcvideo'"; char output[1024] = "\0"; FILE * stream; if ((stream = popen(cmd, "r")) == NULL){ return -1; } int ret; if (fread(output, sizeof(char), 1024, stream) <= 0){ ret = 0; } else { ret = 1; } fclose(stream); return ret; } int isExists = 0; QString path = QString("/sys/bus/usb/drivers/usb/"); QDir dir(path); if (!dir.exists()){ return -1; } dir.setFilter(QDir::Dirs); dir.setSorting(QDir::Name); QFileInfoList fileinfoList = dir.entryInfoList(); for(QFileInfo fileinfo : fileinfoList){ if (fileinfo.fileName() == "." || fileinfo.fileName() == ".."){ continue; } if (fileinfo.fileName().contains(":")){ continue; } if (fileinfo.fileName() == businfo){ isExists = 1; } } return isExists; } QString ClassRealize::toggleCameraDevice(QString businfo){ QString path = QString("/sys/bus/usb/drivers/usb/"); int status = getCameraDeviceEnable(); if (status == -1){ return QString("Camera Device Not Exists!"); } if (status){ QString cmd = QString("echo '%1' > %2/unbind").arg(businfo).arg(path); system(cmd.toLatin1().data()); return QString("unbinded"); } else { QString cmd = QString("echo '%1' > %2/bind").arg(businfo).arg(path); system(cmd.toLatin1().data()); return QString("binded"); } } bool ClassRealize::isVirtualWlan(QString dp){ QDir dir(VIRTUAL_PATH); if (!dir.exists()){ return false; } dir.setFilter(QDir::Dirs); dir.setSorting(QDir::Name); int count = dir.count(); if (count <= 0){ return false; } QFileInfoList fileinfoList = dir.entryInfoList(); for(QFileInfo fileinfo : fileinfoList){ if (fileinfo.fileName() == "." || fileinfo.fileName() == ".."){ continue; } if (QString::compare(fileinfo.fileName(), dp) == 0){ return true; } } return false; } int ClassRealize::getCurrentWlanMode(){ struct rfkill_event event; ssize_t len; int fd; int bls = 0, unbls = 0; QList status; fd = open("/dev/rfkill", O_RDONLY); if (fd < 0) { qCritical("Can't open RFKILL control device"); return -1; } if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) { qCritical("Can't set RFKILL control device to non-blocking"); close(fd); return -1; } while (1) { len = read(fd, &event, sizeof(event)); if (len < 0) { if (errno == EAGAIN) break; qWarning("Reading of RFKILL events failed"); break; } if (len != RFKILL_EVENT_SIZE_V1) { qWarning("Wrong size of RFKILL event\n"); continue; } // printf("%u - %u: %u\n", event.idx, event.type, event.soft); if (event.type != RFKILL_TYPE_WLAN) continue; if (isVirtualWlan(QString(getRFkillName(event.idx)))){ continue; } status.append(event.soft ? 1 : 0); } close(fd); if (status.length() == 0){ return -1; } for (int s : status){ s ? bls++ : unbls++; } if (bls == status.length()){ //block return 0; } else if (unbls == status.length()){ //unblock return 1; } else { //not block & not unblock return 0; } } QString ClassRealize::toggleWlanMode(bool enable){ struct rfkill_event event; int fd; ssize_t len; __u8 block; fd = open("/dev/rfkill", O_RDWR); if (fd < 0) { return QString("Can't open RFKILL control device"); } block = enable ? 0 : 1; memset(&event, 0, sizeof(event)); event.op= RFKILL_OP_CHANGE_ALL; event.type = RFKILL_TYPE_WLAN; event.soft = block; len = write(fd, &event, sizeof(event)); if (len < 0){ return QString("Failed to change RFKILL state"); } close(fd); return block ? QString("blocked") : QString("unblocked"); } int ClassRealize::getCurrentBluetoothMode(){ struct rfkill_event event; ssize_t len; int fd; int bls = 0, unbls = 0; QList status; fd = open("/dev/rfkill", O_RDONLY); if (fd < 0) { qCritical("Can't open RFKILL control device"); return -1; } if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) { qCritical("Can't set RFKILL control device to non-blocking"); close(fd); return -1; } while (1) { len = read(fd, &event, sizeof(event)); if (len < 0) { if (errno == EAGAIN) break; qWarning("Reading of RFKILL events failed"); break; } if (len != RFKILL_EVENT_SIZE_V1) { qWarning("Wrong size of RFKILL event\n"); continue; } // printf("%u - %u: %u\n", event.idx, event.type, event.soft); if (event.type != RFKILL_TYPE_BLUETOOTH) continue; status.append(event.soft ? 1 : 0); } close(fd); if (status.length() == 0){ return -1; } for (int s : status){ s ? bls++ : unbls++; } if (bls == status.length()){ //block return 0; } else if (unbls == status.length()){ //unblock return 1; } else { //not block & not unblock return 0; } } QString ClassRealize::toggleBluetoothMode(bool enable){ struct rfkill_event event; int fd; ssize_t len; __u8 block; fd = open("/dev/rfkill", O_RDWR); if (fd < 0) { return QString("Can't open RFKILL control device"); } block = enable ? 0 : 1; memset(&event, 0, sizeof(event)); event.op= RFKILL_OP_CHANGE_ALL; event.type = RFKILL_TYPE_BLUETOOTH; event.soft = block; len = write(fd, &event, sizeof(event)); if (len < 0){ return QString("Failed to change RFKILL state"); } close(fd); return block ? QString("blocked") : QString("unblocked"); } QList ClassRealize::getStatusBeforeFlightModeEnable(){ QList re; struct rfkill_event event; ssize_t len; int fd; int bls = 0, unbls = 0; QList status; fd = open("/dev/rfkill", O_RDONLY); if (fd < 0) { qCritical("Can't open RFKILL control device"); return re; } if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) { qCritical("Can't set RFKILL control device to non-blocking"); close(fd); return re; } while (1) { len = read(fd, &event, sizeof(event)); if (len < 0) { if (errno == EAGAIN) break; qWarning("Reading of RFKILL events failed"); break; } if (len != RFKILL_EVENT_SIZE_V1) { qWarning("Wrong size of RFKILL event\n"); continue; } if (isVirtualWlan(QString(getRFkillName(event.idx)))){ continue; } // printf("%u: %u\n", event.idx, event.soft); // status.append(event.soft ? 1 : 0); if (!event.soft && !re.contains(event.type)){ re.append(event.type); } } close(fd); return re; } QString ClassRealize::setSingleFlightMode(int type){ struct rfkill_event event; int fd; ssize_t len; __u8 block = 0; fd = open("/dev/rfkill", O_RDWR); if (fd < 0) { return QString("Can't open RFKILL control device"); } memset(&event, 0, sizeof(event)); event.op= RFKILL_OP_CHANGE_ALL; /* RFKILL_TYPE_ALL = 0 */ event.type = type; event.soft = block; len = write(fd, &event, sizeof(event)); if (len < 0){ return QString("Failed to change RFKILL state"); } close(fd); return QString(); } int ClassRealize::getCurrentFlightMode(){ struct rfkill_event event; ssize_t len; int fd; int bls = 0, unbls = 0; QList status; fd = open("/dev/rfkill", O_RDONLY); if (fd < 0) { qCritical("Can't open RFKILL control device"); return -1; } if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) { qCritical("Can't set RFKILL control device to non-blocking"); close(fd); return -1; } while (1) { len = read(fd, &event, sizeof(event)); if (len < 0) { if (errno == EAGAIN) break; qWarning("Reading of RFKILL events failed"); break; } if (len != RFKILL_EVENT_SIZE_V1) { qWarning("Wrong size of RFKILL event\n"); continue; } if (isVirtualWlan(QString(getRFkillName(event.idx)))){ continue; } // printf("%u: %u\n", event.idx, event.soft); status.append(event.soft ? 1 : 0); } close(fd); if (status.length() == 0){ return -1; } for (int s : status){ s ? bls++ : unbls++; } if (bls == status.length()){ //block return 1; } else if (unbls == status.length()){ //unblock return 0; } else { //not block & not unblock return 0; } } QString ClassRealize::toggleFlightMode(bool enable){ struct rfkill_event event; int fd; ssize_t len; __u8 block; fd = open("/dev/rfkill", O_RDWR); if (fd < 0) { return QString("Can't open RFKILL control device"); } block = enable ? 1 : 0; memset(&event, 0, sizeof(event)); event.op= RFKILL_OP_CHANGE_ALL; /* RFKILL_TYPE_ALL = 0 */ event.type = RFKILL_TYPE_ALL; event.soft = block; len = write(fd, &event, sizeof(event)); if (len < 0){ return QString("Failed to change RFKILL state"); } close(fd); return QString(); } int ClassRealize::setCameraKeyboardLight(bool lightup){ char * target = "/sys/class/leds/platform::cameramute/brightness"; if (access(target, F_OK) == -1){ return -1; } int value = lightup ? 1 : 0; char cmd[256]; sprintf(cmd, "echo %d > %s", value, target); system(cmd); return 1; } int ClassRealize::setAirplaneModeKeyboardLight(bool lightup){ char * target = "/sys/class/leds/platform::wlanmute/brightness"; if (access(target, F_OK) == -1){ return -1; } int value = lightup ? 1 : 0; char cmd[256]; sprintf(cmd, "echo %d > %s", value, target); system(cmd); return 1; } const char * getRFkillName(__u32 idx){ static char name[128] = {}; char *pos, filename[64]; int fd; snprintf(filename, sizeof(filename) - 1, "/sys/class/rfkill/rfkill%u/name", idx); fd = open(filename, O_RDONLY); if (fd < 0) return NULL; memset(name, 0, sizeof(name)); read(fd, name, sizeof(name) - 1); pos = strchr(name, '\n'); if (pos) *pos = '\0'; close(fd); return name; } const char * getRFkillType(__u32 idx){ static char name[128] = {}; char *pos, filename[64]; int fd; snprintf(filename, sizeof(filename) - 1, "/sys/class/rfkill/rfkill%u/type", idx); fd = open(filename, O_RDONLY); if (fd < 0) return NULL; memset(name, 0, sizeof(name)); read(fd, name, sizeof(name) - 1); pos = strchr(name, '\n'); if (pos) *pos = '\0'; close(fd); return name; } kylin-display-switch/registerdbus/conf/0000755000175000017500000000000014100733566017222 5ustar fengfengkylin-display-switch/registerdbus/conf/org.ukui.kds.service0000644000175000017500000000010514100733566023123 0ustar fengfeng[D-BUS Service] Name=org.ukui.kds Exec=/usr/bin/launchdbus User=root kylin-display-switch/registerdbus/conf/org.ukui.kds.conf0000644000175000017500000000151514100733566022416 0ustar fengfeng kylin-display-switch/kds/0000755000175000017500000000000014107351020014340 5ustar fengfengkylin-display-switch/kds/widget.h0000644000175000017500000000511614107351020015777 0ustar fengfeng/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, 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, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef WIDGET_H #define WIDGET_H #include #include #ifdef signals #undef signals #endif extern "C" { #define MATE_DESKTOP_USE_UNSTABLE_API #include #include #include #include } class QDBusInterface; namespace Ui { class Widget; } class Widget : public QWidget { Q_OBJECT public: explicit Widget(QWidget *parent = 0); ~Widget(); public: void beginSetup(); void initData(); void setupComponent(); void setupConnect(); MateRRConfig * makeCloneSetup(); MateRRConfig * makePrimarySetup(); MateRRConfig * makeOtherSetup(); MateRRConfig * makeXineramaSetup(); int getCurrentStatus(); void initCurrentStatus(int id); void setCurrentFirstOutputTip(); QDBusInterface * ukcciface; private: Ui::Widget *ui; QButtonGroup * btnsGroup; private: MateRRScreen * kScreen; // MateRRConfig * kConfig; private: bool _getCloneSize(int * width, int * height); bool _isLaptop(MateRROutputInfo * info); bool _setNewPrimaryOutput(MateRRConfig * config); bool _turnonOutput(MateRROutputInfo * info, int x, int y); MateRRMode * _findBestMode(MateRROutput * output); int _turnonGetRightmostOffset(MateRROutputInfo * info, int x); bool _configIsAllOff(MateRRConfig * config); char * _findFirstOutput(MateRRConfig * config); public slots: void msgReceiveAnotherOne(const QString &msg); private slots: void nextSelectedOption(); void lastSelectedOption(); void confirmCurrentOption(); void receiveButtonClick(int x, int y); void closeApp(); Q_SIGNALS: void tellBtnClicked(int id); }; #endif // WIDGET_H kylin-display-switch/kds/expendbutton.h0000644000175000017500000000113614100733566017245 0ustar fengfeng#ifndef EXPENDBUTTON_H #define EXPENDBUTTON_H #include #include #include class ExpendButton : public QPushButton { Q_OBJECT public: explicit ExpendButton(QWidget *parent = 0); ~ExpendButton(); public: void setSign(int id); void setBtnLogo(QString logo); void setBtnText(QString text); void setBtnChecked(bool checked); bool getBtnChecked(); private: QLabel * logoLabel; QLabel * textLabel; QLabel * spaceLabel; QLabel * statusLabel; int sign; QString qss0; QString qss1; }; #endif // EXPENDBUTTON_H kylin-display-switch/kds/kdswidget.cpp0000644000175000017500000005126714107351020017044 0ustar fengfeng#include "kdswidget.h" #include "ui_kdswidget.h" #include #include #include #include #include #include "expendbutton.h" #define TITLEHEIGHT 90 #define OPTIONSHEIGHT 70 #define BOTTOMHEIGHT 60 enum { FIRSTSCREEN, CLONESCREEN, EXTENDSCREEN, // LEXTENDSCREEN, OTHERSCREEN, ALLMODES, }; bool operator<(const QSize &s1, const QSize &s2) { return s1.width() * s1.height() < s2.width() * s2.height(); } template<> bool qMapLessThanKey(const QSize &s1, const QSize &s2) { return s1 < s2; } KDSWidget::KDSWidget(QWidget *parent) : QWidget(parent), ui(new Ui::KDSWidget) { ui->setupUi(this); } KDSWidget::~KDSWidget() { delete ui; } void KDSWidget::beginSetupKF5(){ QObject::connect(new KScreen::GetConfigOperation(), &KScreen::GetConfigOperation::finished, [&](KScreen::ConfigOperation *op) { setConfig(qobject_cast(op)->config()); }); setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint); setAttribute(Qt::WA_TranslucentBackground, true); /* 不在任务栏显示图标 */ KWindowSystem::setState(winId(), NET::SkipTaskbar | NET::SkipPager); btnsGroup = new QButtonGroup; QDBusConnection::systemBus().connect(QString(), \ QString(), \ "org.ukui.kds.interface", \ "signalNextOption", \ this, SLOT(nextSelectedOption())); QDBusConnection::systemBus().connect(QString(), \ QString(), \ "org.ukui.kds.interface", \ "signalLastOption", \ this, SLOT(lastSelectedOption())); QDBusConnection::systemBus().connect(QString(), \ QString(), \ "org.ukui.kds.interface", \ "signalCloseApp", \ this, SLOT(closeApp())); QDBusConnection::systemBus().connect(QString(), \ QString(), \ "org.ukui.kds.interface", \ "signalMakeClicked", \ this, SLOT(confirmCurrentOption())); QDBusConnection::systemBus().connect(QString(), \ QString(), \ "org.ukui.kds.interface", \ "signalButtonClicked", \ this, SLOT(receiveButtonClick(int,int))); } QString KDSWidget::getCurrentPrimaryScreenName(){ QDBusInterface usdiface("org.ukui.SettingsDaemon", "/org/ukui/SettingsDaemon/wayland", "org.ukui.SettingsDaemon.wayland", QDBusConnection::sessionBus()); if (usdiface.isValid()){ QDBusReply reply = usdiface.call("priScreenName"); if (reply.isValid()){ return reply.value(); } } return QString(""); } int KDSWidget::getCurrentScale(){ QDBusInterface usdiface("org.ukui.SettingsDaemon", "/org/ukui/SettingsDaemon/wayland", "org.ukui.SettingsDaemon.wayland", QDBusConnection::sessionBus()); if (usdiface.isValid()){ QDBusReply reply = usdiface.call("scale"); if (reply.isValid()){ return reply.value(); } } return 1; } QPoint KDSWidget::getWinPos(){ QString pName = getCurrentPrimaryScreenName(); if (!pName.isEmpty()){ const KScreen::ConfigPtr &config = this->currentConfig(); Q_FOREACH(const KScreen::OutputPtr &output, config->connectedOutputs()) { if (QString::compare(output.data()->name(), pName) == 0){ QRect rect = output.data()->geometry(); return rect.center(); } } } QScreen * pScreen = QGuiApplication::screens().at(0); return pScreen->geometry().center(); } void KDSWidget::setupComponent(){ ui->outputPrimaryTip->hide(); // setCurrentFirstOutputTip(); for (int i = 0; i < ALLMODES; i++){ ExpendButton * btn = new ExpendButton(); btn->setFixedHeight(70); btnsGroup->addButton(btn, i); switch (i) { case FIRSTSCREEN: btn->setSign(FIRSTSCREEN % 2); btn->setBtnText(tr("First Screen")); btn->setBtnLogo(":/img/main.png"); break; case CLONESCREEN: btn->setSign(CLONESCREEN % 2); btn->setBtnText(tr("Clone Screen")); btn->setBtnLogo(":/img/clone.png"); break; case EXTENDSCREEN: btn->setSign(EXTENDSCREEN % 2); btn->setBtnText(tr("Extend Screen")); btn->setBtnLogo(":/img/extend.png"); break; // case LEXTENDSCREEN: // btn->setSign(LEXTENDSCREEN % 2); // btn->setBtnText(tr("Left Extend Screen")); // btn->setBtnLogo(":/img/extend.png"); // break; case OTHERSCREEN: btn->setSign(OTHERSCREEN % 2); btn->setBtnText(tr("Vice Screen")); btn->setBtnLogo(":/img/vice.png"); break; default: break; } ui->btnsVerLayout->addWidget(btn); } int h = TITLEHEIGHT + OPTIONSHEIGHT * ALLMODES + BOTTOMHEIGHT; setFixedWidth(400); setFixedHeight(h); /// QSS ui->titleFrame->setStyleSheet("QFrame#titleFrame{background: #A6000000; border: none; border-top-left-radius: 24px; border-top-right-radius: 24px;}"); ui->bottomFrame->setStyleSheet("QFrame#bottomFrame{background: #A6000000; border: none; border-bottom-left-radius: 24px; border-bottom-right-radius: 24px;}"); ui->splitFrame->setStyleSheet("QFrame#splitFrame{background: #99000000; border: none;}"); ui->titleLabel->setStyleSheet("QLabel{color: #FFFFFF; font-size: 24px;}"); ui->outputPrimaryTip->setStyleSheet("QLabel{color: #60FFFFFF; font-size: 18px;}"); ui->outputName->setStyleSheet("QLabel{color: #60FFFFFF; font-size: 18px;}"); ui->outputDisplayName->setStyleSheet("QLabel{color: #60FFFFFF; font-size: 18px;}"); } void KDSWidget::setupConnect(){ connect(btnsGroup, static_cast(&QButtonGroup::buttonClicked), this, [=](int id){ /* 获取旧选项 */ for (QAbstractButton * button : btnsGroup->buttons()){ ExpendButton * btn = dynamic_cast(button); // qDebug() << "old index: " << btn->getBtnChecked(); int index = btnsGroup->id(button); if (index == id && btn->getBtnChecked()){ goto closeapp; } } switch (id) { case FIRSTSCREEN: setFirstModeSetup(); setCurrentUIStatus(FIRSTSCREEN); break; case CLONESCREEN: setCloneModeSetup(); setCurrentUIStatus(CLONESCREEN); break; case EXTENDSCREEN: setExtendModeSetup(); setCurrentUIStatus(EXTENDSCREEN); break; // case LEXTENDSCREEN: // setLeftExtendModeSetup(); // setCurrentUIStatus(LEXTENDSCREEN); // break; case OTHERSCREEN: setOtherModeSetup(); setCurrentUIStatus(OTHERSCREEN); break; default: break; } closeapp: close(); }); } int KDSWidget::getCurrentStatus(){ QString firstOutputName; const KScreen::ConfigPtr &config = this->currentConfig(); const KScreen::OutputList &outputs = config->connectedOutputs(); firstOutputName = findFirstOutput(); if (outputs.count() < 2){ return FIRSTSCREEN; } else { /* output.data()->clones().isEmpty() is not valid */ Q_FOREACH(const KScreen::OutputPtr &output, outputs) { // if (!output.data()->clones().isEmpty()){ // return CLONESCREEN; // } if (QString::compare(firstOutputName, output.data()->name()) == 0){ if (!output.data()->isEnabled()){ return OTHERSCREEN; } } if (!output.data()->isEnabled()){ return FIRSTSCREEN; } } Q_FOREACH(const KScreen::OutputPtr &output, outputs) { if (output.data()->pos().x() != 0){ return EXTENDSCREEN; } } return CLONESCREEN; } // Q_FOREACH(const KScreen::OutputPtr &output, outputs) { // if (QString::compare(firstOutputName, output.data()->name()) == 0){ // QPoint pPos = output.data()->pos(); // if (pPos.x() > 0){ // return LEXTENDSCREEN; // } else { // return REXTENDSCREEN; // } // } // } } void KDSWidget::setCurrentUIStatus(int id){ //set all no checked for (QAbstractButton * button : btnsGroup->buttons()){ ExpendButton * btn = dynamic_cast(button); btn->setBtnChecked(false); if (id == btnsGroup->id(button)){ btn->setBtnChecked(true); btn->setChecked(true); } } // status == -1 if (id == -1){ ExpendButton * btn1 = dynamic_cast(btnsGroup->button(FIRSTSCREEN)); // btn1->setBtnChecked(true); btn1->setChecked(true); } } void KDSWidget::setConfig(const KScreen::ConfigPtr &config) { mConfig = config; //获取主屏位置 QPoint point = getWinPos(); move(point.x() - width()/2, point.y() - height()/2); setupComponent(); setupConnect(); setCurrentUIStatus(getCurrentStatus()); } KScreen::ConfigPtr KDSWidget::currentConfig() const { return mConfig; } void KDSWidget::setCurrentFirstOutputTip(){ const KScreen::ConfigPtr &config = this->currentConfig(); QString firstOutputName = findFirstOutput(); Q_FOREACH(const KScreen::OutputPtr &output, config->connectedOutputs()) { QString opName = output.data()->name(); QString opDisName = output.data()->edid()->name(); if (QString::compare(firstOutputName, output.data()->name()) == 0){ ui->outputName->setText(opName); ui->outputDisplayName->setText(""/*opDisName*/); return; } } ui->outputName->setText(tr("N/A")); } QString KDSWidget::findFirstOutput(){ int firstopID = -1; QString firstopName; const KScreen::ConfigPtr &config = this->currentConfig(); Q_FOREACH(const KScreen::OutputPtr &output, config->connectedOutputs()) { if (firstopID == -1){ firstopID = output.data()->id(); firstopName = output.data()->name(); } if (firstopID > output.data()->id()){ firstopID = output.data()->id(); firstopName = output.data()->name(); } } return firstopName; } void KDSWidget::setCloneModeSetup(){ QList clones; const KScreen::ConfigPtr &config = this->currentConfig(); QSize cloneSize = findBestCloneSize(); Q_FOREACH(const KScreen::OutputPtr &output, config->connectedOutputs()) { float bestRate = 0.0; QString bestID; output.data()->setEnabled(true); Q_FOREACH (const KScreen::ModePtr &mode, output->modes()) { if (mode.data()->size() == cloneSize){ float r = mode.data()->refreshRate(); if (bestRate < r){ bestRate = r; bestID = mode.data()->id(); } } } if (bestRate > 0){ output.data()->setCurrentModeId(bestID); output.data()->setRotation(KScreen::Output::None); output.data()->setPos(QPoint(0, 0)); if (!output.data()->isPrimary()){ clones.append(output.data()->id()); } } } Q_FOREACH(const KScreen::OutputPtr &output, config->connectedOutputs()) { if (output.data()->isPrimary()){ output.data()->setClones(clones); } else { output.data()->setClones(QList()); } } if (!KScreen::Config::canBeApplied(config)) { // qDebug() << "Can not apply!"; return; } auto *op = new KScreen::SetConfigOperation(config); op->exec(); syncPrimaryScreenData(getCurrentPrimaryScreenName()); } void KDSWidget::setExtendModeSetup(){ const KScreen::ConfigPtr &config = this->currentConfig(); int x = 0; Q_FOREACH(const KScreen::OutputPtr &output, config->connectedOutputs()) { if (!output.data()->isPrimary()){ continue; } output.data()->setEnabled(true); output.data()->setClones(QList()); x = turnonAndGetRightmostOffset(output, x); } Q_FOREACH(const KScreen::OutputPtr &output, config->connectedOutputs()) { if (output.data()->isPrimary()){ continue; } output.data()->setEnabled(true); output.data()->setClones(QList()); x = turnonAndGetRightmostOffset(output, x); } if (!KScreen::Config::canBeApplied(config)) { // qDebug() << "Can not apply!"; return; } auto *op = new KScreen::SetConfigOperation(config); op->exec(); // syncPrimaryScreenData(getCurrentPrimaryScreenName()); } void KDSWidget::setLeftExtendModeSetup(){ const KScreen::ConfigPtr &config = this->currentConfig(); int x = 0; Q_FOREACH(const KScreen::OutputPtr &output, config->connectedOutputs()) { if (output.data()->isPrimary()){ continue; } output.data()->setEnabled(true); output.data()->setClones(QList()); x = turnonAndGetRightmostOffset(output, x); } Q_FOREACH(const KScreen::OutputPtr &output, config->connectedOutputs()) { if (!output.data()->isPrimary()){ continue; } output.data()->setEnabled(true); output.data()->setClones(QList()); x = turnonAndGetRightmostOffset(output, x); } if (!KScreen::Config::canBeApplied(config)) { // qDebug() << "Can not apply!"; return; } auto *op = new KScreen::SetConfigOperation(config); op->exec(); Q_FOREACH(const KScreen::OutputPtr &output, config->connectedOutputs()) { qDebug() << "\n" << output.data()->name() << output.data()->clones() << output.data()->clone(); } } void KDSWidget::setFirstModeSetup(){ const KScreen::ConfigPtr &config = this->currentConfig(); QString firstName = findFirstOutput(); Q_FOREACH(const KScreen::OutputPtr &output, config->connectedOutputs()) { /* 取消镜像模式标志位 */ output.data()->setClones(QList()); if (QString::compare(output.data()->name(), firstName) == 0){ turnonSpecifiedOutput(output, 0, 0); } else { output.data()->setEnabled(false); } } if (!KScreen::Config::canBeApplied(config)) { // qDebug() << "Can not apply!"; return; } auto * op = new KScreen::SetConfigOperation(config); op->exec(); syncPrimaryScreenData(firstName); } void KDSWidget::setOtherModeSetup(){ const KScreen::ConfigPtr &config = this->currentConfig(); QString firstName = findFirstOutput(); QString otherName; Q_FOREACH(const KScreen::OutputPtr &output, config->connectedOutputs()) { /* 取消镜像模式标志位 */ output.data()->setClones(QList()); if (QString::compare(output.data()->name(), firstName) == 0){ output.data()->setEnabled(false); } else { // output.data()->setEnabled(true); turnonSpecifiedOutput(output, 0, 0); } //获取非主屏的Name。TODO:多屏(>2)情况下呢? if (QString::compare(output.data()->name(), firstName) == 0){ } else { otherName = output.data()->name(); } } if (!KScreen::Config::canBeApplied(config)) { // qDebug() << "Can not apply!"; return; } auto * op = new KScreen::SetConfigOperation(config); op->exec(); syncPrimaryScreenData(otherName); } int KDSWidget::turnonAndGetRightmostOffset(const KScreen::OutputPtr &output, int x){ turnonSpecifiedOutput(output, x, 0); int width; // width = output.data()->size().width(); width = output.data()->preferredMode().data()->size().width(); // qDebug() << output.data()->name() << "width is " << output.data()->size() << output.data()->preferredMode().data()->size(); // Q_FOREACH (const KScreen::ModePtr &mode, output->modes()) { // qDebug() << "mode is: " << mode.data()->id() << mode.data()->size(); // } x += width; return x; } bool KDSWidget::turnonSpecifiedOutput(const KScreen::OutputPtr &output, int x, int y){ output->setEnabled(true); output->setCurrentModeId(output.data()->preferredModeId()); output->setRotation(KScreen::Output::None); output->setPos(QPoint(x, y)); return true; } QSize KDSWidget::findBestCloneSize(){ const KScreen::ConfigPtr &config = this->currentConfig(); QMap commonSizes; Q_FOREACH(const KScreen::OutputPtr &output, config->connectedOutputs()) { QList pSizes; Q_FOREACH (const KScreen::ModePtr &mode, output->modes()) { QSize s = mode.data()->size(); if (pSizes.contains(s)) continue; pSizes.append(s); if (commonSizes.contains(s)){ commonSizes[s]++; } else { commonSizes.insert(s, 1); } } } QList commonResults = commonSizes.keys(config->connectedOutputs().count()); QSize smallestSize; /* TODO: */ if (commonSizes.isEmpty()){ // Q_FOREACH (const KScreen::OutputPtr &output, config->connectedOutputs()) { // if (!smallestSize.isValid() || output->preferredMode()->size() < smallestSize) { // smallestSize = output->preferredMode()->size(); // } // } } else { Q_FOREACH(QSize s1, commonResults){ if (!smallestSize.isValid() || smallestSize < s1){ smallestSize = s1; } } } return smallestSize; } void KDSWidget::nextSelectedOption(){ int current = btnsGroup->checkedId(); int next; /* no button checked */ // if (current == -1) // ; next = current == ALLMODES - 1 ? 0 : current + 1; ExpendButton * btn = dynamic_cast(btnsGroup->button(next)); btn->setChecked(true); } void KDSWidget::lastSelectedOption(){ int current = btnsGroup->checkedId(); int last; /* no button checked */ if (current == -1) current = ALLMODES; last = current == 0 ? ALLMODES - 1 : current - 1; ExpendButton * btn = dynamic_cast(btnsGroup->button(last)); btn->setChecked(true); } void KDSWidget::confirmCurrentOption(){ int current = btnsGroup->checkedId(); // qDebug() << "current checked" << current; if (current == -1) return; ExpendButton * btn = dynamic_cast(btnsGroup->button(current)); btn->click(); } void KDSWidget::closeApp(){ close(); } void KDSWidget::receiveButtonClick(int x, int y){ // qDebug() << "receive button press " << x << y; if (!this->geometry().contains(x, y)){ close(); } } void KDSWidget::msgReceiveAnotherOne(const QString &msg){ // qDebug() << "another one " << msg; nextSelectedOption(); } void KDSWidget::syncPrimaryScreenData(QString pName){ if (!pName.isEmpty()){ const KScreen::ConfigPtr &config = this->currentConfig(); int scale = getCurrentScale(); Q_FOREACH(const KScreen::OutputPtr &output, config->connectedOutputs()) { if (QString::compare(output.data()->name(), pName) == 0){ QRect rect = output.data()->geometry(); QDBusMessage message = QDBusMessage::createMethodCall("org.ukui.SettingsDaemon", "/org/ukui/SettingsDaemon/wayland", "org.ukui.SettingsDaemon.wayland", "priScreenChanged"); message << rect.x() / scale << rect.y() / scale << rect.width() / scale << rect.height() / scale << pName; QDBusConnection::sessionBus().send(message); } } } } kylin-display-switch/kds/kds.pro0000644000175000017500000000353114100733566015661 0ustar fengfeng#------------------------------------------------- # # Project created by QtCreator 2020-11-12T15:37:31 # #------------------------------------------------- QT += core gui dbus network KWindowSystem KScreen greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = kydisplayswitch TEMPLATE = app # The following define makes your compiler emit warnings if you use # any feature of Qt which as been marked as deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS include (../shared/qtsingleapplication/qtsingleapplication.pri) LIBS += -lX11 CONFIG += link_pkgconfig CONFIG += C++11 PKGCONFIG += mate-desktop-2.0 \ # You can also make your code fail to compile if you use deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 target.source += $$TARGET target.path = /usr/bin gsetting.files += ../conf/org.ukui.kds.gschema.xml gsetting.path = /usr/share/glib-2.0/schemas desktop.files += ../kylin-display-switch-daemon.desktop desktop.files += ../kylin-display-switch-mkt.desktop desktop.path = /etc/xdg/autostart/ service.files += ../conf/kylin-display-switch.service service.path = /usr/lib/systemd/system/ INSTALLS += \ target \ gsetting \ desktop \ service \ SOURCES += \ kdswidget.cpp \ main.cpp \ widget.cpp \ expendbutton.cpp HEADERS += \ kdswidget.h \ widget.h \ expendbutton.h FORMS += \ kdswidget.ui \ widget.ui RESOURCES += \ res/img.qrc TRANSLATIONS += \ res/zh_CN.ts \ kylin-display-switch/kds/main.cpp0000644000175000017500000000513414107351020015773 0ustar fengfeng/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, 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, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "widget.h" #include "kdswidget.h" #include #include "qtsingleapplication.h" #include #include int getCurrentScreenWidth(){ Display * pDis = XOpenDisplay(0); if (NULL == pDis){ return 0; } Screen * pScreen = DefaultScreenOfDisplay(pDis); if (NULL == pScreen){ return 0; } int width = pScreen->width; XCloseDisplay(pDis); return width; } int main(int argc, char *argv[]) { if (getCurrentScreenWidth() > 2560){ QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); } QString id = QString("kds" + QLatin1String(getenv("DISPLAY"))); QtSingleApplication app(id, argc, argv); if (app.isRunning()){ app.sendMessage("hello world!"); return 0; /* EXIT_SUCCESS */ } QTranslator qtTranslator; qtTranslator.load(QString(":/%1").arg(QLocale::system().name())); app.installTranslator(&qtTranslator); KDSWidget kdsw; Widget w; QString sessionType = qgetenv("XDG_SESSION_TYPE"); if (QString::compare(sessionType, "wayland") == 0){ kdsw.beginSetupKF5(); // QObject::connect(&app, SIGNAL(messageReceived(const QString&, NULL)), &w, SLOT(msgReceiveAnotherOne(QString))); QObject::connect(&app, &QtSingleApplication::messageReceived, &kdsw, &KDSWidget::msgReceiveAnotherOne); kdsw.show(); } else { w.beginSetup(); // QObject::connect(&app, SIGNAL(messageReceived(const QString&, NULL)), &w, SLOT(msgReceiveAnotherOne(QString))); QObject::connect(&app, &QtSingleApplication::messageReceived, &w, &Widget::msgReceiveAnotherOne); w.show(); } return app.exec(); } kylin-display-switch/kds/expendbutton.cpp0000644000175000017500000000473014100733566017603 0ustar fengfeng#include "expendbutton.h" #include ExpendButton::ExpendButton(QWidget *parent) : QPushButton(parent) { setFocusPolicy(Qt::NoFocus); setCheckable(true); sign = 0; qss0 = QString("QPushButton{background: #99000000; border: none;}" "QPushButton:hover{background: #80000000; border: none;}" "QPushButton:checked{background: #80000000; border: none;}" "/*QPushButton:!checked{background: #99000000; border: none;}*/"); qss1 = QString("QPushButton{background: #A6000000; border: none;}" "QPushButton:hover{background: #80000000; border: none;}" "QPushButton:checked{background: #80000000; border: none;}" "/*QPushButton:!checked{background: #A6000000; border: none;}*/"); QHBoxLayout * generalHorLayout = new QHBoxLayout(this); generalHorLayout->setSpacing(0); generalHorLayout->setContentsMargins(44, 0, 20, 0); logoLabel = new QLabel(this); logoLabel->setFixedSize(QSize(60, 60)); textLabel = new QLabel(this); textLabel->setStyleSheet("QLabel{color: #FFFFFF; font-size: 18px;}"); QSizePolicy textSizePolicy = textLabel->sizePolicy(); textSizePolicy.setHorizontalPolicy(QSizePolicy::Fixed); textSizePolicy.setVerticalPolicy(QSizePolicy::Fixed); textLabel->setSizePolicy(textSizePolicy); spaceLabel = new QLabel(this); spaceLabel->setFixedSize(QSize(60, 30)); statusLabel = new QLabel(this); statusLabel->setFixedSize(QSize(27, 18)); statusLabel->setPixmap(QPixmap(":/img/selected.png")); generalHorLayout->addWidget(logoLabel, Qt::AlignVCenter); generalHorLayout->addWidget(spaceLabel, Qt::AlignVCenter); generalHorLayout->addWidget(textLabel, Qt::AlignVCenter); generalHorLayout->addStretch(); generalHorLayout->addWidget(statusLabel, Qt::AlignVCenter); setLayout(generalHorLayout); } ExpendButton::~ExpendButton() { } void ExpendButton::setSign(int id){ sign = id; if (sign == 0){ setStyleSheet(qss0); } else if (sign == 1){ setStyleSheet(qss1); } } void ExpendButton::setBtnLogo(QString logo){ logoLabel->setPixmap(QPixmap(logo)); } void ExpendButton::setBtnText(QString text){ textLabel->setText(text); } void ExpendButton::setBtnChecked(bool checked){ if (checked){ statusLabel->show(); } else { statusLabel->hide(); } } bool ExpendButton::getBtnChecked(){ return statusLabel->isVisible(); } kylin-display-switch/kds/res/0000755000175000017500000000000014100733566015145 5ustar fengfengkylin-display-switch/kds/res/img/0000755000175000017500000000000014100733566015721 5ustar fengfengkylin-display-switch/kds/res/img/phone.png0000644000175000017500000000035414100733566017542 0ustar fengfengPNG  IHDR;0 pHYs  ~IDATH Fy  ڠ Q~e @5!$B ֒<4W'%wj;RH&6Mlb@ ğ=2?$fmDm<"ԎdFcOǚ{w8v%ۙVغ 58UdwIENDB`kylin-display-switch/kds/res/img/clone.png0000644000175000017500000000117614100733566017534 0ustar fengfengPNG  IHDR<<:r pHYs  ~0IDAThq0?_6NP6lP7(#8n8A=r"H $mw3|B0B`JO6O@w`}$#%amUKHl+[zʖ=?h\.,{;ܠ`ыآ] LR^J " J4"8گ#yK\Ce]g)+eW6.^'oowlÏLNK97g~g]kc7qo*I%b]ZەrT,Z7 W PGGŨ1ᮣ{/*||H)6+SZng8oذ_KnR KYL7TF-3*3T4֢S[xwԆ[ g,<8gX>{ 5}dxG[ܔ۴[KDaDaDaDaDaDaDa0iAIENDB`kylin-display-switch/kds/res/img/vice.png0000644000175000017500000000102714100733566017355 0ustar fengfengPNG  IHDR<<:r pHYs  ~IDATh1NAȆ+mƚ`GKz7Xۈ4cf . 3}$Kﷳ3LGeQa騰tN4z~0Z$ f|& k!n;}ZAgi騰tT8 ͮ z ? эفNZQa v?Hn W$Ηo\^Dmk|-h;yB7Y`Œ)ԋ5K6"Vf [lL b>gtnZR=Bpolf_ZJGQa騰tTX:*, o.|yOIENDB`kylin-display-switch/kds/res/img/extend.png0000644000175000017500000000115114100733566017714 0ustar fengfengPNG  IHDR<<:r pHYs  ~IDAThZm }_olPoNPolPwz&dgtvw*ңEQb|y'㸃,RIpHcG;f)8[K^!siIO¥&v'SV3w\2@.µ`*s`i,(Ɉ|БqCLm !+*p5n-Ցߞ\X<={Ϲx}&,\h tiyҚ N img/clone.png img/extend.png img/main.png img/phone.png img/selected.png img/vice.png zh_CN.qm kylin-display-switch/kds/res/zh_CN.ts0000644000175000017500000000501614100733566016520 0ustar fengfeng KDSWidget System Screen Projection 系统投屏 FirstOutput: 第一屏幕: First Screen 第一屏 Clone Screen 镜像屏 Extend Screen 扩展屏 Vice Screen 其他屏 N/A N/A Widget KDS 系统投屏 System Screen Projection 系统投屏 FirstOutput: 第一屏幕: First Screen 第一屏 Clone Screen 镜像屏 Extend Screen 扩展屏 Vice Screen 其他屏 kylin-display-switch/kds/res/zh_CN.qm0000644000175000017500000000145114100733566016506 0ustar fengfengV>8r*rs `O0 `Oi\P\O Clone Screen KDSWidgetbi\U\O Extend Screen KDSWidget{,N\O First Screen KDSWidget {,N\O^U FirstOutput: KDSWidgetN/AN/A KDSWidget|~b\OSystem Screen Projection KDSWidgetQvN\O Vice Screen KDSWidget\P\O Clone ScreenWidgetbi\U\O Extend ScreenWidget{,N\O First ScreenWidget {,N\O^U FirstOutput:Widget|~b\OKDSWidget|~b\OSystem Screen ProjectionWidgetQvN\O Vice ScreenWidgetkylin-display-switch/kds/widget.ui0000644000175000017500000001457714100733566016214 0ustar fengfeng Widget 0 0 400 460 KDS 0 0 0 0 0 0 98 16777215 98 QFrame::StyledPanel QFrame::Raised 0 0 0 0 0 0 Qt::Vertical 20 40 0 0 System Screen Projection 8 Qt::Horizontal 40 20 0 0 FirstOutput: 0 0 0 0 Qt::Horizontal 40 20 Qt::Vertical QSizePolicy::Fixed 20 10 0 0 1 16777215 1 QFrame::StyledPanel QFrame::Raised QFrame::StyledPanel QFrame::Raised kylin-display-switch/kds/widget.cpp0000644000175000017500000005331214107351020016333 0ustar fengfeng/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * 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 General Public License as published by * the Free Software Foundation; either version 2 of the License, 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, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "widget.h" #include "ui_widget.h" #include #include #include #include #include #include "expendbutton.h" #define TITLEHEIGHT 90 #define OPTIONSHEIGHT 70 #define BOTTOMHEIGHT 60 #define FIRSTSCREENID 0 #define CLONESCREENID 1 #define EXTENEDSCREENID 2 #define OTHERSCREENID 3 #define ALLMODESID 4 Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui->setupUi(this); } Widget::~Widget() { delete ui; delete ukcciface; } void Widget::beginSetup(){ setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint); setAttribute(Qt::WA_TranslucentBackground, true); ukcciface = new QDBusInterface("org.ukui.ukcc.session", "/", "org.ukui.ukcc.session.interface", QDBusConnection::sessionBus()); /* 不在任务栏显示图标 */ KWindowSystem::setState(winId(), NET::SkipTaskbar | NET::SkipPager); QScreen * pScreen = QGuiApplication::screens().at(0); QPoint point = pScreen->geometry().center(); move(point.x() - width()/2, point.y() - height()/2); initData(); setupComponent(); setupConnect(); initCurrentStatus(getCurrentStatus()); QDBusConnection::systemBus().connect(QString(), \ QString(), \ "org.ukui.kds.interface", \ "signalNextOption", \ this, SLOT(nextSelectedOption())); QDBusConnection::systemBus().connect(QString(), \ QString(), \ "org.ukui.kds.interface", \ "signalLastOption", \ this, SLOT(lastSelectedOption())); QDBusConnection::systemBus().connect(QString(), \ QString(), \ "org.ukui.kds.interface", \ "signalCloseApp", \ this, SLOT(closeApp())); QDBusConnection::systemBus().connect(QString(), \ QString(), \ "org.ukui.kds.interface", \ "signalMakeClicked", \ this, SLOT(confirmCurrentOption())); QDBusConnection::systemBus().connect(QString(), \ QString(), \ "org.ukui.kds.interface", \ "signalButtonClicked", \ this, SLOT(receiveButtonClick(int,int))); } void Widget::initData(){ btnsGroup = new QButtonGroup; gtk_init(NULL, NULL); //Monitor init kScreen = mate_rr_screen_new (gdk_screen_get_default (), NULL); // kConfig = mate_rr_config_new_current (kScreen, NULL); } void Widget::setupComponent(){ ui->outputPrimaryTip->hide(); // setCurrentFirstOutputTip(); for (int i = 0; i < ALLMODESID; i++){ ExpendButton * btn = new ExpendButton(); btn->setFixedHeight(70); btnsGroup->addButton(btn, i); switch (i) { #ifdef FIRSTSCREENID case FIRSTSCREENID: btn->setSign(FIRSTSCREENID % 2); btn->setBtnText(tr("First Screen")); btn->setBtnLogo(":/img/main.png"); break; #endif #ifdef CLONESCREENID case CLONESCREENID: btn->setSign(CLONESCREENID % 2); btn->setBtnText(tr("Clone Screen")); btn->setBtnLogo(":/img/clone.png"); break; #endif #ifdef EXTENEDSCREENID case EXTENEDSCREENID: btn->setSign(EXTENEDSCREENID % 2); btn->setBtnText(tr("Extend Screen")); btn->setBtnLogo(":/img/extend.png"); break; #endif #ifdef OTHERSCREENID case OTHERSCREENID: btn->setSign(OTHERSCREENID % 2); btn->setBtnText(tr("Vice Screen")); btn->setBtnLogo(":/img/vice.png"); break; #endif default: break; } ui->btnsVerLayout->addWidget(btn); } int h = TITLEHEIGHT + OPTIONSHEIGHT * ALLMODESID + BOTTOMHEIGHT; setFixedWidth(400); setFixedHeight(h); /// QSS ui->titleFrame->setStyleSheet("QFrame#titleFrame{background: #A6000000; border: none; border-top-left-radius: 24px; border-top-right-radius: 24px;}"); ui->bottomFrame->setStyleSheet("QFrame#bottomFrame{background: #A6000000; border: none; border-bottom-left-radius: 24px; border-bottom-right-radius: 24px;}"); ui->splitFrame->setStyleSheet("QFrame#splitFrame{background: #99000000; border: none;}"); ui->titleLabel->setStyleSheet("QLabel{color: #FFFFFF; font-size: 24px;}"); ui->outputPrimaryTip->setStyleSheet("QLabel{color: #60FFFFFF; font-size: 18px;}"); ui->outputName->setStyleSheet("QLabel{color: #60FFFFFF; font-size: 18px;}"); ui->outputDisplayName->setStyleSheet("QLabel{color: #60FFFFFF; font-size: 18px;}"); } void Widget::setupConnect(){ connect(btnsGroup, static_cast(&QButtonGroup::buttonClicked), this, [=](int id){ /* 获取旧选项 */ for (QAbstractButton * button : btnsGroup->buttons()){ ExpendButton * btn = dynamic_cast(button); // qDebug() << "old index: " << btn->getBtnChecked(); int index = btnsGroup->id(button); if (index == id && btn->getBtnChecked()){ goto closeapp; } } MateRRConfig * settingConfig; switch (id) { #ifdef FIRSTSCREENID case FIRSTSCREENID: settingConfig = makePrimarySetup(); initCurrentStatus(FIRSTSCREENID); break; #endif #ifdef CLONESCREENID case CLONESCREENID: settingConfig = makeCloneSetup(); initCurrentStatus(CLONESCREENID); break; #endif #ifdef EXTENEDSCREENID case EXTENEDSCREENID: settingConfig = makeXineramaSetup(); initCurrentStatus(EXTENEDSCREENID); break; #endif #ifdef OTHERSCREENID case OTHERSCREENID: settingConfig = makeOtherSetup(); initCurrentStatus(OTHERSCREENID); break; #endif default: break; } if (id >= 0 && id < ALLMODESID){ guint32 timestamp, serverTimestamp; gboolean success; GError * error; error = NULL; if (!settingConfig || !mate_rr_config_applicable(settingConfig, kScreen, &error)){ if (error) g_error_free (error); goto closeapp; } mate_rr_screen_get_timestamps(kScreen, NULL, &serverTimestamp); // if (timestamp < serverTimestamp) // timestamp = serverTimestamp; error = NULL; success = mate_rr_config_apply_with_time(settingConfig, kScreen, serverTimestamp, &error); if (!success) { qDebug() << "Could not switch to the following configuration: " << error->message; g_error_free (error); } closeapp: close(); } }); } int Widget::getCurrentStatus(){ MateRRConfig * current = mate_rr_config_new_current(kScreen, NULL); int status; if (mate_rr_config_get_clone(current)){ #ifdef CLONESCREENID g_object_unref(current); current = NULL; return CLONESCREENID; #endif } else { bool firstOutputActive = true; QList actives; char * firstName = _findFirstOutput(current); MateRROutputInfo ** outputs = mate_rr_config_get_outputs(current); for (int i = 0; outputs[i] != NULL; i++){ MateRROutputInfo * info = outputs[i]; if (mate_rr_output_info_is_connected(info)){ char * pName = mate_rr_output_info_get_name(info); if (!mate_rr_output_info_is_active(info)){ actives.append(false); if (strcmp(firstName, pName) == 0){ firstOutputActive = false; } } else { actives.append(true); } } } if (actives.length() < 2){ #ifdef FIRSTSCREENID g_object_unref(current); current = NULL; return FIRSTSCREENID; #endif } int acs = 0, disacs = 0; for (bool b : actives){ b ? acs++ : disacs++; } if (acs == actives.length()){ #ifdef EXTENEDSCREENID g_object_unref(current); current = NULL; return EXTENEDSCREENID; #endif } else { if (firstOutputActive){ #ifdef FIRSTSCREENID g_object_unref(current); current = NULL; return FIRSTSCREENID; #endif } else { #ifdef OTHERSCREENID g_object_unref(current); current = NULL; return OTHERSCREENID; #endif } } } } void Widget::initCurrentStatus(int id){ //set all no checked for (QAbstractButton * button : btnsGroup->buttons()){ ExpendButton * btn = dynamic_cast(button); btn->setBtnChecked(false); if (id == btnsGroup->id(button)){ btn->setBtnChecked(true); btn->setChecked(true); } } // status == -1 if (id == -1){ ExpendButton * btn1 = dynamic_cast(btnsGroup->button(0)); // btn1->setBtnChecked(true); btn1->setChecked(true); } } void Widget::setCurrentFirstOutputTip(){ char * pName; char * pDisplayName; char * firstName; MateRRConfig * config = mate_rr_config_new_current(kScreen, NULL); MateRROutputInfo ** outputs = mate_rr_config_get_outputs (config); firstName = _findFirstOutput(config); for (int i = 0; outputs[i] != NULL; i++){ MateRROutputInfo * info = outputs[i]; if (mate_rr_output_info_is_connected(info)){ pName = mate_rr_output_info_get_name(info); pDisplayName = mate_rr_output_info_get_display_name(info); if (strcmp(firstName, pName) == 0){ ui->outputName->setText(QString(pName)); ui->outputDisplayName->setText(""/*QString(pDisplayName)*/); } } } } void Widget::nextSelectedOption(){ int current = btnsGroup->checkedId(); int next; /* no button checked */ // if (current == -1) // ; next = current == ALLMODESID - 1 ? 0 : current + 1; ExpendButton * btn = dynamic_cast(btnsGroup->button(next)); btn->setChecked(true); } void Widget::lastSelectedOption(){ int current = btnsGroup->checkedId(); int last; /* no button checked */ if (current == -1) current = ALLMODESID; last = current == 0 ? ALLMODESID - 1 : current - 1; ExpendButton * btn = dynamic_cast(btnsGroup->button(last)); btn->setChecked(true); } void Widget::confirmCurrentOption(){ int current = btnsGroup->checkedId(); if (current == -1) return; ExpendButton * btn = dynamic_cast(btnsGroup->button(current)); // btn->click(); btn->animateClick(); } void Widget::closeApp(){ close(); } MateRRConfig * Widget::makeCloneSetup() { ukcciface->call("setScreenMode", "copy"); MateRRConfig * current; MateRROutputInfo ** outputs; int width, height; //获取克隆屏最佳分辨率 _getCloneSize(&width, &height); current = mate_rr_config_new_current(kScreen, NULL); outputs = mate_rr_config_get_outputs(current); mate_rr_config_set_clone(current, TRUE); for (int i = 0; outputs[i] != NULL; i++){ MateRROutputInfo *info = outputs[i]; mate_rr_output_info_set_active (info, FALSE); if (mate_rr_output_info_is_connected(info)){ MateRROutput * output = mate_rr_screen_get_output_by_name(kScreen, mate_rr_output_info_get_name(info)); MateRRMode ** modes = mate_rr_output_list_modes(output); int bestRate = 0; for (int j = 0; modes[j] != NULL; j++){ MateRRMode * mode = modes[j]; int w, h; w = mate_rr_mode_get_width(mode); h = mate_rr_mode_get_height(mode); if (w == width && h == height) { int r = mate_rr_mode_get_freq(mode); if (r > bestRate) bestRate = r; } } if (bestRate > 0){ mate_rr_output_info_set_active(info, TRUE); mate_rr_output_info_set_rotation(info, MATE_RR_ROTATION_0); mate_rr_output_info_set_refresh_rate(info, bestRate); mate_rr_output_info_set_geometry(info, 0, 0, width, height); } } } if (_configIsAllOff(current)){ g_object_unref(current); current = NULL; } return current; } MateRRConfig * Widget::makePrimarySetup(){ ukcciface->call("setScreenMode", "first"); char * firstName; /* Turn on the first screen, disable everything else */ MateRRConfig * current = mate_rr_config_new_current(kScreen, NULL); MateRROutputInfo ** outputs = mate_rr_config_get_outputs(current); mate_rr_config_set_clone(current, FALSE); /* found first output */ firstName = _findFirstOutput(current); for (int i = 0; outputs[i] != NULL; i++){ MateRROutputInfo * info = outputs[i]; char * pName = mate_rr_output_info_get_name(info); if (strcmp(firstName, pName) == 0){ if (!_turnonOutput(info, 0, 0)){ break; } } else { mate_rr_output_info_set_active (info, FALSE); } } _setNewPrimaryOutput(current); if (_configIsAllOff(current)){ g_object_unref(current); current = NULL; } return current; } MateRRConfig * Widget::makeOtherSetup(){ ukcciface->call("setScreenMode", "second"); char * firstName; /* Turn off primary output, and make all external monitors clone from (0, 0) */ MateRRConfig * current = mate_rr_config_new_current(kScreen, NULL); MateRROutputInfo ** outputs = mate_rr_config_get_outputs (current); mate_rr_config_set_clone(current, FALSE); firstName = _findFirstOutput(current); for (int i = 0; outputs[i] != NULL; i++){ MateRROutputInfo * info = outputs[i]; char * pName = mate_rr_output_info_get_name(info); if (strcmp(firstName, pName) == 0){ mate_rr_output_info_set_active(info, FALSE); } else { if (mate_rr_output_info_is_connected(info)){ _turnonOutput(info, 0, 0); } } } _setNewPrimaryOutput(current); if (_configIsAllOff(current)){ g_object_unref(current); current = NULL; } return current; } MateRRConfig * Widget::makeXineramaSetup(){ ukcciface->call("setScreenMode", "expand"); /* Turn on everything that has a preferred mode, and position it from left to right */ MateRRConfig * current = mate_rr_config_new_current(kScreen, NULL); MateRROutputInfo ** outputs = mate_rr_config_get_outputs (current); int x; mate_rr_config_set_clone(current, FALSE); //found primary output _setNewPrimaryOutput(current); x = 0; for (int i = 0; outputs[i] != NULL; i++){ MateRROutputInfo * info = outputs[i]; if (mate_rr_output_info_get_primary(info)){ x = _turnonGetRightmostOffset(info, x); } } for (int i = 0; outputs[i] != NULL; i++){ MateRROutputInfo * info = outputs[i]; if (mate_rr_output_info_is_connected(info) && !mate_rr_output_info_get_primary(info)){ x = _turnonGetRightmostOffset(info, x); } } if (_configIsAllOff(current)){ g_object_unref(current); current = NULL; } return current; } bool Widget::_configIsAllOff(MateRRConfig *config){ MateRROutputInfo ** outputs; outputs = mate_rr_config_get_outputs (config); for (int j = 0; outputs[j] != NULL; j++) { if (mate_rr_output_info_is_active (outputs[j])) { return false; } } return true; } bool Widget::_getCloneSize(int *width, int *height) { MateRRMode **modes = mate_rr_screen_list_clone_modes (kScreen); int bestWidth, bestHeight; bestWidth = 0; bestHeight = 0; for (int i = 0; modes[i] != NULL; ++i){ int w, h; MateRRMode *mode = modes[i]; w = mate_rr_mode_get_width (mode); h = mate_rr_mode_get_height (mode); if (w * h > bestWidth * bestHeight){ bestWidth = w; bestHeight = h; } } if (bestWidth > 0 && bestHeight > 0){ if (width) *width = bestWidth; if (height) *height = bestHeight; return true; } return false; } bool Widget::_isLaptop(MateRROutputInfo * info){ /* 返回该输出是否是笔记本屏幕 */ MateRROutput * output; output = mate_rr_screen_get_output_by_name (kScreen, mate_rr_output_info_get_name (info)); return mate_rr_output_is_laptop(output); } bool Widget::_setNewPrimaryOutput(MateRRConfig *config){ MateRROutputInfo ** outputs = mate_rr_config_get_outputs (config); for (int i = 0; outputs[i] != NULL; i++){ MateRROutputInfo * info = outputs[i]; if (mate_rr_output_info_is_active(info)){ if (mate_rr_output_info_get_primary(info)){ return true; } } } //top left output is primary mate_rr_config_ensure_primary(config); return true; } char *Widget::_findFirstOutput(MateRRConfig *config){ int firstid = -1; char * firstname; MateRROutputInfo ** outputs = mate_rr_config_get_outputs (config); for (int i = 0; outputs[i] != NULL; i++){ MateRROutputInfo * info = outputs[i]; if (mate_rr_output_info_is_connected(info)){ MateRROutput * output = mate_rr_screen_get_output_by_name(kScreen, mate_rr_output_info_get_name(info)); int currentid = mate_rr_output_get_id(output); if (firstid == -1){ firstid = currentid; firstname = mate_rr_output_info_get_name(info); continue; } if (firstid > currentid){ firstid = currentid; firstname = mate_rr_output_info_get_name(info); } } } return firstname; } bool Widget::_turnonOutput(MateRROutputInfo *info, int x, int y){ MateRROutput * output = mate_rr_screen_get_output_by_name (kScreen, mate_rr_output_info_get_name (info)); MateRRMode * mode = _findBestMode(output); if (mode) { mate_rr_output_info_set_active (info, TRUE); mate_rr_output_info_set_geometry (info, x, y, mate_rr_mode_get_width (mode), mate_rr_mode_get_height (mode)); mate_rr_output_info_set_rotation (info, MATE_RR_ROTATION_0); mate_rr_output_info_set_refresh_rate (info, mate_rr_mode_get_freq (mode)); return true; } return false; } MateRRMode * Widget::_findBestMode(MateRROutput *output){ MateRRMode * preferred; MateRRMode ** modes; MateRRMode * bestMode; int bestSize; int bestWidth, bestHeight, bestRate; preferred = mate_rr_output_get_preferred_mode(output); if (preferred) return preferred; modes = mate_rr_output_list_modes(output); if (!modes) return NULL; bestSize = bestWidth = bestHeight = bestRate = 0; bestMode = NULL; for (int i = 0; modes[i] != NULL; i++){ int w, h, r; int size; w = mate_rr_mode_get_width (modes[i]); h = mate_rr_mode_get_height (modes[i]); r = mate_rr_mode_get_freq (modes[i]); size = w * h; if (size > bestSize){ bestSize = size; bestWidth = w; bestHeight = h; bestRate = r; bestMode = modes[i]; } else if (size == bestSize){ if (r > bestRate){ bestRate = r; bestMode = modes[i]; } } } return bestMode; } int Widget::_turnonGetRightmostOffset(MateRROutputInfo *info, int x){ if (_turnonOutput(info, x, 0)){ int width; mate_rr_output_info_get_geometry (info, NULL, NULL, &width, NULL); x += width; } return x; } void Widget::msgReceiveAnotherOne(const QString &msg){ // qDebug() << "another one " << msg; nextSelectedOption(); } void Widget::receiveButtonClick(int x, int y){ // qDebug() << "receive button press " << x << y; if (!this->geometry().contains(x, y)){ close(); } } kylin-display-switch/kds/kdswidget.ui0000644000175000017500000001375414100733566016712 0ustar fengfeng KDSWidget 0 0 535 512 Form 0 0 0 0 0 0 98 16777215 98 QFrame::StyledPanel QFrame::Raised 3 0 0 0 0 Qt::Vertical 20 40 0 0 System Screen Projection 3 Qt::Horizontal 40 20 0 0 FirstOutput: 0 0 0 0 Qt::Horizontal 40 20 Qt::Vertical 20 40 0 0 1 16777215 1 QFrame::StyledPanel QFrame::Raised 0 30 QFrame::StyledPanel QFrame::Raised kylin-display-switch/kds/kdswidget.h0000644000175000017500000000333714107351020016504 0ustar fengfeng#ifndef KDSWIDGET_H #define KDSWIDGET_H #include #include #include #include #include #include #include #include namespace Ui { class KDSWidget; } class KDSWidget : public QWidget { Q_OBJECT public: explicit KDSWidget(QWidget *parent = nullptr); ~KDSWidget(); void beginSetupKF5(); QPoint getWinPos(); QString getCurrentPrimaryScreenName(); int getCurrentScale(); void setupComponent(); void setupConnect(); int getCurrentStatus(); void setCurrentUIStatus(int id); void setCurrentFirstOutputTip(); void syncPrimaryScreenData(QString pName); public: void setConfig(const KScreen::ConfigPtr &config); KScreen::ConfigPtr currentConfig() const; void setCloneModeSetup(); void setExtendModeSetup(); void setFirstModeSetup(); void setOtherModeSetup(); void setLeftExtendModeSetup(); private: QString findFirstOutput(); QSize findBestCloneSize(); bool turnonSpecifiedOutput(const KScreen::OutputPtr &output, int x, int y); int turnonAndGetRightmostOffset(const KScreen::OutputPtr &output, int x); private: Ui::KDSWidget *ui; QButtonGroup * btnsGroup; private: KScreen::ConfigPtr mConfig = nullptr; public slots: void msgReceiveAnotherOne(const QString &msg); private slots: void nextSelectedOption(); void lastSelectedOption(); void confirmCurrentOption(); void receiveButtonClick(int x, int y); void closeApp(); Q_SIGNALS: void tellBtnClicked(int id); }; #endif // KDSWIDGET_H kylin-display-switch/conf/0000755000175000017500000000000014107351027014513 5ustar fengfengkylin-display-switch/conf/org.ukui.kds.gschema.xml0000644000175000017500000000202614107351020021157 0ustar fengfeng true show keyboard tip show keyboard tip or not. eg. Caps Lock. Num Lock true microphone enable or not current microphone enable or not false microphone enable or not current microphone enable or not ['0'] microphone enable or not current microphone enable or not kylin-display-switch/.gitattributes0000644000175000017500000000003414100736260016455 0ustar fengfengdebian/changelog merge=ours