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:
parent
0fae9ad39b
commit
b199b7e654
2 changed files with 189 additions and 1 deletions
|
@ -37,7 +37,7 @@ WpaGui::WpaGui(QWidget *parent, const char *, Qt::WFlags)
|
|||
SLOT(eventHistory()));
|
||||
connect(fileSaveConfigAction, SIGNAL(triggered()), this,
|
||||
SLOT(saveConfig()));
|
||||
connect(fileExitAction, SIGNAL(triggered()), this, SLOT(close()));
|
||||
connect(fileExitAction, SIGNAL(triggered()), this, SLOT(fileExit()));
|
||||
connect(networkAddAction, SIGNAL(triggered()), this,
|
||||
SLOT(addNetwork()));
|
||||
connect(networkEditAction, SIGNAL(triggered()), this,
|
||||
|
@ -79,12 +79,16 @@ WpaGui::WpaGui(QWidget *parent, const char *, Qt::WFlags)
|
|||
eh = NULL;
|
||||
scanres = NULL;
|
||||
udr = NULL;
|
||||
tray_icon = NULL;
|
||||
ctrl_iface = NULL;
|
||||
ctrl_conn = NULL;
|
||||
monitor_conn = NULL;
|
||||
msgNotifier = NULL;
|
||||
ctrl_iface_dir = strdup("/var/run/wpa_supplicant");
|
||||
|
||||
if (QSystemTrayIcon::isSystemTrayAvailable())
|
||||
createTrayIcon();
|
||||
|
||||
parse_argv();
|
||||
|
||||
textStatus->setText("connecting to wpa_supplicant");
|
||||
|
@ -101,6 +105,9 @@ WpaGui::WpaGui(QWidget *parent, const char *, Qt::WFlags)
|
|||
updateStatus();
|
||||
networkMayHaveChanged = true;
|
||||
updateNetworks();
|
||||
|
||||
if (tray_icon)
|
||||
tray_icon->show();
|
||||
}
|
||||
|
||||
|
||||
|
@ -588,6 +595,9 @@ void WpaGui::scan()
|
|||
delete scanres;
|
||||
}
|
||||
|
||||
if (!isVisible())
|
||||
show();
|
||||
|
||||
scanres = new ScanResults();
|
||||
if (scanres == NULL)
|
||||
return;
|
||||
|
@ -604,6 +614,9 @@ void WpaGui::eventHistory()
|
|||
delete eh;
|
||||
}
|
||||
|
||||
if (!isVisible())
|
||||
show();
|
||||
|
||||
eh = new EventHistory();
|
||||
if (eh == NULL)
|
||||
return;
|
||||
|
@ -710,6 +723,14 @@ void WpaGui::processMsg(char *msg)
|
|||
processCtrlReq(pos + strlen(WPA_CTRL_REQ));
|
||||
else if (str_match(pos, WPA_EVENT_SCAN_RESULTS) && scanres)
|
||||
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)
|
||||
{
|
||||
if (eh) {
|
||||
|
@ -1090,5 +1239,26 @@ void WpaGui::closeEvent(QCloseEvent *event)
|
|||
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();
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#ifndef WPAGUI_H
|
||||
#define WPAGUI_H
|
||||
|
||||
#include <QSystemTrayIcon>
|
||||
#include <QObject>
|
||||
#include "ui_wpagui.h"
|
||||
|
||||
|
@ -42,6 +43,7 @@ public slots:
|
|||
virtual void parse_argv();
|
||||
virtual void updateStatus();
|
||||
virtual void updateNetworks();
|
||||
virtual void fileExit();
|
||||
virtual void helpIndex();
|
||||
virtual void helpContents();
|
||||
virtual void helpAbout();
|
||||
|
@ -67,9 +69,13 @@ public slots:
|
|||
virtual void updateNetworkDisabledStatus();
|
||||
virtual void enableListedNetwork(bool);
|
||||
virtual void disableListedNetwork(bool);
|
||||
virtual void showTrayMessage(QSystemTrayIcon::MessageIcon type,
|
||||
int sec, const QString &msg);
|
||||
virtual void showTrayStatus();
|
||||
|
||||
protected slots:
|
||||
virtual void languageChange();
|
||||
virtual void trayActivated(QSystemTrayIcon::ActivationReason how);
|
||||
virtual void closeEvent(QCloseEvent *event);
|
||||
|
||||
private:
|
||||
|
@ -85,6 +91,18 @@ private:
|
|||
char *ctrl_iface_dir;
|
||||
struct wpa_ctrl *monitor_conn;
|
||||
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);
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue