diff --git a/core/backends/devicelink.h b/core/backends/devicelink.h index b56389724..f8d652175 100644 --- a/core/backends/devicelink.h +++ b/core/backends/devicelink.h @@ -36,6 +36,7 @@ class DeviceLink public: DeviceLink(const QString& deviceId, LinkProvider* parent); + virtual ~DeviceLink() { }; const QString& deviceId() { return mDeviceId; } LinkProvider* provider() { return mLinkProvider; } diff --git a/core/backends/lan/landevicelink.cpp b/core/backends/lan/landevicelink.cpp index bdedbeabe..09870579b 100644 --- a/core/backends/lan/landevicelink.cpp +++ b/core/backends/lan/landevicelink.cpp @@ -31,16 +31,24 @@ #include "downloadjob.h" #include "socketlinereader.h" -LanDeviceLink::LanDeviceLink(const QString& d, LinkProvider* a, QTcpSocket* socket) - : DeviceLink(d, a) - , mSocketLineReader(new SocketLineReader(socket, a)) +LanDeviceLink::LanDeviceLink(const QString& deviceId, LinkProvider* parent, QTcpSocket* socket) + : DeviceLink(deviceId, parent) + , mSocketLineReader(new SocketLineReader(socket)) { - connect(mSocketLineReader, SIGNAL(disconnected()), - this, SLOT(deleteLater())); connect(mSocketLineReader, SIGNAL(readyRead()), this, SLOT(dataReceived())); + + //We take ownership of the socket. + //When the link provider distroys us, + //the socket (and the reader) will be + //destroyed as well + connect(socket, SIGNAL(disconnected()), + this, SLOT(deleteLater())); + mSocketLineReader->setParent(this); + socket->setParent(this); } + bool LanDeviceLink::sendPackageEncrypted(QCA::PublicKey& key, NetworkPackage& np) { if (np.hasPayload()) { @@ -55,7 +63,7 @@ bool LanDeviceLink::sendPackageEncrypted(QCA::PublicKey& key, NetworkPackage& np //TODO: Actually detect if a package is received or not, now we keep TCP //"ESTABLISHED" connections that look legit (return true when we use them), - //but that are actually broken + //but that are actually broken (until keepalive detects that they are down). return (written != -1); } @@ -68,9 +76,6 @@ bool LanDeviceLink::sendPackage(NetworkPackage& np) } int written = mSocketLineReader->write(np.serialize()); - //TODO: Actually detect if a package is received or not, now we keep TCP - //"ESTABLISHED" connections that look legit (return true when we use them), - //but that are actually broken return (written != -1); } diff --git a/core/backends/lan/landevicelink.h b/core/backends/lan/landevicelink.h index 2bc55f69c..7d31881fb 100644 --- a/core/backends/lan/landevicelink.h +++ b/core/backends/lan/landevicelink.h @@ -35,7 +35,7 @@ class LanDeviceLink Q_OBJECT public: - LanDeviceLink(const QString& d, LinkProvider* a, QTcpSocket* socket); + LanDeviceLink(const QString& deviceId, LinkProvider* parent, QTcpSocket* socket); bool sendPackage(NetworkPackage& np); bool sendPackageEncrypted(QCA::PublicKey& key, NetworkPackage& np); diff --git a/core/backends/lan/lanlinkprovider.cpp b/core/backends/lan/lanlinkprovider.cpp index 6524076c2..fb819d160 100644 --- a/core/backends/lan/lanlinkprovider.cpp +++ b/core/backends/lan/lanlinkprovider.cpp @@ -38,27 +38,26 @@ void LanLinkProvider::configureSocket(QTcpSocket* socket) { int fd = socket->socketDescriptor(); - char enableKeepAlive = 1; - setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &enableKeepAlive, sizeof(enableKeepAlive)); -#ifdef TCP_KEEPIDLE - int maxIdle = 60; /* seconds */ - setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &maxIdle, sizeof(maxIdle)); -#endif + socket->setSocketOption(QAbstractSocket::KeepAliveOption, QVariant(1)); -#ifdef TCP_KEEPCNT - if (getprotobyname("TCP")) { - int count = 3; // send up to 3 keepalive packets out, then disconnect if no response - setsockopt(fd, getprotobyname("TCP")->p_proto, TCP_KEEPCNT, &count, sizeof(count)); - } -#endif + #ifdef TCP_KEEPIDLE + // time to start sending keepalive packets (seconds) + int maxIdle = 10; + setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &maxIdle, sizeof(maxIdle)); + #endif -#ifdef TCP_KEEPINTVL - if (getprotobyname("TCP")) { - int interval = 5; // send a keepalive packet out every 2 seconds (after the 5 second idle period) - setsockopt(fd, getprotobyname("TCP")->p_proto, TCP_KEEPINTVL, &interval, sizeof(interval)); - } -#endif + #ifdef TCP_KEEPINTVL + // interval between keepalive packets after the initial period (seconds) + int interval = 5; + setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &interval, sizeof(interval)); + #endif + + #ifdef TCP_KEEPCNT + // number of missed keepalive packets before disconnecting + int count = 3; + setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &count, sizeof(count)); + #endif } @@ -104,44 +103,39 @@ void LanLinkProvider::onNetworkChange(QNetworkSession::State state) NetworkPackage::createIdentityPackage(&np); np.set("tcpPort", mTcpPort); mUdpSocket.writeDatagram(np.serialize(), QHostAddress("255.255.255.255"), port); - - //TODO: Ping active connections to see if they are still reachable } -//I'm the existing device, a new device is kindly introducing itself (I will create a TcpSocket) +//I'm the existing device, a new device is kindly introducing itself. +//I will create a TcpSocket and try to connect. This can result in either connected() or connectError(). void LanLinkProvider::newUdpConnection() { while (mUdpServer->hasPendingDatagrams()) { QByteArray datagram; datagram.resize(mUdpServer->pendingDatagramSize()); QHostAddress sender; - quint16 senderPort; - - mUdpServer->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort); - - NetworkPackage* np = new NetworkPackage(""); - bool success = NetworkPackage::unserialize(datagram,np); mUdpServer->readDatagram(datagram.data(), datagram.size(), &sender); NetworkPackage* receivedPackage = new NetworkPackage(""); - success = NetworkPackage::unserialize(datagram, receivedPackage); + bool success = NetworkPackage::unserialize(datagram, receivedPackage); if (!success || receivedPackage->type() != PACKAGE_TYPE_IDENTITY) { delete receivedPackage; + return; } KSharedConfigPtr config = KSharedConfig::openConfig("kdeconnectrc"); const QString myId = config->group("myself").readEntry("id",""); - //kDebug(debugArea()) << "Ignoring my own broadcast"; if (receivedPackage->get("deviceId") == myId) { + //kDebug(debugArea()) << "Ignoring my own broadcast"; + delete receivedPackage; return; } int tcpPort = receivedPackage->get("tcpPort", port); - //kDebug(debugArea()) << "Received Udp presentation from" << sender << "asking for a tcp connection on port " << tcpPort; + //kDebug(debugArea()) << "Received Udp identity package from" << sender << " asking for a tcp connection on port " << tcpPort; QTcpSocket* socket = new QTcpSocket(this); receivedIdentityPackages[socket].np = receivedPackage; @@ -155,26 +149,26 @@ void LanLinkProvider::newUdpConnection() void LanLinkProvider::connectError() { QTcpSocket* socket = qobject_cast(sender()); - - disconnect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(connectError())); + if (!socket) return; disconnect(socket, SIGNAL(connected()), this, SLOT(connected())); + disconnect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(connectError())); NetworkPackage np(""); NetworkPackage::createIdentityPackage(&np); np.set("tcpPort", mTcpPort); mUdpSocket.writeDatagram(np.serialize(), receivedIdentityPackages[socket].sender, port); + //The socket we created didn't work, and we didn't manage + //to create a LanDeviceLink from it, deleting everything. delete receivedIdentityPackages[socket].np; receivedIdentityPackages.remove(socket); + delete socket; } void LanLinkProvider::connected() { - QTcpSocket* socket = qobject_cast(sender()); - if (!socket) return; - disconnect(socket, SIGNAL(connected()), this, SLOT(connected())); disconnect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(connectError())); @@ -188,7 +182,6 @@ void LanLinkProvider::connected() NetworkPackage np2(""); NetworkPackage::createIdentityPackage(&np2); - bool success = deviceLink->sendPackage(np2); if (success) { @@ -213,44 +206,42 @@ void LanLinkProvider::connected() mLinks[deviceId] = deviceLink; } else { - //I think this will never happen + //I think this will never happen, but if it happens the deviceLink + //(or the socket that is now inside it) might not be valid. Delete them. + delete deviceLink; qCDebug(KDECONNECT_CORE) << "Fallback (2), try reverse connection"; mUdpSocket.writeDatagram(np2.serialize(), receivedIdentityPackages[socket].sender, port); - delete deviceLink; } - receivedIdentityPackages.remove(socket); - delete receivedPackage; - + receivedIdentityPackages.remove(socket); + //We don't delete the socket because now it's owned by the LanDeviceLink } -//I'm the new device and this is the answer to my UDP introduction (no data received yet) +//I'm the new device and this is the answer to my UDP identity package (no data received yet) void LanLinkProvider::newConnection() { //qCDebug(KDECONNECT_CORE) << "LanLinkProvider newConnection"; while(mTcpServer->hasPendingConnections()) { QTcpSocket* socket = mTcpServer->nextPendingConnection(); - socket->setSocketOption(QAbstractSocket::KeepAliveOption, 1); + configureSocket(socket); + //This socket is still managed by us (and child of the QTcpServer), if + //it disconnects before we manage to pass it to a LanDeviceLink, it's + //our responsability to delete it. We do so with this connection. + connect(socket, SIGNAL(disconnected()), + socket, SLOT(deleteLater())); + connect(socket, SIGNAL(readyRead()), + this, SLOT(dataReceived())); - connect(socket, SIGNAL(readyRead()), this, SLOT(dataReceived())); } -/* - NetworkPackage np(PACKAGE_TYPE_IDENTITY); - NetworkPackage::createIdentityPackage(&np); - int written = socket->write(np.serialize()); - - qCDebug(KDECONNECT_CORE) << "LanLinkProvider sent package." << written << " bytes written, waiting for reply"; -*/ } -//I'm the new device and this is the answer to my UDP introduction (data received) +//I'm the new device and this is the answer to my UDP identity package (data received) void LanLinkProvider::dataReceived() { QTcpSocket* socket = qobject_cast(sender()); - configureSocket(socket); const QByteArray data = socket->readLine(); @@ -258,17 +249,23 @@ void LanLinkProvider::dataReceived() NetworkPackage np(""); bool success = NetworkPackage::unserialize(data, &np); + //kDebug(debugArea()) << "LanLinkProvider received reply:" << data; if (!success || np.type() != PACKAGE_TYPE_IDENTITY) { qCDebug(KDECONNECT_CORE) << "LanLinkProvider/newConnection: Not an identification package (wuh?)"; return; } - const QString& deviceId = np.get("deviceId"); - LanDeviceLink* deviceLink = new LanDeviceLink(deviceId, this, socket); - //qCDebug(KDECONNECT_CORE) << "Handshaking done (i'm the new device)"; + //This socket will now be owned by the LanDeviceLink, forget about it + disconnect(socket, SIGNAL(readyRead()), + this, SLOT(dataReceived())); + disconnect(socket, SIGNAL(disconnected()), + socket, SLOT(deleteLater())); + + const QString& deviceId = np.get("deviceId"); + LanDeviceLink* deviceLink = new LanDeviceLink(deviceId, this, socket); connect(deviceLink, SIGNAL(destroyed(QObject*)), this, SLOT(deviceLinkDestroyed(QObject*))); @@ -285,7 +282,6 @@ void LanLinkProvider::dataReceived() mLinks[deviceId] = deviceLink; - disconnect(socket,SIGNAL(readyRead()),this,SLOT(dataReceived())); } void LanLinkProvider::deviceLinkDestroyed(QObject* destroyedDeviceLink) diff --git a/core/backends/lan/socketlinereader.cpp b/core/backends/lan/socketlinereader.cpp index 26e9fd2c2..4fdaf1408 100644 --- a/core/backends/lan/socketlinereader.cpp +++ b/core/backends/lan/socketlinereader.cpp @@ -25,13 +25,8 @@ SocketLineReader::SocketLineReader(QTcpSocket* socket, QObject* parent) : QObject(parent) , mSocket(socket) { - - connect(mSocket, SIGNAL(disconnected()), - this, SIGNAL(disconnected())); - connect(mSocket, SIGNAL(readyRead()), this, SLOT(dataReceived())); - } void SocketLineReader::dataReceived() diff --git a/core/backends/lan/socketlinereader.h b/core/backends/lan/socketlinereader.h index d29560763..df11c3ee3 100644 --- a/core/backends/lan/socketlinereader.h +++ b/core/backends/lan/socketlinereader.h @@ -45,7 +45,6 @@ public: qint64 bytesAvailable() { return mPackages.size(); } Q_SIGNALS: - void disconnected(); void readyRead(); private Q_SLOTS: diff --git a/core/backends/linkprovider.h b/core/backends/linkprovider.h index bb89d1c42..00805c1b5 100644 --- a/core/backends/linkprovider.h +++ b/core/backends/linkprovider.h @@ -52,7 +52,7 @@ public Q_SLOTS: virtual void onNetworkChange(QNetworkSession::State state) = 0; Q_SIGNALS: - //NOTE: The provider will to destroy the DeviceLink when it's no longer accessible, + //NOTE: The provider will destroy the DeviceLink when it's no longer accessible, // and every user should listen to the destroyed signal to remove its references. // That's the reason because there is no "onConnectionLost". void onConnectionReceived(const NetworkPackage& identityPackage, DeviceLink*) const; diff --git a/core/networkpackagetypes.h b/core/networkpackagetypes.h index 553faba5d..6aa24a297 100644 --- a/core/networkpackagetypes.h +++ b/core/networkpackagetypes.h @@ -24,6 +24,5 @@ #define PACKAGE_TYPE_IDENTITY QLatin1String("kdeconnect.identity") #define PACKAGE_TYPE_PAIR QLatin1String("kdeconnect.pair") #define PACKAGE_TYPE_ENCRYPTED QLatin1String("kdeconnect.encrypted") -#define PACKAGE_TYPE_PING QLatin1String("kdeconnect.ping") #endif // NETWORKPACKAGETYPES_H diff --git a/fileitemactionplugin/kdeconnectsendfile.desktop b/fileitemactionplugin/kdeconnectsendfile.desktop index ac0d01b26..08268feaf 100644 --- a/fileitemactionplugin/kdeconnectsendfile.desktop +++ b/fileitemactionplugin/kdeconnectsendfile.desktop @@ -9,6 +9,7 @@ Name[es]=Enviar archivo usando el servicio KDE Connect Name[fi]=Lähetä tiedosto KDE-Connect-palvelulla Name[fr]=Envoyer un fichier via le service KDE Connect Name[hu]=Fájl küldése a KDE csatlakozás szolgáltatáson keresztül +Name[ko]=KDE Connect 서비스로 파일 보내기 Name[nl]=Bestand via de service KDE Connect versturen Name[pl]=Wyślij plik przez usługę KDE Connect Name[pt]=Enviar um ficheiro pelo serviço KDE Connect @@ -27,6 +28,7 @@ X-KDE-Submenu[es]=Conectar X-KDE-Submenu[fi]=Yhdistä X-KDE-Submenu[fr]=Connecter X-KDE-Submenu[hu]=Csatlakozás +X-KDE-Submenu[ko]=연결 X-KDE-Submenu[nl]=Verbinden X-KDE-Submenu[pl]=Połącz X-KDE-Submenu[pt]=Ligar diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 9004c0a0a..083c087a2 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -12,6 +12,7 @@ add_subdirectory(mousepad) add_subdirectory(share) add_subdirectory(notifications) add_subdirectory(sftp) +add_subdirectory(screensaver-inhibit) #FIXME: If we split notifications in several files, they won't appear in the same group in the Notifications KCM install(FILES kdeconnect.notifyrc DESTINATION ${KNOTIFYRC_INSTALL_DIR}) diff --git a/plugins/README.txt b/plugins/README.txt new file mode 100644 index 000000000..d88ea52a1 --- /dev/null +++ b/plugins/README.txt @@ -0,0 +1,42 @@ +Writting a plugin for KDE Connect +================================= + +For the desktop client (this project): +-------------------------------------- + +1. Enter the "plugins" directory. +2. Copy the "ping" under a different name ("findmyphone" in this example). +3. Add "add_subdirectory(findmyphone)" to CMakeLists.txt after the others "add_subdirectory". +1. Enter the new "findmyphone" directory. +5. Edit CMakeLists.txt by replacing "ping" with "findmyphone". +6. Rename other files in this directory by replacing "ping" with "findmyphone" +7. Write a description of your plugin into "README" +8. Edit findmyphoneplugin.cpp and findmyphoneplugin.h. + A. Change license header. + B. Replace (case sensitive) "ping" with "findmyphone", "PingPlugin" with "FindMyPhonePlugin" and "PING" with "FINDMYPHONE". +9. Edit kdeconnect_findmyphone.desktop file: + A. Replace "ping" with "findmyphone". + B. Change name, description, icon, author, email, version, website, license info. + C. Remove all the translations + D. Set X-KDEConnect-SupportedPackageType and X-KDEConnect-OutgoingPackageType to the package type your plugin will receive + and send, respectively. In this example this is "kdeconnect.findmyphone". Make sure that this matches what is defined in + the findmyplugin.h file (in the line "#define PACKAGE_TYPE_..."), and also in Android. +10. Now you have an empty skeleton to implement your new plugin logic. + +For Android (project kdeconnect-android): +----------------------------------------- + +1. Change directory to src/org/kde/kdeconnect/Plugins. +2. Copy "PingPlugin" under a different name ("FindMyPhonePlugin" in this example). +1. Enter the new "FindMyPhonePlugin" directory. +4. Rename "PingPlugin.java" to "FindMyPhonePlugin.java" +5. Edit it. Replace (case sensitive) "Ping" with "FindMyPhone", "ping" with "findmyphone", "PING" with "FINDMYPHONE" + and "plugin_ping" with "plugin_findmyphone". +6. Open res/values/strings.xml. Find and copy the lines "pref_plugin_ping_desc" and "pref_plugin_ping" replacing "ping" + with "findmyphone" and edit the plugin name and description between ). +7. Open src/org/kde/kdeconnect/Plugins/PluginFactory.java. + A. Copy "import … PingPlugin" line with replacing "PingPlugin" with "FindMyPhonePlugin". + B. Copy "PluginFactory.registerPlugin(PingPlugin.class);" line with replacing "PingPlugin" with "FindMyPhonePlugin". +8. Open src/org/kde/kdeconnect/NetworkPackage.java. Copy a "public final static String PACKAGE_TYPE_PING = …" line + replacing "PING" with the package type you will be using (should match the desktop client). +9. Now you have an empty skeleton to implement your new plugin logic. diff --git a/plugins/kdeconnect.notifyrc b/plugins/kdeconnect.notifyrc index 34b35e02c..ab20ab169 100644 --- a/plugins/kdeconnect.notifyrc +++ b/plugins/kdeconnect.notifyrc @@ -55,12 +55,15 @@ Name[ca]=Sol·licitud d'aparellament Name[cs]=Požadavek na párování Name[de]=Verbindungsanfrage Name[es]=Petición de vinculación -Name[fi]=Parituspyyntö +Name[fi]=Paripyyntö +Name[hu]=Párosítási kérés +Name[ko]=페어링 요청 Name[nl]=Verzoek om een paar te maken Name[pl]=Żądanie parowania Name[pt]=Pedido de Emparelhamento Name[pt_BR]=Solicitação de emparelhamento Name[sk]=Požiadavka na spárovanie +Name[sv]=Begäran om ihopparning Name[uk]=Запит щодо пов’язування Name[x-test]=xxPairing Requestxx Comment=Pairing request received from a devices @@ -68,12 +71,15 @@ Comment[ca]=Les sol·licituds d'aparellament rebudes des d'un dispositiu Comment[cs]=Požadavek na párování přijat ze zařízení Comment[de]=Verbindungsanfrage von einem Gerät erhalten Comment[es]=Petición de vinculación recibida desde un dispositivo -Comment[fi]=Saatiin parituspyyntö laitteelta +Comment[fi]=Saatiin paripyyntö laitteelta +Comment[hu]=Párosítási kérés érkezett egy eszköztől +Comment[ko]=장치에서 페어링 요청을 받음 Comment[nl]=Verzoek om een paar te maken ontvangen van een apparaat Comment[pl]=Otrzymano żądanie parowania z urządzeń Comment[pt]=Pedido de emparelhamento recebido de um dispositivo Comment[pt_BR]=Solicitação de emparelhamento recebida de um dispositivo Comment[sk]=Požiadavka na spárovanie prijatá zo zariadenia +Comment[sv]=Begäran om ihopparning mottagen från en apparat Comment[uk]=Від пристрою отримано запит щодо пов’язування Comment[x-test]=xxPairing request received from a devicesxx Action=Popup @@ -291,7 +297,7 @@ Name[cs]=Ping Name[da]=Ping Name[de]=Ping Name[es]=Ping -Name[fi]=Ping +Name[fi]=Tiedustelupaketti Name[fr]=Commande « Ping » Name[hu]=Ping Name[it]=Ping @@ -315,7 +321,7 @@ Comment[cs]=Ping přijat Comment[da]=Ping modtaget Comment[de]=Ping empfangen Comment[es]=Ping recibido -Comment[fi]=Vastaanotettiin ping +Comment[fi]=Vastaanotettiin tiedustelupaketti Comment[fr]=Commande « Ping » reçue Comment[hu]=Ping érkezett Comment[it]=Hai ricevuto un ping @@ -390,12 +396,15 @@ Name[ca]=Sol·licitud d'aparellament Name[cs]=Požadavek na párování Name[de]=Verbindungsanfrage Name[es]=Petición de vinculación -Name[fi]=Parituspyyntö +Name[fi]=Paripyyntö +Name[hu]=Párosítási kérés +Name[ko]=페어링 요청 Name[nl]=Verzoek om een paar te maken Name[pl]=Żądanie parowania Name[pt]=Pedido de Emparelhamento Name[pt_BR]=Solicitação de emparelhamento Name[sk]=Požiadavka na spárovanie +Name[sv]=Begäran om ihopparning Name[uk]=Запит щодо пов’язування Name[x-test]=xxPairing Requestxx Comment=Pairing request received from a devices @@ -403,12 +412,15 @@ Comment[ca]=Les sol·licituds d'aparellament rebudes des d'un dispositiu Comment[cs]=Požadavek na párování přijat ze zařízení Comment[de]=Verbindungsanfrage von einem Gerät erhalten Comment[es]=Petición de vinculación recibida desde un dispositivo -Comment[fi]=Saatiin parituspyyntö laitteelta +Comment[fi]=Saatiin paripyyntö laitteelta +Comment[hu]=Párosítási kérés érkezett egy eszköztől +Comment[ko]=장치에서 페어링 요청을 받음 Comment[nl]=Verzoek om een paar te maken ontvangen van een apparaat Comment[pl]=Otrzymano żądanie parowania z urządzeń Comment[pt]=Pedido de emparelhamento recebido de um dispositivo Comment[pt_BR]=Solicitação de emparelhamento recebida de um dispositivo Comment[sk]=Požiadavka na spárovanie prijatá zo zariadenia +Comment[sv]=Begäran om ihopparning mottagen från en apparat Comment[uk]=Від пристрою отримано запит щодо пов’язування Comment[x-test]=xxPairing request received from a devicesxx Action=Popup diff --git a/plugins/mousepad/kdeconnect_mousepad.desktop b/plugins/mousepad/kdeconnect_mousepad.desktop index 1c3204af5..263041640 100644 --- a/plugins/mousepad/kdeconnect_mousepad.desktop +++ b/plugins/mousepad/kdeconnect_mousepad.desktop @@ -19,6 +19,7 @@ Name[es]=Cursor del ratón Name[fi]=Kosketuslevy Name[fr]=Pavé tactile Name[hu]=Érintőtábla +Name[ko]=터치패드 Name[nl]=Touchpad Name[pl]=Gładzik Name[pt]=Rato por Toque @@ -36,6 +37,7 @@ Comment[es]=Usar su teléfono como cursor del ratón Comment[fi]=Käytä puhelinta kosketuslevynä Comment[fr]=Utilisez votre téléphone comme un pavé tactile Comment[hu]=A telefon használata érintőtáblaként +Comment[ko]=내 장치를 터치패드로 사용하기 Comment[nl]=Uw telefoon gebruiken als touchpad Comment[pl]=Użyj swojego telefonu jako gładzika Comment[pt]=Usar o seu telemóvel como painel de rato diff --git a/plugins/mousepad/mousepadplugin.cpp b/plugins/mousepad/mousepadplugin.cpp index fea207856..958a288ca 100644 --- a/plugins/mousepad/mousepadplugin.cpp +++ b/plugins/mousepad/mousepadplugin.cpp @@ -52,6 +52,24 @@ int SpecialKeysMap[] = { XK_Return, // 12 XK_Delete, // 13 XK_Escape, // 14 + XK_Sys_Req, // 15 + XK_Scroll_Lock, // 16 + 0, // 17 + 0, // 18 + 0, // 19 + 0, // 20 + XK_F1, // 21 + XK_F2, // 22 + XK_F3, // 23 + XK_F4, // 24 + XK_F5, // 25 + XK_F6, // 26 + XK_F7, // 27 + XK_F8, // 28 + XK_F9, // 29 + XK_F10, // 30 + XK_F11, // 31 + XK_F12, // 32 }; template @@ -77,7 +95,9 @@ MousepadPlugin::~MousepadPlugin() bool MousepadPlugin::receivePackage(const NetworkPackage& np) { - //TODO: Split mouse/keyboard in two different plugins to avoid big if statements + //qDebug() << np.serialize(); + + //TODO: Split mouse/keyboard in two different plugins to avoid this big if statement float dx = np.get("dx", 0); float dy = np.get("dy", 0); @@ -86,11 +106,13 @@ bool MousepadPlugin::receivePackage(const NetworkPackage& np) bool isDoubleClick = np.get("doubleclick", false); bool isMiddleClick = np.get("middleclick", false); bool isRightClick = np.get("rightclick", false); + bool isSingleHold = np.get("singlehold", false); + bool isSingleRelease = np.get("singlerelease", false); bool isScroll = np.get("scroll", false); QString key = np.get("key", ""); int specialKey = np.get("specialKey", 0); - if (isSingleClick || isDoubleClick || isMiddleClick || isRightClick || isScroll || !key.isEmpty() || specialKey) { + if (isSingleClick || isDoubleClick || isMiddleClick || isRightClick || isSingleHold || isScroll || !key.isEmpty() || specialKey) { if(!m_display) { m_display = XOpenDisplay(NULL); @@ -114,7 +136,13 @@ bool MousepadPlugin::receivePackage(const NetworkPackage& np) } else if (isRightClick) { XTestFakeButtonEvent(m_display, RightMouseButton, True, 0); XTestFakeButtonEvent(m_display, RightMouseButton, False, 0); - } else if( isScroll ) { + } else if (isSingleHold){ + //For drag'n drop + XTestFakeButtonEvent(m_display, LeftMouseButton, True, 0); + } else if (isSingleRelease){ + //For drag'n drop. NEVER USED (release is done by tapping, which actually triggers a isSingleClick). Kept here for future-proofnes. + XTestFakeButtonEvent(m_display, LeftMouseButton, False, 0); + } else if (isScroll) { if (dy < 0) { XTestFakeButtonEvent(m_display, MouseWheelDown, True, 0); XTestFakeButtonEvent(m_display, MouseWheelDown, False, 0); @@ -124,6 +152,14 @@ bool MousepadPlugin::receivePackage(const NetworkPackage& np) } } else if (!key.isEmpty() || specialKey) { + bool ctrl = np.get("ctrl", false); + bool alt = np.get("alt", false); + bool shift = np.get("shift", false); + + if (ctrl) XTestFakeKeyEvent (m_display, XKeysymToKeycode(m_display, XK_Control_L), True, 0); + if (alt) XTestFakeKeyEvent (m_display, XKeysymToKeycode(m_display, XK_Alt_L), True, 0); + if (shift) XTestFakeKeyEvent (m_display, XKeysymToKeycode(m_display, XK_Shift_L), True, 0); + if (specialKey) { if (specialKey > (int)arraySize(SpecialKeysMap)) { @@ -132,6 +168,7 @@ bool MousepadPlugin::receivePackage(const NetworkPackage& np) } int keycode = XKeysymToKeycode(m_display, SpecialKeysMap[specialKey]); + XTestFakeKeyEvent (m_display, keycode, True, 0); XTestFakeKeyEvent (m_display, keycode, False, 0); @@ -150,6 +187,10 @@ bool MousepadPlugin::receivePackage(const NetworkPackage& np) fakekey_release(m_fakekey); } + if (ctrl) XTestFakeKeyEvent (m_display, XKeysymToKeycode(m_display, XK_Control_L), False, 0); + if (alt) XTestFakeKeyEvent (m_display, XKeysymToKeycode(m_display, XK_Alt_L), False, 0); + if (shift) XTestFakeKeyEvent (m_display, XKeysymToKeycode(m_display, XK_Shift_L), False, 0); + } XFlush(m_display); diff --git a/plugins/mpriscontrol/mpriscontrolplugin.cpp b/plugins/mpriscontrol/mpriscontrolplugin.cpp index 65b44b198..7d705e778 100644 --- a/plugins/mpriscontrol/mpriscontrolplugin.cpp +++ b/plugins/mpriscontrol/mpriscontrolplugin.cpp @@ -85,6 +85,19 @@ void MprisControlPlugin::addPlayer(const QString& service) OrgFreedesktopDBusPropertiesInterface* freedesktopInterface = new OrgFreedesktopDBusPropertiesInterface(service, "/org/mpris/MediaPlayer2", QDBusConnection::sessionBus(), this); connect(freedesktopInterface, SIGNAL(PropertiesChanged(QString, QVariantMap, QStringList)), this, SLOT(propertiesChanged(QString, QVariantMap))); + OrgMprisMediaPlayer2PlayerInterface* mprisInterface0 = new OrgMprisMediaPlayer2PlayerInterface(service, "/org/mpris/MediaPlayer2", QDBusConnection::sessionBus()); + connect(mprisInterface0, SIGNAL(Seeked(qlonglong)), this, SLOT(seeked(qlonglong))); +} + +void MprisControlPlugin::seeked(qlonglong position){ + qCDebug(KDECONNECT_PLUGIN_MPRIS) << "Seeked in player"; + NetworkPackage np(PACKAGE_TYPE_MPRIS); + np.set("pos", position/1000); //Send milis instead of nanos + OrgFreedesktopDBusPropertiesInterface* interface = (OrgFreedesktopDBusPropertiesInterface*)sender(); + const QString& service = interface->service(); + const QString& player = playerList.key(service); + np.set("player", player); + sendPackage(np); } void MprisControlPlugin::propertiesChanged(const QString& propertyInterface, const QVariantMap& properties) @@ -113,6 +126,13 @@ void MprisControlPlugin::propertiesChanged(const QString& propertyInterface, con np.set("nowPlaying",nowPlaying); somethingToSend = true; } + if (nowPlayingMap.contains("mpris:length")) { + if (nowPlayingMap.contains("mpris:length")) { + long long length = nowPlayingMap["mpris:length"].toLongLong(); + np.set("length",length/1000); //milis to nanos + } + somethingToSend = true; + } } if (properties.contains("PlaybackStatus")) { @@ -126,6 +146,12 @@ void MprisControlPlugin::propertiesChanged(const QString& propertyInterface, con const QString& service = interface->service(); const QString& player = playerList.key(service); np.set("player", player); + // Always also update the position + OrgMprisMediaPlayer2PlayerInterface mprisInterface(playerList[player], "/org/mpris/MediaPlayer2", QDBusConnection::sessionBus()); + if (mprisInterface.canSeek()) { + long long pos = mprisInterface.position(); + np.set("pos", pos/1000); //Send milis instead of nanos + } sendPackage(np); } } @@ -173,6 +199,13 @@ bool MprisControlPlugin::receivePackage (const NetworkPackage& np) mprisInterface.Seek(offset); } + if (np.has("SetPosition")){ + qlonglong position = np.get("SetPosition",0)*1000; + qlonglong seek = position - mprisInterface.position(); + qCDebug(KDECONNECT_PLUGIN_MPRIS) << "Setting position by seeking" << seek << "to" << playerList[player]; + mprisInterface.Seek(seek); + } + //Send something read from the mpris interface NetworkPackage answer(PACKAGE_TYPE_MPRIS); bool somethingToSend = false; @@ -182,7 +215,12 @@ bool MprisControlPlugin::receivePackage (const NetworkPackage& np) QString nowPlaying = nowPlayingMap["xesam:title"].toString(); if (nowPlayingMap.contains("xesam:artist")) { nowPlaying = nowPlayingMap["xesam:artist"].toString() + " - " + nowPlaying; + }if (nowPlayingMap.contains("mpris:length")) { + qlonglong length = nowPlayingMap["mpris:length"].toLongLong(); + answer.set("length",length/1000); } + qlonglong pos = mprisInterface.position(); + answer.set("pos", pos/1000); answer.set("nowPlaying",nowPlaying); diff --git a/plugins/mpriscontrol/mpriscontrolplugin.h b/plugins/mpriscontrol/mpriscontrolplugin.h index 20653d3d7..038f4b2dc 100644 --- a/plugins/mpriscontrol/mpriscontrolplugin.h +++ b/plugins/mpriscontrol/mpriscontrolplugin.h @@ -46,6 +46,7 @@ public Q_SLOTS: private Q_SLOTS: void serviceOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner); void propertiesChanged(const QString& propertyInterface, const QVariantMap& properties); + void seeked(qlonglong); private: void addPlayer(const QString& ifaceName); diff --git a/plugins/ping/kdeconnect_ping.desktop b/plugins/ping/kdeconnect_ping.desktop index 7757bf67b..46959a110 100644 --- a/plugins/ping/kdeconnect_ping.desktop +++ b/plugins/ping/kdeconnect_ping.desktop @@ -19,7 +19,7 @@ Name[cs]=Ping Name[da]=Ping Name[de]=Ping Name[es]=Ping -Name[fi]=Ping +Name[fi]=Tiedustelupaketti Name[fr]=Commande « Ping » Name[hu]=Ping Name[it]=Ping @@ -43,7 +43,7 @@ Comment[cs]=Posílat a přijímat ping Comment[da]=Send og modtag ping Comment[de]=Senden und Empfangen von Pings Comment[es]=Enviar y recibir pings -Comment[fi]=Lähetä ja vastaanota pingejä +Comment[fi]=Lähetä ja vastaanota tiedustelupaketteja Comment[fr]=Envoyez et recevez des « ping » Comment[hu]=Pingek küldése és fogadása Comment[it]=Invia e ricevi ping diff --git a/plugins/ping/pingplugin.cpp b/plugins/ping/pingplugin.cpp index 0f7362677..5c8ddb7d5 100644 --- a/plugins/ping/pingplugin.cpp +++ b/plugins/ping/pingplugin.cpp @@ -25,7 +25,7 @@ #include #include #include - +#include #include #include diff --git a/plugins/ping/pingplugin.h b/plugins/ping/pingplugin.h index 146db57b0..3217dcdab 100644 --- a/plugins/ping/pingplugin.h +++ b/plugins/ping/pingplugin.h @@ -22,11 +22,10 @@ #define PINGPLUGIN_H #include -#include #include -Q_DECLARE_LOGGING_CATEGORY(KDECONNECT_PLUGIN_PING) +#define PACKAGE_TYPE_PING QLatin1String("kdeconnect.ping") class Q_DECL_EXPORT PingPlugin : public KdeConnectPlugin diff --git a/plugins/screensaver-inhibit/CMakeLists.txt b/plugins/screensaver-inhibit/CMakeLists.txt new file mode 100644 index 000000000..f7bda4444 --- /dev/null +++ b/plugins/screensaver-inhibit/CMakeLists.txt @@ -0,0 +1,15 @@ +set(kdeconnect_screensaver_inhibit_SRCS + screensaverinhibitplugin.cpp +) + +add_library(kdeconnect_screensaver_inhibit ${kdeconnect_screensaver_inhibit_SRCS}) + +target_link_libraries(kdeconnect_screensaver_inhibit kdeconnectcore + Qt5::DBus + KF5::I18n + KF5::Service + KF5::Notifications +) + +install(TARGETS kdeconnect_screensaver_inhibit DESTINATION ${PLUGIN_INSTALL_DIR} ) +install(FILES kdeconnect_screensaver_inhibit.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) diff --git a/plugins/screensaver-inhibit/README b/plugins/screensaver-inhibit/README new file mode 100644 index 000000000..9f1b7ee19 --- /dev/null +++ b/plugins/screensaver-inhibit/README @@ -0,0 +1,3 @@ +This plugin inhibits the screensaver from kicking in when the device is connected +to kdeconnect, it then uninhibits the screensaver if the device was to go out of +range or be disconnected. \ No newline at end of file diff --git a/plugins/screensaver-inhibit/kdeconnect_screensaver_inhibit.desktop b/plugins/screensaver-inhibit/kdeconnect_screensaver_inhibit.desktop new file mode 100644 index 000000000..957f3c78d --- /dev/null +++ b/plugins/screensaver-inhibit/kdeconnect_screensaver_inhibit.desktop @@ -0,0 +1,39 @@ +[Desktop Entry] +Encoding=UTF-8 +Type=Service +ServiceTypes=KdeConnect/Plugin +X-KDE-Library=kdeconnect_screensaver_inhibit +X-KDE-PluginInfo-Author=Pramod Dematagoda +X-KDE-PluginInfo-Email=pmdematagoda@mykolab.ch +X-KDE-PluginInfo-Name=kdeconnect_screensaver_inhibit +X-KDE-PluginInfo-Version=0.1 +X-KDE-PluginInfo-Website=http://albertvaka.wordpress.com +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-EnabledByDefault=false +Icon=preferences-desktop-screensaver +Name=Inhibit screensaver +Name[ca]=Inhibeix l'estalvi de pantalla +Name[es]=Inhibir salvapantallas +Name[fi]=Estä näytönsäästäjän käynnistyminen +Name[ko]=화면 보호기 막기 +Name[nl]=Schermbeveiliging tegenhouden +Name[pl]=Powstrzymaj wygaszacz ekranu +Name[pt]=Inibir o protector de ecrã +Name[pt_BR]=Inibir o protetor de tela +Name[sk]=Obmedziť šetrič obrazovky +Name[sv]=Stoppa skärmsläckare +Name[uk]=Заборона зберігача екрана +Name[x-test]=xxInhibit screensaverxx +Comment=Inhibit the screensaver when the device is connected +Comment[ca]=Inhibeix l'estalvi de pantalla quan es connecta el dispositiu +Comment[es]=Inhibir el salvapantallas cuando el dispositivo está conectado +Comment[fi]=Estä näytönsäästäjän käynnistyminen, kun laite on yhteydessä +Comment[ko]=장치가 연결되어 있을 때 화면 보호기 실행 막기 +Comment[nl]=Houdt de schermbeveiliging tegen wanneer het apparaat is verbonden +Comment[pl]=Powstrzymaj wygaszacz ekrany po podłączeniu urządzenia +Comment[pt]=Inibir o protector de ecrã quando o dispositivo é ligado +Comment[pt_BR]=Inibir o protetor de tela quando o dispositivo estiver conectado +Comment[sk]=Obmedziť šetrič obrazovky keď je pripojené zariadenie +Comment[sv]=Stoppa skärmsläckaren när apparaten ansluts +Comment[uk]=Забороняє зберігач екрана, якщо з’єднано пристрій +Comment[x-test]=xxInhibit the screensaver when the device is connectedxx diff --git a/plugins/screensaver-inhibit/screensaverinhibitplugin.cpp b/plugins/screensaver-inhibit/screensaverinhibitplugin.cpp new file mode 100644 index 000000000..4d74fb4a4 --- /dev/null +++ b/plugins/screensaver-inhibit/screensaverinhibitplugin.cpp @@ -0,0 +1,81 @@ +/** + * Copyright 2014 Pramod Dematagoda + * + * 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) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "screensaverinhibitplugin.h" + +#include +#include +#include +#include +#include +#include +#include + +K_PLUGIN_FACTORY( KdeConnectPluginFactory, registerPlugin< ScreensaverInhibitPlugin >(); ) + +Q_LOGGING_CATEGORY(KDECONNECT_PLUGIN_SCREENSAVERINHIBIT, "kdeconnect.plugin.screensaverinhibit") + +const QString INHIBIT_SERVICE = "org.freedesktop.ScreenSaver"; +const QString INHIBIT_INTERFACE = INHIBIT_SERVICE; +const QString INHIBIT_PATH = "/ScreenSaver"; +const QString INHIBIT_METHOD = "Inhibit"; +const QString UNINHIBIT_METHOD = "UnInhibit"; +const QString SIMULATE_ACTIVITY_METHOD = "SimulateUserActivity"; + +ScreensaverInhibitPlugin::ScreensaverInhibitPlugin(QObject* parent, const QVariantList& args) + : KdeConnectPlugin(parent, args) +{ + QDBusInterface inhibitInterface(INHIBIT_SERVICE, INHIBIT_PATH, INHIBIT_INTERFACE); + + QDBusMessage reply = inhibitInterface.call(INHIBIT_METHOD, "kdeconnect", "Phone is connected"); + + if (reply.errorMessage() != NULL) { + qCDebug(KDECONNECT_PLUGIN_SCREENSAVERINHIBIT) << "Unable to inhibit the screensaver: " << reply.errorMessage(); + } else { + // Store the cookie we receive, this will be sent back when sending the uninhibit call. + this->inhibitCookie = reply.arguments().first().toUInt(); + } +} + +ScreensaverInhibitPlugin::~ScreensaverInhibitPlugin() +{ + QDBusInterface inhibitInterface(INHIBIT_SERVICE, INHIBIT_PATH, INHIBIT_INTERFACE); + inhibitInterface.call(UNINHIBIT_METHOD, this->inhibitCookie); + + /* + * Simulate user activity because what ever manages the screensaver does not seem to start the timer + * automatically when all inhibitions are lifted and the user does nothing which results in an + * unlocked desktop which would be dangerous. Ideally we should not be doing this and the screen should + * be locked anyway. + */ + inhibitInterface.call(SIMULATE_ACTIVITY_METHOD); +} + +void ScreensaverInhibitPlugin::connected() +{} + +bool ScreensaverInhibitPlugin::receivePackage(const NetworkPackage& np) +{ + Q_UNUSED(np); + return false; +} + + +#include "screensaverinhibitplugin.moc" diff --git a/plugins/screensaver-inhibit/screensaverinhibitplugin.h b/plugins/screensaver-inhibit/screensaverinhibitplugin.h new file mode 100644 index 000000000..d2efeca37 --- /dev/null +++ b/plugins/screensaver-inhibit/screensaverinhibitplugin.h @@ -0,0 +1,45 @@ +/** + * Copyright 2014 Pramod Dematagoda + * + * 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) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef SCREENSAVERINHIBITPLUGIN_H +#define SCREENSAVERINHIBITPLUGIN_H + +#include + +#include + +class Q_DECL_EXPORT ScreensaverInhibitPlugin + : public KdeConnectPlugin +{ + Q_OBJECT + +public: + explicit ScreensaverInhibitPlugin(QObject *parent, const QVariantList &args); + virtual ~ScreensaverInhibitPlugin(); + +public Q_SLOTS: + virtual bool receivePackage(const NetworkPackage& np); + virtual void connected(); + +private: + uint inhibitCookie; +}; + +#endif diff --git a/plugins/share/kdeconnect_share.desktop b/plugins/share/kdeconnect_share.desktop index 5f2c3201a..160c96c14 100644 --- a/plugins/share/kdeconnect_share.desktop +++ b/plugins/share/kdeconnect_share.desktop @@ -34,7 +34,7 @@ Name[uk]=Оприлюднення і отримання Name[x-test]=xxShare and receivexx Comment=Receive and send files, URLs or plain text easily Comment[bg]=Лесно получаване и изпращане на файлове, адреси и обикновен текст -Comment[ca]=Rep i envia fitxers, els URL o text pla amb facilitat +Comment[ca]=Rep i envia fitxers, els URL o text net amb facilitat Comment[cs]=Jednoduše přijímejte a posílejte soubory, URL nebo čistý text Comment[da]=Modtag og send filer, URL'er eller klartekst på nem måde Comment[de]=Empfang und Senden von Dateien, URLs oder einfacher Text diff --git a/plugins/telephony/kdeconnect_telephony.desktop b/plugins/telephony/kdeconnect_telephony.desktop index 2a7224849..d44b59512 100644 --- a/plugins/telephony/kdeconnect_telephony.desktop +++ b/plugins/telephony/kdeconnect_telephony.desktop @@ -60,4 +60,4 @@ Comment[uk]=Показ сповіщень щодо дзвінків і SMS (ск Comment[x-test]=xxShow notifications for calls and SMS (answering coming soon)xx X-KdeConnect-SupportedPackageType=kdeconnect.telephony -X-KdeConnect-OutgoingPackageType= +X-KdeConnect-OutgoingPackageType=kdeconnect.telephony diff --git a/plugins/telephony/telephonyplugin.cpp b/plugins/telephony/telephonyplugin.cpp index bea8c0824..114b5eabe 100644 --- a/plugins/telephony/telephonyplugin.cpp +++ b/plugins/telephony/telephonyplugin.cpp @@ -26,6 +26,7 @@ #include + K_PLUGIN_FACTORY( KdeConnectPluginFactory, registerPlugin< TelephonyPlugin >(); ) Q_LOGGING_CATEGORY(KDECONNECT_PLUGIN_TELEPHONY, "kdeconnect.plugin.telephony") @@ -82,6 +83,11 @@ KNotification* TelephonyPlugin::createNotification(const NetworkPackage& np) notification->setTitle(title); notification->setText(content); + if (event == "ringing") { + notification->setActions( QStringList(i18n("Mute call")) ); + connect(notification, SIGNAL(action1Activated()), this, SLOT(sendMutePackage())); + } + return notification; } @@ -105,4 +111,11 @@ bool TelephonyPlugin::receivePackage(const NetworkPackage& np) } +void TelephonyPlugin::sendMutePackage() +{ + NetworkPackage package(PACKAGE_TYPE_TELEPHONY); + package.set( "action", "mute" ); + sendPackage(package); +} + #include "telephonyplugin.moc" diff --git a/plugins/telephony/telephonyplugin.h b/plugins/telephony/telephonyplugin.h index 0d0a131a4..fb57d5ebd 100644 --- a/plugins/telephony/telephonyplugin.h +++ b/plugins/telephony/telephonyplugin.h @@ -43,6 +43,7 @@ public: public Q_SLOTS: virtual bool receivePackage(const NetworkPackage& np); virtual void connected() { } + void sendMutePackage(); private: KNotification* createNotification(const NetworkPackage& np);