summaryrefslogtreecommitdiffstats
path: root/src/src/knetstatsview.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/src/knetstatsview.cpp')
-rw-r--r--src/src/knetstatsview.cpp402
1 files changed, 402 insertions, 0 deletions
diff --git a/src/src/knetstatsview.cpp b/src/src/knetstatsview.cpp
new file mode 100644
index 0000000..ea480ab
--- /dev/null
+++ b/src/src/knetstatsview.cpp
@@ -0,0 +1,402 @@
+/***************************************************************************
+ * Copyright (C) 2004-2005 by Hugo Parente Lima *
+ * hugo_pl@users.sourceforge.net *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+#include "knetstatsview.h"
+#include "knetstats.h"
+
+// KDE headers
+#include <kapplication.h>
+#include <kiconloader.h>
+#include <kpopupmenu.h>
+#include <kmessagebox.h>
+#include <kaboutapplication.h>
+#include <kconfig.h>
+#include <kglobal.h>
+#include <kstandarddirs.h>
+
+#include <kaction.h>
+#include <kstdaccel.h>
+#include <kstdaction.h>
+#include <khelpmenu.h>
+#include <kpassivepopup.h>
+
+// Qt headers
+#include <qtimer.h>
+#include <qfile.h>
+#include <qtooltip.h>
+#include <qcursor.h>
+#include <qevent.h>
+#include <qfont.h>
+#include <qfontmetrics.h>
+#include <qpainter.h>
+
+// C headers
+#include <cstring>
+#include <cstdio>
+
+// Linux headers
+extern "C" {
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <linux/if.h>
+}
+
+#include "configure.h"
+#include "statistics.h"
+
+extern const char* programName;
+
+KNetStatsView::KNetStatsView(KNetStats* parent, const QString& interface)
+: KSystemTray(parent, 0), mSysDevPath("/sys/class/net/"+interface+"/"), mInterface(interface) {
+ mFdSock = 0;
+ mFirstUpdate = true;
+ mMaxSpeedAge = 0;
+ mMaxSpeed = 0.0;
+ mBRx = mBTx = mPRx = mPTx = 0;
+ mConnected = mCarrier = true;
+ mTotalBytesRx = mTotalBytesTx = mTotalPktRx = mTotalPktTx = 0;
+ mSpeedBufferPtr = mSpeedHistoryPtr = 0;
+ mStatistics = 0;
+
+ readOptions(interface, &mOptions, true);
+ resetBuffers();
+ openFdSocket();
+ memset(&mDevInfo, 0, sizeof(mDevInfo));
+ strcpy(mDevInfo.ifr_name, mInterface.latin1());
+
+ setTextFormat(Qt::PlainText);
+ mContextMenu = parent->contextMenu();
+ show();
+
+ // Timer
+ mTimer = new QTimer(this, "timer");
+ connect(mTimer, SIGNAL(timeout()), this, SLOT(updateStats(void)));
+
+ QToolTip::add(this, i18n("Monitoring %1").arg(mInterface));
+ setup();
+ mStatistics = new Statistics(this);
+}
+
+KNetStatsView::~KNetStatsView() {
+ if (mFdSock != -1)
+ shutdown(mFdSock, SHUT_RDWR);
+
+}
+
+void KNetStatsView::setup() {
+ if (mOptions.mViewMode == Text)
+ setFont(mOptions.mTxtFont);
+ else if (mOptions.mViewMode == Icon) {
+ // Load Icons
+ KIconLoader* loader = kapp->iconLoader();
+ mIconError = loader->loadIcon("theme"+QString::number(mOptions.mTheme)+"_error.png",
+ KIcon::Panel, ICONSIZE);
+ mIconNone = loader->loadIcon("theme"+QString::number(mOptions.mTheme)+"_none.png",
+ KIcon::Panel, ICONSIZE);
+ mIconTx = loader->loadIcon("theme"+QString::number(mOptions.mTheme)+"_tx.png",
+ KIcon::Panel, ICONSIZE);
+ mIconRx =loader->loadIcon("theme"+QString::number(mOptions.mTheme)+"_rx.png",
+ KIcon::Panel, ICONSIZE);
+ mIconBoth = loader->loadIcon("theme"+QString::number(mOptions.mTheme)+"_both.png",
+ KIcon::Panel, ICONSIZE);
+ mCurrentIcon = &mIconNone;
+ }
+ mTimer->start(mOptions.mUpdateInterval);
+ updateStats();
+ QWidget::update();
+ mFirstUpdate = false;
+}
+
+void KNetStatsView::say(const QString& message) {
+ KPassivePopup::message(programName, message, kapp->miniIcon(), this);
+}
+
+void KNetStatsView::updateViewOptions() {
+ readOptions(mInterface, &mOptions);
+ setup();
+}
+
+void KNetStatsView::updateStats() {
+ FILE* flags_fp = fopen((mSysDevPath+"flags").latin1(), "r");
+ bool currentStatus;
+ if (!flags_fp)
+ currentStatus = false;
+ else {
+ int flags;
+ fscanf(flags_fp, "%Xu", &flags);
+ fclose(flags_fp);
+ currentStatus = IFF_UP & flags;
+ }
+
+ if (!currentStatus && mConnected) { // interface down...
+ mConnected = false;
+ resetBuffers();
+ QWidget::update();
+ say(i18n("%1 is inactive").arg(mInterface));
+ } else if (currentStatus && !mConnected) {
+ mConnected = true;
+ say(i18n("%1 is active").arg(mInterface));
+ }
+
+ // kernel < 2.6.9 (I think) does not have carrier info, considering carrier ever on.
+ FILE* carrier_fp = fopen((mSysDevPath+"carrier").latin1(), "r");
+ char carrierFlag = '1';
+ if (carrier_fp) {
+ carrierFlag = fgetc(carrier_fp);
+ fclose(carrier_fp);
+ }
+
+ if (!mConnected)
+ return;
+ if (carrierFlag == '0') { // carrier down
+ if (mCarrier) {
+ mCarrier = false;
+ QWidget::update();
+ say(i18n("%1 is disconnected").arg(mInterface));
+ }
+ return;
+ } else if (!mCarrier) { // carrier up
+ mCarrier = true;
+ say(i18n("%1 is connected").arg(mInterface));
+ }
+
+ unsigned int brx = readInterfaceNumValue("rx_bytes");
+ unsigned int btx = readInterfaceNumValue("tx_bytes");
+ unsigned int prx = readInterfaceNumValue("rx_packets");
+ unsigned int ptx = readInterfaceNumValue("tx_packets");
+
+
+ if (!mFirstUpdate) { // a primeira velocidade sempre eh absurda, para evitar isso temos o mFirstUpdate
+ if (++mSpeedBufferPtr >= SPEED_BUFFER_SIZE)
+ mSpeedBufferPtr = 0;
+
+ // Calcula as velocidades
+ mSpeedBufferTx[mSpeedBufferPtr] = ((btx - mBTx)*(1000.0f/mOptions.mUpdateInterval));
+ mSpeedBufferRx[mSpeedBufferPtr] = ((brx - mBRx)*(1000.0f/mOptions.mUpdateInterval));
+ mSpeedBufferPTx[mSpeedBufferPtr] = ((ptx - mPTx)*(1000.0f/mOptions.mUpdateInterval));
+ mSpeedBufferPRx[mSpeedBufferPtr] = ((prx - mPRx)*(1000.0f/mOptions.mUpdateInterval));
+
+ if (++mSpeedHistoryPtr >= HISTORY_SIZE)
+ mSpeedHistoryPtr = 0;
+ mSpeedHistoryRx[mSpeedHistoryPtr] = calcSpeed(mSpeedBufferRx);
+ mSpeedHistoryTx[mSpeedHistoryPtr] = calcSpeed(mSpeedBufferTx);
+
+ mMaxSpeedAge--;
+
+ if (mSpeedHistoryTx[mSpeedHistoryPtr] > mMaxSpeed) {
+ mMaxSpeed = mSpeedHistoryTx[mSpeedHistoryPtr];
+ mMaxSpeedAge = HISTORY_SIZE;
+ }
+ if (mSpeedHistoryRx[mSpeedHistoryPtr] > mMaxSpeed) {
+ mMaxSpeed = mSpeedHistoryRx[mSpeedHistoryPtr];
+ mMaxSpeedAge = HISTORY_SIZE;
+ }
+ if (mMaxSpeedAge < 1)
+ calcMaxSpeed();
+ }
+
+ if (mOptions.mViewMode == Icon) {
+ QPixmap* newIcon;
+ if (brx == mBRx) {
+ if (btx == mBTx )
+ newIcon = &mIconNone;
+ else
+ newIcon = &mIconTx;
+ } else {
+ if (btx == mBTx )
+ newIcon = &mIconRx;
+ else
+ newIcon = &mIconBoth;
+ }
+
+ if (newIcon != mCurrentIcon) {
+ mCurrentIcon = newIcon;
+ QWidget::update();
+ }
+ } else if (mOptions.mViewMode == Graphic || (btx != mBTx && brx != mBRx))
+ QWidget::update();
+
+ // Update stats
+ mTotalBytesRx += brx - mBRx;
+ mTotalBytesTx += btx - mBTx;
+ mTotalPktRx += prx - mPRx;
+ mTotalPktTx += ptx - mPTx;
+
+ mBRx = brx;
+ mBTx = btx;
+ mPRx = prx;
+ mPTx = ptx;
+}
+
+unsigned long KNetStatsView::readInterfaceNumValue(const char* name) {
+ // stdio functions appear to be more fast than QFile?
+ FILE* fp = fopen((mSysDevPath+"statistics/"+name).latin1(), "r");
+ long retval;
+ fscanf(fp, "%lu", &retval);
+ fclose(fp);
+ return retval;
+}
+
+QString KNetStatsView::readInterfaceStringValue(const char* name, int maxlength) {
+ QFile macFile(mSysDevPath+name);
+ macFile.open(IO_ReadOnly);
+ QString value;
+ macFile.readLine(value, maxlength);
+ return value;
+}
+
+void KNetStatsView::resetBuffers() {
+ memset(mSpeedHistoryRx, 0, sizeof(double)*HISTORY_SIZE);
+ memset(mSpeedHistoryTx, 0, sizeof(double)*HISTORY_SIZE);
+ memset(mSpeedBufferRx, 0, sizeof(double)*SPEED_BUFFER_SIZE);
+ memset(mSpeedBufferTx, 0, sizeof(double)*SPEED_BUFFER_SIZE);
+ memset(mSpeedBufferPRx, 0, sizeof(double)*SPEED_BUFFER_SIZE);
+ memset(mSpeedBufferPTx, 0, sizeof(double)*SPEED_BUFFER_SIZE);
+}
+
+void KNetStatsView::paintEvent( QPaintEvent* ) {
+ QPainter paint(this);
+ switch(mOptions.mViewMode) {
+ case Icon:
+ if (!mCarrier || !mConnected)
+ mCurrentIcon = &mIconError;
+ paint.drawPixmap(0, 0, *mCurrentIcon);
+ break;
+ case Text:
+ drawText(paint);
+ break;
+ case Graphic:
+ drawGraphic(paint);
+ break;
+ }
+}
+
+void KNetStatsView::drawText(QPainter& paint) {
+ if (!mCarrier || !mConnected) {
+ paint.drawText(rect(), Qt::AlignCenter, "?");
+ } else {
+ paint.setFont( mOptions.mTxtFont );
+ paint.setPen( mOptions.mTxtUplColor );
+ paint.drawText( rect(), Qt::AlignTop, Statistics::byteFormat(byteSpeedTx(), "KB", "MB"));
+ paint.setPen( mOptions.mTxtDldColor );
+ paint.drawText( rect(), Qt::AlignBottom, Statistics::byteFormat(byteSpeedRx(), "KB", "MB"));
+ }
+}
+
+void KNetStatsView::drawGraphic(QPainter& paint) {
+ if (!mCarrier || !mConnected) {
+ paint.drawText(rect(), Qt::AlignCenter, "X");
+ return;
+ }
+
+ QSize size = this->size();
+
+ if (!mOptions.mChartTransparentBackground)
+ paint.fillRect(0, 0, size.width(), size.height(), mOptions.mChartBgColor);
+
+ const int HEIGHT = size.height()-1;
+
+ // qDebug("MaxSpeed: %d, age: %d", int(mMaxSpeed), mMaxSpeedAge);
+ int lastX;
+ int lastRxY = HEIGHT - int(HEIGHT * (mSpeedHistoryRx[mSpeedHistoryPtr]/mMaxSpeed));
+ int lastTxY = HEIGHT - int(HEIGHT * (mSpeedHistoryTx[mSpeedHistoryPtr]/mMaxSpeed));
+ int x = lastX = size.width();
+ int count = 0;
+ for (int i = mSpeedHistoryPtr; count < width(); i--) {
+ if (i < 0)
+ i = HISTORY_SIZE-1;
+
+ int rxY = HEIGHT - int(HEIGHT * (mSpeedHistoryRx[i]/mMaxSpeed));
+ int txY = HEIGHT - int(HEIGHT * (mSpeedHistoryTx[i]/mMaxSpeed));
+ paint.setPen(mOptions.mChartDldColor);
+ paint.drawLine(lastX, lastRxY, x, rxY);
+ paint.setPen(mOptions.mChartUplColor);
+ paint.drawLine(lastX, lastTxY, x, txY);
+ //qDebug("%d => %d", i, int(mSpeedHistoryRx[i]));
+ lastX = x;
+ lastRxY = rxY;
+ lastTxY = txY;
+
+ count++;
+ x = width()-int(count+1);
+ }
+}
+
+void KNetStatsView::mousePressEvent(QMouseEvent* ev) {
+ if (ev->button() == Qt::RightButton )
+ mContextMenu->exec(QCursor::pos());
+ else if (ev->button() == Qt::LeftButton)
+ if (mStatistics->isShown())
+ mStatistics->accept();
+ else
+ mStatistics->show();
+}
+
+bool KNetStatsView::openFdSocket() {
+ if (mFdSock > 0)
+ return true;
+ if ((mFdSock = socket(AF_INET, SOCK_DGRAM, 0)) > 0)
+ return true;
+ return false;
+}
+
+QString KNetStatsView::getIp() {
+ if (mFdSock == -1 && !openFdSocket())
+ return "";
+
+ ioctl(mFdSock, SIOCGIFADDR, &mDevInfo);
+ sockaddr_in sin = ((sockaddr_in&)mDevInfo.ifr_addr);
+ return inet_ntoa(sin.sin_addr);
+}
+
+QString KNetStatsView::getNetmask() {
+ if (mFdSock == -1 && !openFdSocket())
+ return "";
+ ioctl(mFdSock, SIOCGIFNETMASK, &mDevInfo);
+ sockaddr_in mask = ((sockaddr_in&)mDevInfo.ifr_netmask);
+ return inet_ntoa(mask.sin_addr);
+}
+
+void KNetStatsView::readOptions( const QString& name, KNetStatsView::Options* opts, bool defaultVisibility ) {
+ KConfig* cfg = kapp->config();
+ KConfigGroupSaver groupSaver(cfg, name);
+
+ // general
+ opts->mUpdateInterval = cfg->readNumEntry("UpdateInterval", 300);
+ opts->mViewMode = (Mode)cfg->readNumEntry("ViewMode", 0);
+ opts->mMonitoring = cfg->readBoolEntry("Monitoring", defaultVisibility);
+ // txt view
+ opts->mTxtFont = cfg->readFontEntry("TxtFont");
+ opts->mTxtUplColor = cfg->readColorEntry("TxtUplColor", &Qt::red);
+ opts->mTxtDldColor = cfg->readColorEntry("TxtDldColor", &Qt::green);
+ // IconView
+ int defaultTheme = 0;
+ if (name.startsWith("wlan"))
+ defaultTheme = 3; // three... is a magic number... a magic number....
+ opts->mTheme = cfg->readNumEntry("Theme", defaultTheme);
+ // Graphic
+ opts->mChartUplColor = cfg->readColorEntry("ChartUplColor", &Qt::red);
+ opts->mChartDldColor = cfg->readColorEntry("ChartDldColor", &Qt::blue);
+ opts->mChartBgColor = cfg->readColorEntry("ChartBgColor", &Qt::white);
+ opts->mChartTransparentBackground = cfg->readBoolEntry("ChartUseTransparentBackground", true);
+}
+
+
+#include "knetstatsview.moc"