summaryrefslogtreecommitdiff
path: root/plasma
diff options
context:
space:
mode:
Diffstat (limited to 'plasma')
-rw-r--r--plasma/CMakeLists.txt27
-rw-r--r--plasma/README12
-rw-r--r--plasma/common.cc53
-rw-r--r--plasma/common.hpp15
-rw-r--r--plasma/comthread.cc226
-rw-r--r--plasma/comthread.hpp153
-rw-r--r--plasma/config.ui101
-rw-r--r--plasma/configdialog.cc42
-rw-r--r--plasma/configdialog.h28
-rw-r--r--plasma/gtft.cpp216
-rw-r--r--plasma/gtft.h66
-rwxr-xr-xplasma/install.sh12
-rw-r--r--plasma/plasma-applet-gtft.desktop16
-rw-r--r--plasma/tcpchannel.cc387
14 files changed, 1354 insertions, 0 deletions
diff --git a/plasma/CMakeLists.txt b/plasma/CMakeLists.txt
new file mode 100644
index 0000000..237a68f
--- /dev/null
+++ b/plasma/CMakeLists.txt
@@ -0,0 +1,27 @@
+project(plasma-gtft)
+
+find_package(KDE4 REQUIRED)
+include(KDE4Defaults)
+include(MacroOptionalAddSubdirectory)
+# find_package(Plasma REQUIRED)
+
+add_definitions (${QT_DEFINITIONS} ${KDE4_DEFINITIONS})
+include_directories (${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} ${KDE4_INCLUDES})
+include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${PLASMA_INCLUDE_DIR})
+
+set(gtft_SRCS
+ configdialog.cc
+ gtft.cpp
+ comthread.cc
+ common.cc
+ tcpchannel.cc)
+
+kde4_add_ui_files(gtft_SRCS config.ui)
+macro_bool_to_01(KEXIV2_FOUND HAVE_KEXIV2)
+kde4_add_plugin(plasma_applet_gtft ${gtft_SRCS})
+
+target_link_libraries(plasma_applet_gtft ${KDE4_PLASMA_LIBS} ${KDE4_KDEUI_LIBS} )
+
+install(TARGETS plasma_applet_gtft DESTINATION ${PLUGIN_INSTALL_DIR})
+install(FILES plasma-applet-gtft.desktop DESTINATION ${SERVICES_INSTALL_DIR})
+
diff --git a/plasma/README b/plasma/README
new file mode 100644
index 0000000..1fbdf2a
--- /dev/null
+++ b/plasma/README
@@ -0,0 +1,12 @@
+
+# Install like all plasmoids
+
+mkdir build
+cd build
+cmake ../ -DCMAKE_INSTALL_PREFIX=`kde4-config --prefix`
+make -s
+sudo make -s install
+
+# After an update restart plasma
+kquitapp plasma && plasma
+
diff --git a/plasma/common.cc b/plasma/common.cc
new file mode 100644
index 0000000..13cea6b
--- /dev/null
+++ b/plasma/common.cc
@@ -0,0 +1,53 @@
+//***************************************************************************
+// Group VDR/GraphTFT
+// File common.cc
+// Date 04.11.06 - Jörg Wendel
+// This code is distributed under the terms and conditions of the
+// GNU GENERAL PUBLIC LICENSE. See the file COPYING for details.
+//***************************************************************************
+
+#include <sys/time.h>
+#include <stdarg.h>
+#include <time.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <plasma/applet.h>
+
+//***************************************************************************
+// Tell
+//***************************************************************************
+
+int tell(int eloquence, const char* format, ...)
+{
+ const int sizeTime = 8; // "12:12:34"
+ const int sizeMSec = 4; // ",142"
+ const int sizeHeader = sizeTime + sizeMSec + 1;
+ const int maxBuf = 1000;
+
+ struct timeval tp;
+ char buf[maxBuf];
+ va_list ap;
+ time_t now;
+
+ if (eloquence < 2)
+ {
+ va_start(ap, format);
+
+ time(&now);
+ gettimeofday(&tp, 0);
+
+ vsnprintf(buf + sizeHeader, maxBuf - sizeHeader, format, ap);
+ strftime(buf, sizeTime+1, "%H:%M:%S", localtime(&now));
+
+ sprintf(buf+sizeTime, ",%3.3ld", tp.tv_usec / 1000);
+
+ buf[sizeHeader-1] = ' ';
+
+ kDebug() << buf;
+
+ va_end(ap);
+ }
+
+ return 0;
+}
diff --git a/plasma/common.hpp b/plasma/common.hpp
new file mode 100644
index 0000000..b9c9765
--- /dev/null
+++ b/plasma/common.hpp
@@ -0,0 +1,15 @@
+//***************************************************************************
+// Group VDR/GraphTFT
+// File common.hpp
+// Date 04.11.06 - Jörg Wendel
+// This code is distributed under the terms and conditions of the
+// GNU GENERAL PUBLIC LICENSE. See the file COPYING for details.
+//***************************************************************************
+
+#ifndef __COMMON_HPP__
+#define __COMMON_HPP__
+
+int tell(int eloquence, const char* format, ...);
+
+#endif // __COMMON_HPP__
+
diff --git a/plasma/comthread.cc b/plasma/comthread.cc
new file mode 100644
index 0000000..52ef1b8
--- /dev/null
+++ b/plasma/comthread.cc
@@ -0,0 +1,226 @@
+//***************************************************************************
+// Group VDR/GraphTFT
+// File comthread.cc
+// Date 28.10.06 - Jörg Wendel
+// This code is distributed under the terms and conditions of the
+// GNU GENERAL PUBLIC LICENSE. See the file COPYING for details.
+//--------------------------------------------------------------------------
+// Class ComThread
+//***************************************************************************
+
+#include <arpa/inet.h>
+
+#include "comthread.hpp"
+
+//***************************************************************************
+// Object
+//***************************************************************************
+
+ComThread::ComThread()
+ : QThread()
+{
+ line = new TcpChannel();
+
+ bufferSize = maxBuffer;
+
+ buffer = new char[bufferSize+1];
+ header = new TcpChannel::Header;
+
+ timeout = 1;
+ port = -1;
+ *host = 0;
+}
+
+ComThread::~ComThread()
+{
+ if (line->isConnected())
+ {
+ tell(eloAlways, "Logout from server, closing tcp connection");
+ line->write(cGraphTftComService::cmdLogout);
+ line->close();
+ }
+
+ delete line;
+ delete header;
+ delete[] buffer;
+}
+
+//***************************************************************************
+// Run
+//***************************************************************************
+
+void ComThread::run()
+{
+ const int checkTimeout = 2;
+
+ int status;
+ time_t lastCheck = time(0);
+
+ running = true;
+
+ while (running)
+ {
+ if (!line->isConnected())
+ {
+ tell(eloAlways, "Trying connecting to '%s' at port (%d)", host, port);
+
+ if (line->open(host, port) == success)
+ tell(eloAlways, "Connection to '%s' established", host);
+ else
+ tell(eloAlways, "Connecting to '%s' failed", host);
+ }
+
+ while (line->isConnected() && running)
+ {
+ if (lastCheck+checkTimeout < time(0))
+ {
+ line->write(cGraphTftComService::cmdCheck);
+ lastCheck = time(0);
+ }
+
+ if ((status = line->look(1)) != success)
+ {
+ if (status != TcpChannel::wrnNoEventPending)
+ {
+ line->close();
+ tell(eloAlways, "Error: Communication problems, "
+ "look failed, status was (%d)", status);
+
+ break;
+ }
+
+ continue;
+ }
+
+ if ((status = read()) != success)
+ {
+ line->close();
+ tell(eloAlways, "Error: Communication problems, "
+ "read failed, status was (%d)", status);
+
+ break;
+ }
+ }
+
+ if (!running) break;
+
+ tell(eloAlways, "Retrying in %ld seconds", timeout);
+
+ for (int i = 0; i < timeout && running; i++)
+ sleep(1);
+ }
+}
+
+//***************************************************************************
+// Transmit events
+//***************************************************************************
+
+int ComThread::mouseEvent(int x, int y, int button, int flag, int data)
+{
+ GraphTftTouchEvent m;
+
+ m.x = x;
+ m.y = y;
+ m.button = button;
+ m.flag = flag;
+ m.data = data;
+ line->write(cGraphTftComService::cmdMouseEvent, (char*)&m, sizeof(GraphTftTouchEvent));
+
+ return 0;
+}
+
+//***************************************************************************
+// ...
+//***************************************************************************
+
+int ComThread::keyEvent(int key, int flag)
+{
+ GraphTftTouchEvent m;
+
+ m.x = 0;
+ m.y = 0;
+ m.button = key;
+ m.flag = flag | efKeyboard;
+ line->write(cGraphTftComService::cmdMouseEvent, (char*)&m, sizeof(GraphTftTouchEvent));
+
+ return 0;
+}
+
+//***************************************************************************
+// Read
+//***************************************************************************
+
+int ComThread::read()
+{
+ int status;
+ TcpChannel::Header tmp;
+
+ // es stehen Daten an, erst einmal den Header abholen ..
+
+ if ((status = line->read((char*)&tmp, sizeof(TcpChannel::Header))) == 0)
+ {
+ header->command = ntohl(tmp.command);
+ header->size = ntohl(tmp.size);
+
+ switch (header->command)
+ {
+ case cGraphTftComService::cmdWelcome:
+ {
+ tell(eloAlways, "Got welcome");
+
+ break;
+ }
+
+ case cGraphTftComService::cmdLogout:
+ {
+ tell(eloAlways, "Got logout from client, closing line");
+ line->close();
+
+ break;
+ }
+
+ case cGraphTftComService::cmdData:
+ {
+ tell(eloDebug, "Debug: Received %d bytes", header->size);
+
+ bufferLock.lockForWrite();
+ status = line->read(buffer, header->size);
+ bufferLock.unlock();
+
+ if (status == success)
+ update((unsigned char*)buffer, header->size);
+
+ break;
+ }
+
+ case cGraphTftComService::cmdMouseEvent:
+ {
+ GraphTftTouchEvent ev;
+
+ status = line->read((char*)&ev, header->size);
+ tell(eloAlways, "Got mouse event, button (%d) at (%d/%d)", ev.button, ev.x, ev.y);
+
+ break;
+ }
+
+ default:
+ {
+ tell(eloAlways, "Got unexpected protocol (%d), aborting", header->command);
+ status = -1;
+
+ break;
+ }
+ }
+ }
+
+ return status;
+}
+
+//***************************************************************************
+// Update Image
+//***************************************************************************
+
+void ComThread::update(unsigned char* buffer, int size)
+{
+ emit updateImage(buffer, size);
+}
diff --git a/plasma/comthread.hpp b/plasma/comthread.hpp
new file mode 100644
index 0000000..ccec05e
--- /dev/null
+++ b/plasma/comthread.hpp
@@ -0,0 +1,153 @@
+//***************************************************************************
+// Group VDR/GraphTFT
+// File graphtft.hpp
+// Date 28.10.06 - Jörg Wendel
+// This code is distributed under the terms and conditions of the
+// GNU GENERAL PUBLIC LICENSE. See the file COPYING for details.
+//--------------------------------------------------------------------------
+// Class ComThread
+// Class TcpChannel
+//***************************************************************************
+
+#ifndef __COMTHREAD_HPP__
+#define __COMTHREAD_HPP__
+
+#include <QObject>
+#include <QThread>
+#include <QReadWriteLock>
+
+#define __FRONTEND
+#include <../common.h>
+
+#include <common.hpp>
+#include <../service.h>
+
+#include <unistd.h>
+
+//***************************************************************************
+// TcpChannel
+//***************************************************************************
+
+class TcpChannel
+{
+ public:
+
+ // declarations
+
+ enum Errors
+ {
+ errChannel = -100,
+
+ errUnknownHostname,
+ errBindAddressFailed,
+ errAcceptFailed,
+ errListenFailed,
+ errConnectFailed,
+ errIOError,
+ errConnectionClosed,
+ errInvalidEndpoint,
+ errOpenEndpointFailed,
+
+ // Warnungen
+
+ wrnNoEventPending,
+ errUnexpectedEvent,
+ wrnChannelBlocked,
+ wrnNoConnectIndication,
+ wrnNoResponseFromServer,
+ wrnNoDataAvaileble,
+ wrnSysInterrupt,
+ wrnTimeout
+ };
+
+ struct Header
+ {
+ int command;
+ int size;
+ };
+
+ // object
+
+ TcpChannel();
+ ~TcpChannel();
+
+ // api function
+
+ int open(const char* aHost, int aPort);
+ int close();
+ int look(int aTimeout);
+ int read(char* buf, int bufLen);
+ int write(int command, const char* buf = 0, int bufLen = 0);
+ int isConnected() { return handle != 0; }
+
+ private:
+
+ int checkErrno();
+
+ int handle;
+ unsigned short port;
+ char localHost[100];
+ char remoteHost[100];
+ long localAddr;
+ long remoteAddr;
+ long timeout;
+ int lookAheadChar;
+ int lookAhead;
+ int nTtlReceived;
+ int nTtlSent;
+};
+
+//***************************************************************************
+// Communication Thread
+//***************************************************************************
+
+class ComThread : public QThread, public cGraphTftComService
+{
+ Q_OBJECT
+
+ public:
+
+ enum Misc
+ {
+ maxBuffer = 1024*1024
+ };
+
+ ComThread();
+ virtual ~ComThread();
+
+ void stop() { running = false; }
+ int mouseEvent(int x, int y, int button, int flag, int data = 0);
+ int keyEvent(int key, int flag);
+
+ const char* getBuffer() { return buffer; }
+ int getSize() { return header->size; }
+
+ void setHost(const char* aHost) { strcpy(host, aHost); }
+ void setPort(unsigned short aPort) { port = aPort; }
+ QReadWriteLock* getBufferLock() { return &bufferLock; }
+
+ signals:
+
+ void updateImage(unsigned char* buffer, int size);
+
+ protected:
+
+ void update(unsigned char* buffer, int size);
+ void run();
+ int read();
+
+ TcpChannel* line;
+
+ char* buffer;
+ int bufferSize;
+ QReadWriteLock bufferLock;
+
+ long timeout;
+ int running;
+ TcpChannel::Header* header;
+ unsigned short port;
+ char host[100];
+};
+
+//***************************************************************************
+#endif // __COMTHREAD_HPP__
diff --git a/plasma/config.ui b/plasma/config.ui
new file mode 100644
index 0000000..98c9479
--- /dev/null
+++ b/plasma/config.ui
@@ -0,0 +1,101 @@
+<ui version="4.0" >
+ <class>config</class>
+ <widget class="QWidget" name="config" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>480</width>
+ <height>250</height>
+ </rect>
+ </property>
+ <property name="minimumSize" >
+ <size>
+ <width>0</width>
+ <height>250</height>
+ </size>
+ </property>
+ <property name="styleSheet" >
+ <string notr="true" />
+ </property>
+ <layout class="QVBoxLayout" >
+ <item>
+ <widget class="QGroupBox" name="groupBox_2" >
+ <property name="title" >
+ <string>VDR</string>
+ </property>
+ <property name="flat" >
+ <bool>true</bool>
+ </property>
+ <layout class="QGridLayout" name="gridLayout" >
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label_2" >
+ <property name="text" >
+ <string>Host</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" >
+ <widget class="QLineEdit" name="lineEditHost" >
+ <property name="text" >
+ <string>localhost</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="label" >
+ <property name="text" >
+ <string>Port</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QLineEdit" name="lineEditPort" >
+ <property name="inputMask" >
+ <string>990000; </string>
+ </property>
+ <property name="text" >
+ <string>2039</string>
+ </property>
+ <property name="maxLength" >
+ <number>6</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox" >
+ <property name="title" >
+ <string>Appearance</string>
+ </property>
+ <property name="flat" >
+ <bool>true</bool>
+ </property>
+ <layout class="QVBoxLayout" >
+ <item>
+ <layout class="QVBoxLayout" >
+ <item>
+ <widget class="QCheckBox" name="smoothScaling" >
+ <property name="toolTip" >
+ <string>Use smooth scaling when resizing pictures. Usually pictures look better this way, but it takes more time to load them.</string>
+ </property>
+ <property name="text" >
+ <string>Smooth scaling</string>
+ </property>
+ <property name="checked" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/plasma/configdialog.cc b/plasma/configdialog.cc
new file mode 100644
index 0000000..f791870
--- /dev/null
+++ b/plasma/configdialog.cc
@@ -0,0 +1,42 @@
+
+#include "configdialog.h"
+
+ConfigDialog::ConfigDialog(QWidget* parent)
+ : QWidget(parent)
+{
+ ui.setupUi(this);
+}
+
+ConfigDialog::~ConfigDialog()
+{
+}
+
+void ConfigDialog::setSmoothScaling(bool smooth)
+{
+ ui.smoothScaling->setChecked(smooth);
+}
+
+bool ConfigDialog::smoothScaling() const
+{
+ return ui.smoothScaling->isChecked();
+}
+
+void ConfigDialog::setHost(QString host)
+{
+ ui.lineEditHost->setText(host);
+}
+
+QString ConfigDialog::host() const
+{
+ return ui.lineEditHost->text();
+}
+
+void ConfigDialog::setPort(unsigned int port)
+{
+ ui.lineEditPort->setText(QString::number(port));
+}
+
+unsigned int ConfigDialog::port() const
+{
+ return ui.lineEditPort->text().toInt();
+}
diff --git a/plasma/configdialog.h b/plasma/configdialog.h
new file mode 100644
index 0000000..ea0d7a5
--- /dev/null
+++ b/plasma/configdialog.h
@@ -0,0 +1,28 @@
+
+
+#ifndef CONFIGDIALOG_H
+#define CONFIGDIALOG_H
+
+#include "ui_config.h"
+
+class ConfigDialog : public QWidget
+{
+ Q_OBJECT
+
+ public:
+
+ ConfigDialog(QWidget* parent);
+ ~ConfigDialog();
+
+ void setSmoothScaling(bool smooth);
+ bool smoothScaling() const;
+ void setHost(QString host);
+ QString host() const;
+ void setPort(unsigned int port);
+ unsigned int port() const;
+
+ Ui::config ui;
+
+};
+
+#endif // CONFIGDIALOG_H
diff --git a/plasma/gtft.cpp b/plasma/gtft.cpp
new file mode 100644
index 0000000..7ae993a
--- /dev/null
+++ b/plasma/gtft.cpp
@@ -0,0 +1,216 @@
+
+#include <KConfigDialog>
+#include <KSharedConfig>
+#include <KServiceTypeTrader>
+#include <kglobalsettings.h>
+
+#include <gtft.h>
+#include <configdialog.h>
+
+GtftApplet::GtftApplet(QObject* parent, const QVariantList& args)
+ : Plasma::Applet(parent, args)
+{
+ configDialog = 0;
+ vdrWidth = 720;
+ vdrHeight = 576;
+
+ thread = new ComThread();
+
+ setHasConfigurationInterface(true);
+ setCacheMode(QGraphicsItem::NoCache);
+ setBackgroundHints(Plasma::Applet::NoBackground);
+ setAspectRatioMode(Plasma::KeepAspectRatio); // Plasma::IgnoreAspectRatio
+
+ resize(400, 300);
+}
+
+GtftApplet::~GtftApplet()
+{
+ if (thread)
+ {
+ tell(eloAlways, "Stopping thread");
+
+ thread->stop();
+
+ if (!thread->wait(1000))
+ tell(eloAlways, "Thread would not end!");
+ else
+ tell(eloAlways, "Thread ended regularly");
+
+ delete thread;
+ }
+}
+
+void GtftApplet::init()
+{
+ // picture.load("/home/wendel/test.jpg");
+
+ // read config
+
+ KConfigGroup cg = config();
+
+ smoothScaling = cg.readEntry("smoothScaling", true);
+ host = cg.readEntry("vdr host", "localhost");
+ port = cg.readEntry("vdr port", 2039);
+
+ connect(thread, SIGNAL(updateImage(unsigned char*, int)),
+ this, SLOT(updateImage(unsigned char*, int)));
+
+ tell(eloAlways, "Starting thread");
+
+ thread->setHost(host.toAscii());
+ thread->setPort(port);
+
+ thread->start();
+}
+
+//***************************************************************************
+// Configuration
+//***************************************************************************
+
+void GtftApplet::createConfigurationInterface(KConfigDialog* parent)
+{
+ configDialog = new ConfigDialog(parent);
+
+ parent->addPage(configDialog, i18n("General"), "configure");
+ parent->setDefaultButton(KDialog::Ok);
+ parent->showButtonSeparator(true);
+
+ connect(parent, SIGNAL(applyClicked()), this, SLOT(configAccepted()));
+ connect(parent, SIGNAL(okClicked()), this, SLOT(configAccepted()));
+
+ configDialog->setSmoothScaling(smoothScaling);
+ configDialog->setHost(host);
+ configDialog->setPort(port);
+}
+
+void GtftApplet::configAccepted()
+{
+ KConfigGroup cg = config();
+
+ // connection parameter changed ?
+
+ if (host != configDialog->host() ||
+ port != configDialog->port())
+ {
+ // reconnect ..
+
+ thread->stop();
+ host = configDialog->host();
+ port = configDialog->port();
+ thread->setHost(host.toAscii());
+ thread->setPort(port);
+ thread->start();
+ }
+
+ smoothScaling = configDialog->smoothScaling();
+
+ cg.writeEntry("smoothScaling", smoothScaling);
+ cg.writeEntry("vdr host", host);
+ cg.writeEntry("vdr port", port);
+
+ emit configNeedsSaving();
+}
+
+void GtftApplet::updateImage(unsigned char* buffer, int size)
+{
+ thread->getBufferLock()->lockForRead();
+ picture.loadFromData(buffer, size);
+ thread->getBufferLock()->unlock();
+
+ update();
+}
+
+void GtftApplet::paintInterface(QPainter* p, const QStyleOptionGraphicsItem* option,
+ const QRect& rect)
+{
+ Q_UNUSED(option);
+ QPixmap* pixmap;
+
+ Qt::TransformationMode tm = smoothScaling ? Qt::SmoothTransformation : Qt::FastTransformation;
+
+ if (!picture.isNull())
+ pixmap = &picture;
+ else
+ return ;
+
+ QPixmap scaledImage = pixmap->scaled(rect.size(), Qt::KeepAspectRatio, tm);
+ p->drawPixmap(rect, scaledImage);
+
+ // notice some data for 'scaling' the mouse cooridinates ...
+
+ paintRect = rect;
+ vdrWidth = pixmap->width();
+ vdrHeight = pixmap->height();
+}
+
+//***************************************************************************
+// User Action
+//***************************************************************************
+
+void GtftApplet::keyPressEvent(QKeyEvent* keyEvent)
+{
+ thread->mouseEvent(0, 0, keyEvent->nativeScanCode(), ComThread::efKeyboard);
+}
+
+void GtftApplet::mouseMoveEvent(QGraphicsSceneMouseEvent* /*event*/)
+{
+ // don't drag the widget ...
+}
+
+void GtftApplet::mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event)
+{
+ QPoint p = clickCoordinate(event->screenPos());
+
+ thread->mouseEvent(p.x(), p.y(), cGraphTftComService::mbLeft,
+ cGraphTftComService::efDoubleClick);
+}
+
+void GtftApplet::mouseReleaseEvent(QGraphicsSceneMouseEvent* /*event*/)
+{
+ // #TODO
+ // Mouse gestures
+}
+
+void GtftApplet::wheelEvent(QGraphicsSceneWheelEvent* wheelEvent)
+{
+ QPoint p = clickCoordinate(wheelEvent->screenPos());
+
+ if (wheelEvent->delta() > 0)
+ thread->mouseEvent(p.x(), p.y(), cGraphTftComService::mbWheelUp, 0);
+ else
+ thread->mouseEvent(p.x(), p.y(), cGraphTftComService::mbWheelDown, 0);
+}
+
+void GtftApplet::mousePressEvent(QGraphicsSceneMouseEvent* event)
+{
+ QPoint p = clickCoordinate(event->screenPos());
+
+ tell(4, "mousePressEvent %d/%d", p.x(), p.y());
+
+ if (event->buttons() == Qt::LeftButton)
+ thread->mouseEvent(p.x(), p.y(), cGraphTftComService::mbLeft, 0);
+ else if (event->buttons() == Qt::MidButton)
+ thread->mouseEvent(p.x(), p.y(), cGraphTftComService::mbRight, 0);
+}
+
+QPoint GtftApplet::clickCoordinate(QPoint screenPos)
+{
+ QPoint p;
+
+ // calc position relative to the draw area (the image)
+
+ p.setX(screenPos.x() - (geometry().x() + paintRect.x()));
+ p.setY(screenPos.y() - (geometry().y() + paintRect.y()));
+
+ // scale
+
+ p.setX((int)(((double)p.x() / (double)paintRect.width()) * (double)vdrWidth));
+ p.setY((int)(((double)p.y() / (double)paintRect.height()) * (double)vdrHeight));
+
+ return p;
+}
+
+//***************************************************************************
+
+#include "gtft.moc"
diff --git a/plasma/gtft.h b/plasma/gtft.h
new file mode 100644
index 0000000..e2daa21
--- /dev/null
+++ b/plasma/gtft.h
@@ -0,0 +1,66 @@
+
+
+#ifndef _GTFT_H
+#define _GTFT_H
+
+#include <QPainter>
+#include <QGraphicsSceneMouseEvent>
+#include <Plasma/Applet>
+
+#include <comthread.hpp>
+
+class ConfigDialog;
+
+// using namespace Plasma;
+
+class GtftApplet : public Plasma::Applet
+{
+ Q_OBJECT
+
+ public:
+
+ GtftApplet(QObject* parent, const QVariantList& args);
+ ~GtftApplet();
+
+ void mouseDoubleClickEvent(QGraphicsSceneMouseEvent* mouseEvent);
+ void mouseReleaseEvent(QGraphicsSceneMouseEvent* mouseEvent);
+ void wheelEvent(QGraphicsSceneWheelEvent* wheelEvent);
+ void mousePressEvent(QGraphicsSceneMouseEvent *event);
+ void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
+ void keyPressEvent(QKeyEvent* keyEvent);
+
+ void paintInterface(QPainter* painter, const QStyleOptionGraphicsItem* option,
+ const QRect& contentsRect);
+ void init();
+
+ public slots:
+
+ void updateImage(unsigned char* buffer, int size);
+ void createConfigurationInterface(KConfigDialog *parent);
+
+ protected Q_SLOTS:
+
+ void configAccepted();
+
+ protected:
+
+ QPoint clickCoordinate(QPoint screenPos);
+
+ private:
+
+ ConfigDialog* configDialog;
+ bool smoothScaling;
+ QString host;
+ unsigned int port;
+ QRect paintRect;
+
+ QPixmap picture;
+ ComThread* thread;
+
+ int vdrWidth;
+ int vdrHeight;
+};
+
+K_EXPORT_PLASMA_APPLET(gtft, GtftApplet)
+
+#endif // _GTFT_H
diff --git a/plasma/install.sh b/plasma/install.sh
new file mode 100755
index 0000000..16841a9
--- /dev/null
+++ b/plasma/install.sh
@@ -0,0 +1,12 @@
+
+if [ ! -d build ]; then
+ mkdir build
+fi
+
+cd build
+cmake ../ -DCMAKE_INSTALL_PREFIX=`kde4-config --prefix`
+make -s
+sudo make -s install
+
+# kquitapp plasma && plasma
+
diff --git a/plasma/plasma-applet-gtft.desktop b/plasma/plasma-applet-gtft.desktop
new file mode 100644
index 0000000..cd61c18
--- /dev/null
+++ b/plasma/plasma-applet-gtft.desktop
@@ -0,0 +1,16 @@
+[Desktop Entry]
+Name=GraphTFT
+Comment=Frontend for VDR graphTFT plugin
+Type=Service
+Icon=system-run
+X-KDE-ServiceTypes=Plasma/Applet
+X-KDE-Library=plasma_applet_gtft
+X-KDE-PluginInfo-Author=Jörg Wendel
+X-KDE-PluginInfo-Email=vdr@jwendel.de
+X-KDE-PluginInfo-Name=graphtft
+X-KDE-PluginInfo-Version=0.0.1
+X-KDE-PluginInfo-Website=
+X-KDE-PluginInfo-Category=Multimedia
+X-KDE-PluginInfo-Depends=
+X-KDE-PluginInfo-License=GPL
+X-KDE-PluginInfo-EnabledByDefault=true
diff --git a/plasma/tcpchannel.cc b/plasma/tcpchannel.cc
new file mode 100644
index 0000000..1f76940
--- /dev/null
+++ b/plasma/tcpchannel.cc
@@ -0,0 +1,387 @@
+//***************************************************************************
+// Group VDR/GraphTFT
+// File tcpchannel.cc
+// Date 28.10.06 - Jörg Wendel
+// This code is distributed under the terms and conditions of the
+// GNU GENERAL PUBLIC LICENSE. See the file COPYING for details.
+//--------------------------------------------------------------------------
+// Class TcpChannel
+//***************************************************************************
+
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+
+#include "comthread.hpp"
+
+//***************************************************************************
+// Class TcpChannel
+//***************************************************************************
+//***************************************************************************
+// Object
+//***************************************************************************
+
+TcpChannel::TcpChannel()
+{
+ handle = 0;
+ port = 0;
+ *localHost = 0;
+ *remoteHost = 0;
+ localAddr = 0;
+ remoteAddr = 0;
+ timeout = 30;
+ lookAheadChar = false;
+ lookAhead = 0;
+ nTtlSent = 0;
+ nTtlReceived = 0;
+}
+
+TcpChannel::~TcpChannel()
+{
+ // nothing yet !
+}
+
+//***************************************************************************
+// Open
+//***************************************************************************
+
+int TcpChannel::open(const char* aHost, int aPort)
+{
+ const char* hostName;
+ struct sockaddr_in localSockAddr, remoteSockAddr;
+ struct hostent* hostInfo;
+ int aHandle;
+
+ if (!aHost || !*aHost)
+ return -1;
+
+ hostName = aHost;
+
+ // clear
+
+ memset((char*)&localSockAddr, 0, sizeof(localSockAddr));
+ memset((char*)&remoteSockAddr, 0, sizeof(remoteSockAddr));
+
+ // init
+
+ localSockAddr.sin_family = remoteSockAddr.sin_family = AF_INET;
+ remoteSockAddr.sin_port = htons(aPort);
+
+ // resolve local host
+
+ if (localHost && *localHost)
+ {
+ // search alias
+
+ if ((hostInfo = ::gethostbyname(localHost)))
+ memcpy((char*)&localAddr, hostInfo->h_addr, hostInfo->h_length);
+
+ else if ((localAddr = inet_addr(localHost)) == (int)INADDR_NONE)
+ return errUnknownHostname;
+
+ // set local endpoint
+
+ memcpy(&localSockAddr.sin_addr, &localAddr, sizeof(struct in_addr));
+ }
+
+ // map hostname to ip
+
+ if ((hostInfo = ::gethostbyname(hostName)))
+ memcpy((char*)&remoteAddr, hostInfo->h_addr, hostInfo->h_length);
+
+ else if ((remoteAddr = inet_addr(hostName)) == (int)INADDR_NONE)
+ return errUnknownHostname;
+
+ // save hostname
+
+ strncpy(remoteHost, hostName, sizeof(remoteHost));
+
+ // set sockaddr
+
+ memcpy(&remoteSockAddr.sin_addr, &remoteAddr, sizeof(struct in_addr));
+
+ // create new socket
+
+ if ((aHandle = socket(PF_INET, SOCK_STREAM, 0)) < 0)
+ return errOpenEndpointFailed;
+
+ // bind only if localSockAddr is set
+
+ if (*((int*)&localSockAddr.sin_addr) != 0)
+ {
+ // bind local address to socket
+
+ if (::bind(aHandle, (struct sockaddr*)&localSockAddr, sizeof(localSockAddr)) < 0)
+ {
+ ::close(aHandle);
+
+ return errBindAddressFailed;
+ }
+ }
+
+ // none blocking
+
+ if (fcntl(handle, F_SETFL, O_NONBLOCK) < 0)
+ return fail;
+
+ // connect to server
+
+ if (connect(aHandle, (struct sockaddr*)&remoteSockAddr, sizeof(remoteSockAddr)) < 0)
+ {
+ ::close(aHandle);
+
+ if (errno != ECONNREFUSED)
+ return errConnectFailed;
+
+ return wrnNoResponseFromServer;
+ }
+
+ // save results
+
+ handle = aHandle;
+ port = aPort;
+
+ return success;
+}
+
+//***************************************************************************
+// Read
+//***************************************************************************
+
+int TcpChannel::read(char* buf, int bufLen)
+{
+ int nfds, result;
+ fd_set readFD;
+ int nReceived;
+ struct timeval wait;
+
+ memset(buf, 0, bufLen);
+ nReceived = 0;
+
+ if (lookAhead)
+ {
+ *(buf) = lookAheadChar;
+ lookAhead = false;
+ nReceived++;
+ }
+
+ while (nReceived < bufLen)
+ {
+ result = ::read(handle, buf + nReceived, bufLen - nReceived);
+
+ if (result < 0)
+ {
+ if (errno != EWOULDBLOCK)
+ return checkErrno();
+
+ // time-out for select
+
+ wait.tv_sec = timeout;
+ wait.tv_usec = 0;
+
+ // clear and set file-descriptors
+
+ FD_ZERO(&readFD);
+ FD_SET(handle, &readFD);
+
+ // look event
+
+ if ((nfds = ::select(handle+1, &readFD, 0, 0, &wait)) < 0)
+ return checkErrno();
+
+ // no event occured -> timeout
+
+ if (nfds == 0)
+ return wrnTimeout;
+ }
+
+ else if (result == 0)
+ {
+ // connection closed -> eof received
+
+ return errConnectionClosed;
+ }
+
+ else
+ {
+ // inc read char count
+
+ nReceived += result;
+ }
+ }
+
+ nTtlReceived += nReceived;
+
+ return success;
+}
+
+//***************************************************************************
+// Look
+//***************************************************************************
+
+int TcpChannel::look(int aTimeout)
+{
+ struct timeval timeout;
+ fd_set readFD, writeFD, exceptFD;
+ int n;
+
+ // time-out for select
+
+ timeout.tv_sec = aTimeout;
+ timeout.tv_usec = 1;
+
+ // clear and set file-descriptors
+
+ FD_ZERO(&readFD);
+ FD_ZERO(&writeFD);
+ FD_ZERO(&exceptFD);
+
+ FD_SET(handle, &readFD);
+ FD_SET(handle, &writeFD);
+ FD_SET(handle, &exceptFD);
+
+ // look event
+
+ n = ::select(handle+1, &readFD, (aTimeout ? 0 : &writeFD) , &exceptFD, &timeout);
+
+ if (n < 0)
+ return checkErrno();
+
+ // check exception
+
+ if (FD_ISSET(handle, &exceptFD))
+ return errUnexpectedEvent;
+
+ // check write ok
+
+ if (!FD_ISSET(handle, &writeFD))
+ return wrnChannelBlocked;
+
+ // check read-event
+
+ if (!FD_ISSET(handle, &readFD))
+ return wrnNoEventPending;
+
+ // check first-char
+
+ if (::read(handle, &lookAheadChar, 1) == 0)
+ return errConnectionClosed;
+
+ // look ahead char received
+
+ lookAhead = true;
+
+ return success;
+}
+
+//***************************************************************************
+// Write to client
+//***************************************************************************
+
+int TcpChannel::write(int command, const char* buf, int bufLen)
+{
+ struct timeval wait;
+ int result, nfds;
+ fd_set writeFD;
+ int nSent = 0;
+ Header header;
+
+ //cMutexLock lock(&_mutex);
+
+ if (buf && !bufLen)
+ bufLen = strlen(buf);
+
+ tell(eloDebug, "Writing (%d) header bytes, command (%d), size (%ld)",
+ sizeof(Header), command, bufLen);
+
+ header.command = htonl(command);
+ header.size = htonl(bufLen);
+ result = ::write(handle, &header, sizeof(Header));
+
+ if (result != sizeof(Header))
+ return errIOError;
+
+ if (!buf)
+ return 0;
+
+ tell(eloDebug, "Writing (%ld) kb now", bufLen/1024);
+
+ do
+ {
+ result = ::write(handle, buf + nSent, bufLen - nSent);
+
+ if (result < 0)
+ {
+ if (errno != EWOULDBLOCK)
+ return checkErrno();
+
+ // time-out for select
+
+ wait.tv_sec = timeout;
+ wait.tv_usec = 0;
+
+ // clear and set file-descriptors
+
+ FD_ZERO(&writeFD);
+ FD_SET(handle, &writeFD);
+
+ // look event
+
+ if ((nfds = ::select(handle+1, 0, &writeFD, 0, &wait)) < 0)
+ {
+ // Error: Select failed
+
+ return checkErrno();
+ }
+
+ // no event occured -> timeout
+
+ if (nfds == 0)
+ return wrnTimeout;
+ }
+ else
+ {
+ nSent += result;
+ }
+
+ } while (nSent < bufLen);
+
+ // increase send counter
+
+ nTtlSent += nSent;
+
+ return success;
+}
+
+//***************************************************************************
+// Close
+//***************************************************************************
+
+int TcpChannel::close()
+{
+ if (!handle)
+ return success;
+
+ ::close(handle);
+ handle = 0;
+
+ return success;
+}
+//***************************************************************************
+// Check Errno
+//***************************************************************************
+
+int TcpChannel::checkErrno()
+{
+ switch (errno)
+ {
+ case EINTR: return wrnSysInterrupt;
+ case EBADF: return errInvalidEndpoint;
+ case EWOULDBLOCK: return wrnNoDataAvaileble;
+ case ECONNRESET: return errConnectionClosed;
+ default: return errIOError;
+ }
+}