diff options
Diffstat (limited to 'plasma')
-rw-r--r-- | plasma/CMakeLists.txt | 27 | ||||
-rw-r--r-- | plasma/README | 12 | ||||
-rw-r--r-- | plasma/common.cc | 53 | ||||
-rw-r--r-- | plasma/common.hpp | 15 | ||||
-rw-r--r-- | plasma/comthread.cc | 226 | ||||
-rw-r--r-- | plasma/comthread.hpp | 153 | ||||
-rw-r--r-- | plasma/config.ui | 101 | ||||
-rw-r--r-- | plasma/configdialog.cc | 42 | ||||
-rw-r--r-- | plasma/configdialog.h | 28 | ||||
-rw-r--r-- | plasma/gtft.cpp | 216 | ||||
-rw-r--r-- | plasma/gtft.h | 66 | ||||
-rwxr-xr-x | plasma/install.sh | 12 | ||||
-rw-r--r-- | plasma/plasma-applet-gtft.desktop | 16 | ||||
-rw-r--r-- | plasma/tcpchannel.cc | 387 |
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; + } +} |