diff --git a/wpa_supplicant/doc/docbook/wpa_gui.sgml b/wpa_supplicant/doc/docbook/wpa_gui.sgml index fe9123624..5f7b49da0 100644 --- a/wpa_supplicant/doc/docbook/wpa_gui.sgml +++ b/wpa_supplicant/doc/docbook/wpa_gui.sgml @@ -16,6 +16,7 @@ wpa_gui -p path to ctrl sockets -i ifname + -m seconds -t -q @@ -51,6 +52,14 @@ a control socket in the socket path. + + -m seconds + + Set the update interval in seconds for the signal + strength meter. This value must be a positive integer, otherwise + meter is not enabled (default behavior). + + -t diff --git a/wpa_supplicant/wpa_gui-qt4/wpagui.cpp b/wpa_supplicant/wpa_gui-qt4/wpagui.cpp index bc6fa7f4a..408e3876c 100644 --- a/wpa_supplicant/wpa_gui-qt4/wpagui.cpp +++ b/wpa_supplicant/wpa_gui-qt4/wpagui.cpp @@ -135,6 +135,7 @@ WpaGui::WpaGui(QApplication *_app, QWidget *parent, const char *, Qt::WFlags) monitor_conn = NULL; msgNotifier = NULL; ctrl_iface_dir = strdup("/var/run/wpa_supplicant"); + signalMeterInterval = 0; parse_argv(); @@ -161,6 +162,10 @@ WpaGui::WpaGui(QApplication *_app, QWidget *parent, const char *, Qt::WFlags) timer->setSingleShot(FALSE); timer->start(1000); + signalMeterTimer = new QTimer(this); + signalMeterTimer->setInterval(signalMeterInterval); + connect(signalMeterTimer, SIGNAL(timeout()), SLOT(signalMeterUpdate())); + if (openCtrlConnection(ctrl_iface) < 0) { debug("Failed to open control connection to " "wpa_supplicant."); @@ -234,7 +239,7 @@ void WpaGui::parse_argv() { int c; for (;;) { - c = getopt(qApp->argc(), qApp->argv(), "i:p:tq"); + c = getopt(qApp->argc(), qApp->argv(), "i:m:p:tq"); if (c < 0) break; switch (c) { @@ -242,6 +247,9 @@ void WpaGui::parse_argv() free(ctrl_iface); ctrl_iface = strdup(optarg); break; + case 'm': + signalMeterInterval = atoi(optarg) * 1000; + break; case 'p': free(ctrl_iface_dir); ctrl_iface_dir = strdup(optarg); @@ -496,6 +504,8 @@ void WpaGui::updateStatus() textBssid->clear(); textIpAddress->clear(); updateTrayToolTip(tr("no status information")); + updateTrayIcon(TrayIconOffline); + signalMeterTimer->stop(); #ifdef CONFIG_NATIVE_WINDOWS static bool first = true; @@ -544,6 +554,11 @@ void WpaGui::updateStatus() ssid_updated = true; textSsid->setText(pos); updateTrayToolTip(pos + tr(" (associated)")); + if (!signalMeterInterval) { + /* if signal meter is not enabled show + * full signal strength */ + updateTrayIcon(TrayIconSignalExcellent); + } } else if (strcmp(start, "ip_address") == 0) { ipaddr_updated = true; textIpAddress->setText(pos); @@ -587,6 +602,23 @@ void WpaGui::updateStatus() } else textEncryption->clear(); + if (signalMeterInterval) { + /* + * Handle signal meter service. When network is not associated, + * deactivate timer, otherwise keep it going. Tray icon has to + * be initialized here, because of the initial delay of the + * timer. + */ + if (ssid_updated) { + if (!signalMeterTimer->isActive()) { + updateTrayIcon(TrayIconConnected); + signalMeterTimer->start(); + } + } else { + signalMeterTimer->stop(); + } + } + if (!status_updated) textStatus->clear(); if (!auth_updated) @@ -594,6 +626,7 @@ void WpaGui::updateStatus() if (!ssid_updated) { textSsid->clear(); updateTrayToolTip(tr("(not-associated)")); + updateTrayIcon(TrayIconOffline); } if (!bssid_updated) textBssid->clear(); @@ -828,6 +861,53 @@ void WpaGui::ping() } +void WpaGui::signalMeterUpdate() +{ + char reply[128]; + size_t reply_len = sizeof(reply); + char *rssi; + int rssi_value; + + ctrlRequest("SIGNAL_POLL", reply, &reply_len); + + /* In order to eliminate signal strength fluctuations, try + * to obtain averaged RSSI value in the first place. */ + if ((rssi = strstr(reply, "AVG_RSSI=")) != NULL) + rssi_value = atoi(&rssi[sizeof("AVG_RSSI")]); + else if ((rssi = strstr(reply, "RSSI=")) != NULL) + rssi_value = atoi(&rssi[sizeof("RSSI")]); + else { + debug("Failed to get RSSI value"); + updateTrayIcon(TrayIconSignalNone); + return; + } + + debug("RSSI value: %d", rssi_value); + + /* + * NOTE: The code below assumes, that the unit of the value returned + * by the SIGNAL POLL request is dBm. It might not be true for all + * wpa_supplicant drivers. + */ + + /* + * Calibration is based on "various Internet sources". Nonetheless, + * it seems to be compatible with the Windows 8.1 strength meter - + * tested on Intel Centrino Advanced-N 6235. + */ + if (rssi_value >= -60) + updateTrayIcon(TrayIconSignalExcellent); + else if (rssi_value >= -68) + updateTrayIcon(TrayIconSignalGood); + else if (rssi_value >= -76) + updateTrayIcon(TrayIconSignalOk); + else if (rssi_value >= -84) + updateTrayIcon(TrayIconSignalWeak); + else + updateTrayIcon(TrayIconSignalNone); +} + + static int str_match(const char *a, const char *b) { return strncmp(a, b, strlen(b)) == 0; @@ -1278,10 +1358,7 @@ void WpaGui::createTrayIcon(bool trayOnly) QApplication::setQuitOnLastWindowClosed(false); tray_icon = new QSystemTrayIcon(this); - if (QImageReader::supportedImageFormats().contains(QByteArray("svg"))) - tray_icon->setIcon(QIcon(":/icons/wpa_gui.svg")); - else - tray_icon->setIcon(QIcon(":/icons/wpa_gui.png")); + updateTrayIcon(TrayIconOffline); connect(tray_icon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), @@ -1421,6 +1498,59 @@ void WpaGui::updateTrayToolTip(const QString &msg) } +void WpaGui::updateTrayIcon(TrayIconType type) +{ + if (!tray_icon || currentIconType == type) + return; + + QIcon icon; + QIcon fallback_icon; + + if (QImageReader::supportedImageFormats().contains(QByteArray("svg"))) + fallback_icon = QIcon(":/icons/wpa_gui.svg"); + else + fallback_icon = QIcon(":/icons/wpa_gui.png"); + + switch (type) { + case TrayIconOffline: + icon = QIcon::fromTheme("network-wireless-offline", + fallback_icon); + break; + case TrayIconAcquiring: + icon = QIcon::fromTheme("network-wireless-acquiring", + fallback_icon); + break; + case TrayIconConnected: + icon = QIcon::fromTheme("network-wireless-connected", + fallback_icon); + break; + case TrayIconSignalNone: + icon = QIcon::fromTheme("network-wireless-signal-none", + fallback_icon); + break; + case TrayIconSignalWeak: + icon = QIcon::fromTheme("network-wireless-signal-weak", + fallback_icon); + break; + case TrayIconSignalOk: + icon = QIcon::fromTheme("network-wireless-signal-ok", + fallback_icon); + break; + case TrayIconSignalGood: + icon = QIcon::fromTheme("network-wireless-signal-good", + fallback_icon); + break; + case TrayIconSignalExcellent: + icon = QIcon::fromTheme("network-wireless-signal-excellent", + fallback_icon); + break; + } + + currentIconType = type; + tray_icon->setIcon(icon); +} + + void WpaGui::closeEvent(QCloseEvent *event) { if (eh) { diff --git a/wpa_supplicant/wpa_gui-qt4/wpagui.h b/wpa_supplicant/wpa_gui-qt4/wpagui.h index 026eacb92..c0de67b0d 100644 --- a/wpa_supplicant/wpa_gui-qt4/wpagui.h +++ b/wpa_supplicant/wpa_gui-qt4/wpagui.h @@ -22,6 +22,18 @@ class WpaGui : public QMainWindow, public Ui::WpaGui Q_OBJECT public: + + enum TrayIconType { + TrayIconOffline = 0, + TrayIconAcquiring, + TrayIconConnected, + TrayIconSignalNone, + TrayIconSignalWeak, + TrayIconSignalOk, + TrayIconSignalGood, + TrayIconSignalExcellent, + }; + WpaGui(QApplication *app, QWidget *parent = 0, const char *name = 0, Qt::WFlags fl = 0); ~WpaGui(); @@ -49,6 +61,7 @@ public slots: virtual void scan(); virtual void eventHistory(); virtual void ping(); + virtual void signalMeterUpdate(); virtual void processMsg(char *msg); virtual void processCtrlReq(const char *req); virtual void receiveMsgs(); @@ -70,6 +83,7 @@ public slots: virtual void showTrayMessage(QSystemTrayIcon::MessageIcon type, int sec, const QString &msg); virtual void showTrayStatus(); + virtual void updateTrayIcon(TrayIconType type); virtual void updateTrayToolTip(const QString &msg); virtual void wpsDialog(); virtual void peersDialog(); @@ -113,6 +127,7 @@ private: QAction *quitAction; QMenu *tray_menu; QSystemTrayIcon *tray_icon; + TrayIconType currentIconType; QString wpaStateTranslate(char *state); void createTrayIcon(bool); bool ackTrayIcon; @@ -127,6 +142,9 @@ private: void stopWpsRun(bool success); + QTimer *signalMeterTimer; + int signalMeterInterval; + #ifdef CONFIG_NATIVE_WINDOWS QAction *fileStartServiceAction; QAction *fileStopServiceAction;