wpa_gui-qt4: add system tray support

Add system tray icon support to wpa_gui-qt4. The tray icon remains quiet
when the main dialog is visible, so it should not cause too much pain for
more conservative users of wpa_gui. The addition involves the following
changes:

* when closing wpa_gui via window manager close box, wpa_gui close event is
  ignored and it is minimised to system tray. A status message is displayed
  (or popup dialog box if tray messages are not supported) to provide a
  visual hint that the program is still running in the background.
* add File->Exit slot handler to facilitate application quit from main
  dialog
* provide a context menu with a short list of useful actions
* show/hide main dialog when icon is triggered (single click)
* ensure main dialog is visible when event handler or scan results is
  chosen from tray icon context menu
* show tray messages on connected and disconnected events, display a status
  message a few seconds after connected events

Signed-off-by: Kel Modderman <kel@otaku42.de>
This commit is contained in:
Kel Modderman 2008-09-24 12:26:57 +03:00 committed by Jouni Malinen
parent 0fae9ad39b
commit b199b7e654
2 changed files with 189 additions and 1 deletions

View file

@ -37,7 +37,7 @@ WpaGui::WpaGui(QWidget *parent, const char *, Qt::WFlags)
SLOT(eventHistory())); SLOT(eventHistory()));
connect(fileSaveConfigAction, SIGNAL(triggered()), this, connect(fileSaveConfigAction, SIGNAL(triggered()), this,
SLOT(saveConfig())); SLOT(saveConfig()));
connect(fileExitAction, SIGNAL(triggered()), this, SLOT(close())); connect(fileExitAction, SIGNAL(triggered()), this, SLOT(fileExit()));
connect(networkAddAction, SIGNAL(triggered()), this, connect(networkAddAction, SIGNAL(triggered()), this,
SLOT(addNetwork())); SLOT(addNetwork()));
connect(networkEditAction, SIGNAL(triggered()), this, connect(networkEditAction, SIGNAL(triggered()), this,
@ -79,12 +79,16 @@ WpaGui::WpaGui(QWidget *parent, const char *, Qt::WFlags)
eh = NULL; eh = NULL;
scanres = NULL; scanres = NULL;
udr = NULL; udr = NULL;
tray_icon = NULL;
ctrl_iface = NULL; ctrl_iface = NULL;
ctrl_conn = NULL; ctrl_conn = NULL;
monitor_conn = NULL; monitor_conn = NULL;
msgNotifier = NULL; msgNotifier = NULL;
ctrl_iface_dir = strdup("/var/run/wpa_supplicant"); ctrl_iface_dir = strdup("/var/run/wpa_supplicant");
if (QSystemTrayIcon::isSystemTrayAvailable())
createTrayIcon();
parse_argv(); parse_argv();
textStatus->setText("connecting to wpa_supplicant"); textStatus->setText("connecting to wpa_supplicant");
@ -101,6 +105,9 @@ WpaGui::WpaGui(QWidget *parent, const char *, Qt::WFlags)
updateStatus(); updateStatus();
networkMayHaveChanged = true; networkMayHaveChanged = true;
updateNetworks(); updateNetworks();
if (tray_icon)
tray_icon->show();
} }
@ -588,6 +595,9 @@ void WpaGui::scan()
delete scanres; delete scanres;
} }
if (!isVisible())
show();
scanres = new ScanResults(); scanres = new ScanResults();
if (scanres == NULL) if (scanres == NULL)
return; return;
@ -604,6 +614,9 @@ void WpaGui::eventHistory()
delete eh; delete eh;
} }
if (!isVisible())
show();
eh = new EventHistory(); eh = new EventHistory();
if (eh == NULL) if (eh == NULL)
return; return;
@ -710,6 +723,14 @@ void WpaGui::processMsg(char *msg)
processCtrlReq(pos + strlen(WPA_CTRL_REQ)); processCtrlReq(pos + strlen(WPA_CTRL_REQ));
else if (str_match(pos, WPA_EVENT_SCAN_RESULTS) && scanres) else if (str_match(pos, WPA_EVENT_SCAN_RESULTS) && scanres)
scanres->updateResults(); scanres->updateResults();
else if (str_match(pos, WPA_EVENT_DISCONNECTED))
showTrayMessage(QSystemTrayIcon::Information, 3,
"Disconnected from network.");
else if (str_match(pos, WPA_EVENT_CONNECTED)) {
showTrayMessage(QSystemTrayIcon::Information, 3,
"Connection to network established.");
QTimer::singleShot(5 * 1000, this, SLOT(showTrayStatus()));
}
} }
@ -1070,6 +1091,134 @@ void WpaGui::selectAdapter( const QString & sel )
} }
void WpaGui::createTrayIcon()
{
tray_icon = new QSystemTrayIcon(this);
tray_icon->setToolTip(qAppName() + " - wpa_supplicant user interface");
tray_icon->setIcon(QIcon(":/icons/wpa_gui.svg"));
connect(tray_icon,
SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
this, SLOT(trayActivated(QSystemTrayIcon::ActivationReason)));
ackTrayIcon = false;
tray_menu = new QMenu(this);
disconnectAction = new QAction("&Disconnect", this);
reconnectAction = new QAction("Re&connect", this);
connect(disconnectAction, SIGNAL(triggered()), this,
SLOT(disconnect()));
connect(reconnectAction, SIGNAL(triggered()), this,
SLOT(connectB()));
tray_menu->addAction(disconnectAction);
tray_menu->addAction(reconnectAction);
tray_menu->addSeparator();
eventAction = new QAction("&Event History", this);
scanAction = new QAction("Scan &Results", this);
statAction = new QAction("S&tatus", this);
connect(eventAction, SIGNAL(triggered()), this, SLOT(eventHistory()));
connect(scanAction, SIGNAL(triggered()), this, SLOT(scan()));
connect(statAction, SIGNAL(triggered()), this, SLOT(showTrayStatus()));
tray_menu->addAction(eventAction);
tray_menu->addAction(scanAction);
tray_menu->addAction(statAction);
tray_menu->addSeparator();
showAction = new QAction("&Show Window", this);
hideAction = new QAction("&Hide Window", this);
quitAction = new QAction("&Quit", this);
connect(showAction, SIGNAL(triggered()), this, SLOT(show()));
connect(hideAction, SIGNAL(triggered()), this, SLOT(hide()));
connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
tray_menu->addAction(showAction);
tray_menu->addAction(hideAction);
tray_menu->addSeparator();
tray_menu->addAction(quitAction);
tray_icon->setContextMenu(tray_menu);
}
void WpaGui::showTrayMessage(QSystemTrayIcon::MessageIcon type, int sec,
const QString & msg)
{
if (!QSystemTrayIcon::supportsMessages())
return;
if (isVisible() || !tray_icon || !tray_icon->isVisible())
return;
tray_icon->showMessage(qAppName(), msg, type, sec * 1000);
}
void WpaGui::trayActivated(QSystemTrayIcon::ActivationReason how)
{
switch (how) {
/* use close() here instead of hide() and allow the
* custom closeEvent handler take care of children */
case QSystemTrayIcon::Trigger:
if (isVisible())
close();
else
show();
break;
case QSystemTrayIcon::MiddleClick:
showTrayStatus();
break;
default:
break;
}
}
void WpaGui::showTrayStatus()
{
char buf[2048];
size_t len;
len = sizeof(buf) - 1;
if (ctrlRequest("STATUS", buf, &len) < 0)
return;
buf[len] = '\0';
QString msg, status(buf);
QStringList lines = status.split(QRegExp("\\n"));
for (QStringList::Iterator it = lines.begin();
it != lines.end(); it++) {
int pos = (*it).indexOf('=') + 1;
if (pos < 1)
continue;
if ((*it).startsWith("bssid="))
msg.append("BSSID:\t" + (*it).mid(pos) + "\n");
else if ((*it).startsWith("ssid="))
msg.append("SSID: \t" + (*it).mid(pos) + "\n");
else if ((*it).startsWith("pairwise_cipher="))
msg.append("PAIR: \t" + (*it).mid(pos) + "\n");
else if ((*it).startsWith("group_cipher="))
msg.append("GROUP:\t" + (*it).mid(pos) + "\n");
else if ((*it).startsWith("key_mgmt="))
msg.append("AUTH: \t" + (*it).mid(pos) + "\n");
else if ((*it).startsWith("ip_address="))
msg.append("IP: \t" + (*it).mid(pos) + "\n");
}
showTrayMessage(QSystemTrayIcon::Information, 10, msg);
}
void WpaGui::fileExit()
{
if (tray_icon)
tray_icon->hide();
close();
}
void WpaGui::closeEvent(QCloseEvent *event) void WpaGui::closeEvent(QCloseEvent *event)
{ {
if (eh) { if (eh) {
@ -1090,5 +1239,26 @@ void WpaGui::closeEvent(QCloseEvent *event)
udr = NULL; udr = NULL;
} }
if (tray_icon && tray_icon->isVisible()) {
/* give user a visual hint that the tray icon exists */
if (QSystemTrayIcon::supportsMessages()) {
hide();
QTimer::singleShot(1 * 1000, this,
SLOT(showTrayStatus()));
} else if (!ackTrayIcon) {
QMessageBox::information(this, qAppName() + " systray",
"The program will keep "
"running in the system tray."
" To terminate the program, "
"choose <b>Quit</b> in the "
"context menu of the system "
"tray icon.");
ackTrayIcon = true;
hide();
}
event->ignore();
return;
}
event->accept(); event->accept();
} }

View file

@ -15,6 +15,7 @@
#ifndef WPAGUI_H #ifndef WPAGUI_H
#define WPAGUI_H #define WPAGUI_H
#include <QSystemTrayIcon>
#include <QObject> #include <QObject>
#include "ui_wpagui.h" #include "ui_wpagui.h"
@ -42,6 +43,7 @@ public slots:
virtual void parse_argv(); virtual void parse_argv();
virtual void updateStatus(); virtual void updateStatus();
virtual void updateNetworks(); virtual void updateNetworks();
virtual void fileExit();
virtual void helpIndex(); virtual void helpIndex();
virtual void helpContents(); virtual void helpContents();
virtual void helpAbout(); virtual void helpAbout();
@ -67,9 +69,13 @@ public slots:
virtual void updateNetworkDisabledStatus(); virtual void updateNetworkDisabledStatus();
virtual void enableListedNetwork(bool); virtual void enableListedNetwork(bool);
virtual void disableListedNetwork(bool); virtual void disableListedNetwork(bool);
virtual void showTrayMessage(QSystemTrayIcon::MessageIcon type,
int sec, const QString &msg);
virtual void showTrayStatus();
protected slots: protected slots:
virtual void languageChange(); virtual void languageChange();
virtual void trayActivated(QSystemTrayIcon::ActivationReason how);
virtual void closeEvent(QCloseEvent *event); virtual void closeEvent(QCloseEvent *event);
private: private:
@ -85,6 +91,18 @@ private:
char *ctrl_iface_dir; char *ctrl_iface_dir;
struct wpa_ctrl *monitor_conn; struct wpa_ctrl *monitor_conn;
UserDataRequest *udr; UserDataRequest *udr;
QAction *disconnectAction;
QAction *reconnectAction;
QAction *eventAction;
QAction *scanAction;
QAction *statAction;
QAction *showAction;
QAction *hideAction;
QAction *quitAction;
QMenu *tray_menu;
QSystemTrayIcon *tray_icon;
void createTrayIcon();
bool ackTrayIcon;
int openCtrlConnection(const char *ifname); int openCtrlConnection(const char *ifname);
}; };