Merge branch 'master' into frameworks

Conflicts:
	core/backends/lan/lanlinkprovider.cpp
	plugins/ping/pingplugin.h
	plugins/telephony/telephonyplugin.cpp
This commit is contained in:
Albert Vaca 2015-01-10 20:14:01 -08:00
commit c7c1974ea9
28 changed files with 421 additions and 91 deletions

View file

@ -36,6 +36,7 @@ class DeviceLink
public:
DeviceLink(const QString& deviceId, LinkProvider* parent);
virtual ~DeviceLink() { };
const QString& deviceId() { return mDeviceId; }
LinkProvider* provider() { return mLinkProvider; }

View file

@ -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);
}

View file

@ -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);

View file

@ -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<QString>("id","");
//kDebug(debugArea()) << "Ignoring my own broadcast";
if (receivedPackage->get<QString>("deviceId") == myId) {
//kDebug(debugArea()) << "Ignoring my own broadcast";
delete receivedPackage;
return;
}
int tcpPort = receivedPackage->get<int>("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<QTcpSocket*>(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<QTcpSocket*>(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<QTcpSocket*>(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<QString>("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<QString>("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)

View file

@ -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()

View file

@ -45,7 +45,6 @@ public:
qint64 bytesAvailable() { return mPackages.size(); }
Q_SIGNALS:
void disconnected();
void readyRead();
private Q_SLOTS:

View file

@ -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;

View file

@ -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

View file

@ -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

View file

@ -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})

42
plugins/README.txt Normal file
View file

@ -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 <string> </string>).
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.

View file

@ -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

View file

@ -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

View file

@ -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 <typename T, size_t N>
@ -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<float>("dx", 0);
float dy = np.get<float>("dy", 0);
@ -86,11 +106,13 @@ bool MousepadPlugin::receivePackage(const NetworkPackage& np)
bool isDoubleClick = np.get<bool>("doubleclick", false);
bool isMiddleClick = np.get<bool>("middleclick", false);
bool isRightClick = np.get<bool>("rightclick", false);
bool isSingleHold = np.get<bool>("singlehold", false);
bool isSingleRelease = np.get<bool>("singlerelease", false);
bool isScroll = np.get<bool>("scroll", false);
QString key = np.get<QString>("key", "");
int specialKey = np.get<int>("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<bool>("ctrl", false);
bool alt = np.get<bool>("alt", false);
bool shift = np.get<bool>("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);

View file

@ -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<qlonglong>("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);

View file

@ -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);

View file

@ -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

View file

@ -25,7 +25,7 @@
#include <QDebug>
#include <KLocalizedString>
#include <KPluginFactory>
#include <QLoggingCategory>
#include <core/device.h>
#include <QDBusConnection>

View file

@ -22,11 +22,10 @@
#define PINGPLUGIN_H
#include <QObject>
#include <QLoggingCategory>
#include <core/kdeconnectplugin.h>
Q_DECLARE_LOGGING_CATEGORY(KDECONNECT_PLUGIN_PING)
#define PACKAGE_TYPE_PING QLatin1String("kdeconnect.ping")
class Q_DECL_EXPORT PingPlugin
: public KdeConnectPlugin

View file

@ -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} )

View file

@ -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.

View file

@ -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

View file

@ -0,0 +1,81 @@
/**
* Copyright 2014 Pramod Dematagoda <pmdematagoda@mykolab.ch>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "screensaverinhibitplugin.h"
#include <QDebug>
#include <KLocalizedString>
#include <KPluginFactory>
#include <QLoggingCategory>
#include <core/device.h>
#include <QDBusConnection>
#include <QDBusInterface>
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"

View file

@ -0,0 +1,45 @@
/**
* Copyright 2014 Pramod Dematagoda <pmdematagoda@mykolab.ch>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef SCREENSAVERINHIBITPLUGIN_H
#define SCREENSAVERINHIBITPLUGIN_H
#include <QObject>
#include <core/kdeconnectplugin.h>
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

View file

@ -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

View file

@ -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

View file

@ -26,6 +26,7 @@
#include <KPluginFactory>
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<QString>( "action", "mute" );
sendPackage(package);
}
#include "telephonyplugin.moc"

View file

@ -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);