/******************************************************************************\
* Copyright (c) 2004-2020
*
* Author(s):
* Volker Fischer
*
******************************************************************************
*
* 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 "serverdlg.h"
/* Implementation *************************************************************/
CServerDlg::CServerDlg ( CServer* pNServP,
CSettings* pNSetP,
const bool bStartMinimized,
QWidget* parent,
Qt::WindowFlags f )
: QDialog ( parent, f ),
pServer ( pNServP ),
pSettings ( pNSetP ),
BitmapSystemTrayInactive ( QString::fromUtf8 ( ":/png/LEDs/res/CLEDGreyArrow.png" ) ),
BitmapSystemTrayActive ( QString::fromUtf8 ( ":/png/LEDs/res/CLEDGreenArrow.png" ) )
{
setupUi ( this );
// Add help text to controls -----------------------------------------------
// client list
lvwClients->setWhatsThis ( "" + tr ( "Client List" ) + ": " + tr (
"The client list shows all clients which are currently connected to this "
"server. Some information about the clients like the IP address and name "
"are given for each connected client." ) );
lvwClients->setAccessibleName ( tr ( "Connected clients list view" ) );
// start minimized on operating system start
chbStartOnOSStart->setWhatsThis ( "" + tr ( "Start Minimized on Operating "
"System Start" ) + ": " + tr ( "If the start minimized on operating system start "
"check box is checked, the server will be "
"started when the operating system starts up and is automatically "
"minimized to a system task bar icon." ) );
// CC licence dialog switch
chbUseCCLicence->setWhatsThis ( "" + tr ( "Show Creative Commons Licence "
"Dialog" ) + ": " + tr ( "If enabled, a Creative Commons BY-NC-SA 4.0 Licence "
"dialog is shown each time a new user connects the server." ) );
// Make My Server Public flag
chbRegisterServer->setWhatsThis ( "" + tr ( "Make My Server Public" ) + ": " +
tr ( "If the Make My Server Public check box is checked, this server registers "
"itself at the central server so that all users of the application "
"can see the server in the connect dialog server list and "
"connect to it. The registration of the server is renewed periodically "
"to make sure that all servers in the connect dialog server list are "
"actually available." ) );
// register server status label
lblRegSvrStatus->setWhatsThis ( "" + tr ( "Register Server Status" ) + ": " +
tr ( "If the Make My Server Public check box is checked, this will show "
"whether registration with the central server is successful. If the "
"registration failed, please choose another server list." ) );
// custom central server address
QString strCentrServAddr = "" + tr ( "Custom Central Server Address" ) + ": " +
tr ( "The custom central server address is the IP address or URL of the central "
"server at which the server list of the connection dialog is managed." );
lblCentralServerAddress->setWhatsThis ( strCentrServAddr );
edtCentralServerAddress->setWhatsThis ( strCentrServAddr );
edtCentralServerAddress->setAccessibleName ( tr ( "Central server address line edit" ) );
cbxCentServAddrType->setWhatsThis ( "" + tr ( "Server List Selection" ) + ": " + tr (
"Selects the server list (i.e. central server address) in which your server will be added." ) );
cbxCentServAddrType->setAccessibleName ( tr ( "Server list selection combo box" ) );
// server name
QString strServName = "" + tr ( "Server Name" ) + ": " + tr ( "The server name identifies "
"your server in the connect dialog server list at the clients." );
lblServerName->setWhatsThis ( strServName );
edtServerName->setWhatsThis ( strServName );
edtServerName->setAccessibleName ( tr ( "Server name line edit" ) );
// location city
QString strLocCity = "" + tr ( "Location City" ) + ": " + tr ( "The city in which this "
"server is located can be set here. If a city name is entered, it "
"will be shown in the connect dialog server list at the clients." );
lblLocationCity->setWhatsThis ( strLocCity );
edtLocationCity->setWhatsThis ( strLocCity );
edtLocationCity->setAccessibleName ( tr ( "City where the server is located line edit" ) );
// location country
QString strLocCountry = "" + tr ( "Location country" ) + ": " + tr ( "The country in "
"which this server is located can be set here. If a country is "
"entered, it will be shown in the connect dialog server list at the "
"clients." );
lblLocationCountry->setWhatsThis ( strLocCountry );
cbxLocationCountry->setWhatsThis ( strLocCountry );
cbxLocationCountry->setAccessibleName ( tr (
"Country where the server is located combo box" ) );
// enable recorder
chbEnableRecorder->setAccessibleName( tr ( "Checkbox to turn on or off server recording" ) );
chbEnableRecorder->setWhatsThis( "" + tr ( "Enable Recorder" ) + ":"
+ tr ( "Checked when the recorder is enabled, otherwise unchecked. "
"The recorder will run when a session is in progress, if (set up correctly and) enabled." ) );
// current session directory
edtCurrentSessionDir->setAccessibleName( tr ( "Current session directory text box (read-only)" ) );
edtCurrentSessionDir->setWhatsThis( "" + tr ( "Current Session Directory" ) + ":"
+ tr ( "Enabled during recording and holds the current recording session directory. "
"Disabled after recording or when the recorder is not enabled." ) );
// recorder status
lblRecorderStatus->setAccessibleName ( tr ( "Recorder status label" ) );
lblRecorderStatus->setWhatsThis ( "" + tr ( "Recorder Status" ) + ":"
+ tr ( "Displays the current status of the recorder." ) );
// new recording
pbtNewRecording->setAccessibleName ( tr ( "Request new recording button" ) );
pbtNewRecording->setWhatsThis ( "" + tr ( "New Recording" ) + ":"
+ tr ( "During a recording session, the button can be used to start a new recording." ) );
// check if system tray icon can be used
bSystemTrayIconAvaialbe = SystemTrayIcon.isSystemTrayAvailable();
// init system tray icon
if ( bSystemTrayIconAvaialbe )
{
// prepare context menu to be added to the system tray icon
pSystemTrayIconMenu = new QMenu ( this );
pSystemTrayIconMenu->addAction ( tr ( "E&xit" ),
this, SLOT ( OnSysTrayMenuExit() ) );
pSystemTrayIconMenu->addSeparator();
pSystemTrayIconMenu->addAction (
tr ( "&Hide " ) + APP_NAME + tr ( " server" ),
this, SLOT ( OnSysTrayMenuHide() ) );
pSystemTrayIconMenu->setDefaultAction ( pSystemTrayIconMenu->addAction (
tr ( "&Open " ) + APP_NAME + tr ( " server" ),
this, SLOT ( OnSysTrayMenuOpen() ) ) );
SystemTrayIcon.setContextMenu ( pSystemTrayIconMenu );
// set tool text
SystemTrayIcon.setToolTip ( QString ( APP_NAME ) + tr ( " server" ) );
// show icon of state "inactive"
SystemTrayIcon.setIcon ( QIcon ( BitmapSystemTrayInactive ) );
SystemTrayIcon.show();
}
// act on "start minimized" flag (note, this has to be done after setting
// the correct value for the system tray icon availablility)
if ( bStartMinimized )
{
showMinimized();
}
// set text for version and application name
lblNameVersion->setText ( QString ( APP_NAME ) +
tr ( " server " ) + QString ( VERSION ) );
// set up list view for connected clients
lvwClients->setColumnWidth ( 0, 170 );
lvwClients->setColumnWidth ( 1, 200 );
lvwClients->clear();
// TEST workaround for resize problem of window after iconize in task bar
lvwClients->setMinimumWidth ( 170 + 130 + 60 + 205 );
lvwClients->setMinimumHeight ( 140 );
// insert items in reverse order because in Windows all of them are
// always visible -> put first item on the top
vecpListViewItems.Init ( MAX_NUM_CHANNELS );
for ( int i = MAX_NUM_CHANNELS - 1; i >= 0; i-- )
{
vecpListViewItems[i] = new QTreeWidgetItem ( lvwClients );
vecpListViewItems[i]->setHidden ( true );
}
// central server address type combo box
cbxCentServAddrType->clear();
cbxCentServAddrType->addItem ( csCentServAddrTypeToString ( AT_DEFAULT ) );
cbxCentServAddrType->addItem ( csCentServAddrTypeToString ( AT_ALL_GENRES ) );
cbxCentServAddrType->addItem ( csCentServAddrTypeToString ( AT_GENRE_ROCK ) );
cbxCentServAddrType->addItem ( csCentServAddrTypeToString ( AT_GENRE_JAZZ ) );
cbxCentServAddrType->addItem ( csCentServAddrTypeToString ( AT_GENRE_CLASSICAL_FOLK ) );
cbxCentServAddrType->addItem ( csCentServAddrTypeToString ( AT_CUSTOM ) );
cbxCentServAddrType->setCurrentIndex ( static_cast ( pServer->GetCentralServerAddressType() ) );
// update server name line edit
edtServerName->setText ( pServer->GetServerName() );
// update server city line edit
edtLocationCity->setText ( pServer->GetServerCity() );
// load country combo box with all available countries
cbxLocationCountry->setInsertPolicy ( QComboBox::NoInsert );
cbxLocationCountry->clear();
for ( int iCurCntry = static_cast ( QLocale::AnyCountry );
iCurCntry < static_cast ( QLocale::LastCountry ); iCurCntry++ )
{
// add all countries except of the "Default" country
if ( static_cast ( iCurCntry ) != QLocale::AnyCountry )
{
// store the country enum index together with the string (this is
// important since we sort the combo box items later on)
cbxLocationCountry->addItem ( QLocale::countryToString (
static_cast ( iCurCntry ) ), iCurCntry );
}
}
// sort country combo box items in alphabetical order
cbxLocationCountry->model()->sort ( 0, Qt::AscendingOrder );
// select current country
cbxLocationCountry->setCurrentIndex (
cbxLocationCountry->findData (
static_cast ( pServer->GetServerCountry() ) ) );
// update register server check box
if ( pServer->GetServerListEnabled() )
{
chbRegisterServer->setCheckState ( Qt::Checked );
}
else
{
chbRegisterServer->setCheckState ( Qt::Unchecked );
}
// update show Creative Commons licence check box
if ( pServer->GetLicenceType() == LT_CREATIVECOMMONS )
{
chbUseCCLicence->setCheckState ( Qt::Checked );
}
else
{
chbUseCCLicence->setCheckState ( Qt::Unchecked );
}
// update start minimized check box (only available for Windows)
#ifndef _WIN32
chbStartOnOSStart->setVisible ( false );
#else
const bool bCurAutoStartMinState = pServer->GetAutoRunMinimized();
if ( bCurAutoStartMinState )
{
chbStartOnOSStart->setCheckState ( Qt::Checked );
}
else
{
chbStartOnOSStart->setCheckState ( Qt::Unchecked );
}
// modify registry according to setting (this is just required in case a
// user has changed the registry by hand)
ModifyAutoStartEntry ( bCurAutoStartMinState );
#endif
// Recorder controls
if ( !pServer->GetRecorderInitialised() )
{
// The recorder was not initialised successfully from the command line
// TODO: Once initialising from the GUI is implemented, remove
chbEnableRecorder->setVisible ( false );
edtCurrentSessionDir->setVisible ( false );
lblRecorderStatus->setVisible ( false );
pbtNewRecording->setVisible ( false );
}
edtCurrentSessionDir->setText ( "" );
pbtNewRecording->setAutoDefault ( false );
// TODO: Not yet implemented, so hide them!
pbtRecordingDir->setVisible ( false );
edtRecordingsDir->setVisible ( false );
UpdateRecorderStatus ( QString::null );
// update GUI dependencies
UpdateGUIDependencies();
// set window title
setWindowTitle ( APP_NAME + tr ( " Server" ) );
// View menu --------------------------------------------------------------
QMenu* pViewMenu = new QMenu ( tr ( "&Window" ), this );
pViewMenu->addAction ( tr ( "E&xit" ), this,
SLOT ( close() ), QKeySequence ( Qt::CTRL + Qt::Key_Q ) );
// Main menu bar -----------------------------------------------------------
pMenu = new QMenuBar ( this );
pMenu->addMenu ( pViewMenu );
pMenu->addMenu ( new CHelpMenu ( false, this ) );
// Now tell the layout about the menu
layout()->setMenuBar ( pMenu );
// Window positions --------------------------------------------------------
// main window
if ( !pServer->vecWindowPosMain.isEmpty() && !pServer->vecWindowPosMain.isNull() )
{
restoreGeometry ( pServer->vecWindowPosMain );
}
// Connections -------------------------------------------------------------
// check boxes
QObject::connect ( chbRegisterServer, &QCheckBox::stateChanged,
this, &CServerDlg::OnRegisterServerStateChanged );
QObject::connect ( chbStartOnOSStart, &QCheckBox::stateChanged,
this, &CServerDlg::OnStartOnOSStartStateChanged );
QObject::connect ( chbUseCCLicence, &QCheckBox::stateChanged,
this, &CServerDlg::OnUseCCLicenceStateChanged );
QObject::connect ( chbEnableRecorder, &QCheckBox::stateChanged,
this, &CServerDlg::OnEnableRecorderStateChanged );
// line edits
QObject::connect ( edtCentralServerAddress, &QLineEdit::editingFinished,
this, &CServerDlg::OnCentralServerAddressEditingFinished );
QObject::connect ( edtServerName, &QLineEdit::textChanged,
this, &CServerDlg::OnServerNameTextChanged );
QObject::connect ( edtLocationCity, &QLineEdit::textChanged,
this, &CServerDlg::OnLocationCityTextChanged );
// combo boxes
QObject::connect ( cbxLocationCountry, static_cast ( &QComboBox::activated ),
this, &CServerDlg::OnLocationCountryActivated );
QObject::connect ( cbxCentServAddrType, static_cast ( &QComboBox::activated ),
this, &CServerDlg::OnCentServAddrTypeActivated );
// push buttons
QObject::connect ( pbtNewRecording, &QPushButton::released,
this, &CServerDlg::OnNewRecordingClicked );
// timers
QObject::connect ( &Timer, &QTimer::timeout,
this, &CServerDlg::OnTimer );
// other
QObject::connect ( pServer, &CServer::Started,
this, &CServerDlg::OnServerStarted );
QObject::connect ( pServer, &CServer::Stopped,
this, &CServerDlg::OnServerStopped );
QObject::connect ( pServer, &CServer::SvrRegStatusChanged,
this, &CServerDlg::OnSvrRegStatusChanged );
QObject::connect ( pServer, &CServer::RecordingSessionStarted,
this, &CServerDlg::OnRecordingSessionStarted );
QObject::connect ( pServer, &CServer::StopRecorder,
this, &CServerDlg::OnStopRecorder );
QObject::connect ( QCoreApplication::instance(), &QCoreApplication::aboutToQuit,
this, &CServerDlg::OnAboutToQuit );
QObject::connect ( &SystemTrayIcon, &QSystemTrayIcon::activated,
this, &CServerDlg::OnSysTrayActivated );
// Timers ------------------------------------------------------------------
// start timer for GUI controls
Timer.start ( GUI_CONTRL_UPDATE_TIME );
}
void CServerDlg::closeEvent ( QCloseEvent* Event )
{
// store window positions
pServer->vecWindowPosMain = saveGeometry();
// default implementation of this event handler routine
Event->accept();
}
void CServerDlg::OnStartOnOSStartStateChanged ( int value )
{
const bool bCurAutoStartMinState = ( value == Qt::Checked );
// update registry and server setting (for ini file)
pServer->SetAutoRunMinimized ( bCurAutoStartMinState );
ModifyAutoStartEntry ( bCurAutoStartMinState );
}
void CServerDlg::OnUseCCLicenceStateChanged ( int value )
{
if ( value == Qt::Checked )
{
pServer->SetLicenceType ( LT_CREATIVECOMMONS );
}
else
{
pServer->SetLicenceType ( LT_NO_LICENCE );
}
}
void CServerDlg::OnRegisterServerStateChanged ( int value )
{
const bool bRegState = ( value == Qt::Checked );
// apply new setting to the server and update it
pServer->SetServerListEnabled ( bRegState );
// if registering is disabled, unregister slave server
if ( !bRegState )
{
pServer->UnregisterSlaveServer();
}
pServer->UpdateServerList();
// update GUI dependencies
UpdateGUIDependencies();
}
void CServerDlg::OnCentralServerAddressEditingFinished()
{
// apply new setting to the server and update it
pServer->SetServerListCentralServerAddress (
edtCentralServerAddress->text() );
pServer->UpdateServerList();
}
void CServerDlg::OnServerNameTextChanged ( const QString& strNewName )
{
// check length
if ( strNewName.length() <= MAX_LEN_SERVER_NAME )
{
// apply new setting to the server and update it
pServer->SetServerName ( strNewName );
pServer->UpdateServerList();
}
else
{
// text is too long, update control with shortend text
edtServerName->setText ( strNewName.left ( MAX_LEN_SERVER_NAME ) );
}
}
void CServerDlg::OnLocationCityTextChanged ( const QString& strNewCity )
{
// check length
if ( strNewCity.length() <= MAX_LEN_SERVER_CITY )
{
// apply new setting to the server and update it
pServer->SetServerCity ( strNewCity );
pServer->UpdateServerList();
}
else
{
// text is too long, update control with shortend text
edtLocationCity->setText ( strNewCity.left ( MAX_LEN_SERVER_CITY ) );
}
}
void CServerDlg::OnLocationCountryActivated ( int iCntryListItem )
{
// apply new setting to the server and update it
pServer->SetServerCountry ( static_cast (
cbxLocationCountry->itemData ( iCntryListItem ).toInt() ) );
pServer->UpdateServerList();
}
void CServerDlg::OnCentServAddrTypeActivated ( int iTypeIdx )
{
// if server was registered, unregister first
if ( pServer->GetServerListEnabled() )
{
pServer->UnregisterSlaveServer();
}
// apply new setting to the server and update it
pServer->SetCentralServerAddressType ( static_cast ( iTypeIdx ) );
pServer->UpdateServerList();
// update GUI dependencies
UpdateGUIDependencies();
}
void CServerDlg::OnServerStarted()
{
UpdateSystemTrayIcon ( true );
UpdateRecorderStatus ( QString::null );
}
void CServerDlg::OnServerStopped()
{
UpdateSystemTrayIcon ( false );
UpdateRecorderStatus ( QString::null );
}
void CServerDlg::OnStopRecorder()
{
UpdateRecorderStatus ( QString::null );
}
void CServerDlg::OnSysTrayActivated ( QSystemTrayIcon::ActivationReason ActReason )
{
// on double click on the icon, show window in fore ground
if ( ActReason == QSystemTrayIcon::DoubleClick )
{
ShowWindowInForeground();
}
}
void CServerDlg::OnTimer()
{
CVector vecHostAddresses;
CVector vecsName;
CVector veciJitBufNumFrames;
CVector veciNetwFrameSizeFact;
ListViewMutex.lock();
{
pServer->GetConCliParam ( vecHostAddresses,
vecsName,
veciJitBufNumFrames,
veciNetwFrameSizeFact );
// we assume that all vectors have the same length
const int iNumChannels = vecHostAddresses.Size();
// fill list with connected clients
for ( int i = 0; i < iNumChannels; i++ )
{
if ( !( vecHostAddresses[i].InetAddr == QHostAddress ( static_cast ( 0 ) ) ) )
{
// IP, port number
vecpListViewItems[i]->setText ( 0,
vecHostAddresses[i].toString ( CHostAddress::SM_IP_PORT ) );
// name
vecpListViewItems[i]->setText ( 1, vecsName[i] );
// jitter buffer size (polling for updates)
vecpListViewItems[i]->setText ( 2,
QString().setNum ( veciJitBufNumFrames[i] ) );
vecpListViewItems[i]->setHidden ( false );
}
else
{
vecpListViewItems[i]->setHidden ( true );
}
}
}
ListViewMutex.unlock();
}
void CServerDlg::UpdateGUIDependencies()
{
// get the states which define the GUI dependencies from the server
const bool bCurSerListEnabled = pServer->GetServerListEnabled();
const bool bCurUseDefCentServAddr = ( pServer->GetCentralServerAddressType() != AT_CUSTOM );
const ESvrRegStatus eSvrRegStatus = pServer->GetSvrRegStatus();
// if register server is not enabled, we disable all the configuration
// controls for the server list
cbxCentServAddrType->setEnabled ( bCurSerListEnabled );
grbServerInfo->setEnabled ( bCurSerListEnabled );
// make sure the line edit does not fire signals when we update the text
edtCentralServerAddress->blockSignals ( true );
{
if ( bCurUseDefCentServAddr )
{
// if the default central server is used, just show a text of the
// server name
edtCentralServerAddress->setText ( tr ( "Predefined Address" ) );
}
else
{
// show the current user defined server address
edtCentralServerAddress->setText (
pServer->GetServerListCentralServerAddress() );
}
}
edtCentralServerAddress->blockSignals ( false );
// the line edit of the central server address is only enabled, if the
// server list is enabled and not the default address is used
edtCentralServerAddress->setEnabled (
!bCurUseDefCentServAddr && bCurSerListEnabled );
QString strStatus = svrRegStatusToString ( eSvrRegStatus );
switch ( eSvrRegStatus )
{
case SRS_BAD_ADDRESS:
case SRS_TIME_OUT:
case SRS_CENTRAL_SVR_FULL:
strStatus = "" + strStatus + "";
break;
case SRS_REGISTERED:
strStatus = "" + strStatus + "";
break;
default:
break;
}
lblRegSvrStatus->setText ( strStatus );
}
void CServerDlg::UpdateSystemTrayIcon ( const bool bIsActive )
{
if ( bSystemTrayIconAvaialbe )
{
if ( bIsActive )
{
SystemTrayIcon.setIcon ( QIcon ( BitmapSystemTrayActive ) );
}
else
{
SystemTrayIcon.setIcon ( QIcon ( BitmapSystemTrayInactive ) );
}
}
}
void CServerDlg::ModifyAutoStartEntry ( const bool bDoAutoStart )
{
// auto start is currently only supported for Windows
#ifdef _WIN32
// init settings object so that it points to the correct place in the
// Windows registry for the auto run entry
QSettings RegSettings ( "HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run",
QSettings::NativeFormat );
// create start string of auto run entry
QString strRegValue =
QCoreApplication::applicationFilePath().replace ( "/", "\\" ) +
" -s --startminimized";
#endif
if ( bDoAutoStart )
{
#ifdef _WIN32
// ckeck if registry entry is correctly present, if not, correct
const bool bWriteRegValue = strRegValue.compare (
RegSettings.value ( AUTORUN_SERVER_REG_NAME ).toString() );
if ( bWriteRegValue )
{
// write reg key in the registry
RegSettings.setValue ( AUTORUN_SERVER_REG_NAME, strRegValue );
}
#endif
}
else
{
#ifdef _WIN32
// delete reg key if present
if ( RegSettings.contains ( AUTORUN_SERVER_REG_NAME ) )
{
RegSettings.remove ( AUTORUN_SERVER_REG_NAME );
}
#endif
}
}
void CServerDlg::UpdateRecorderStatus ( QString sessionDir )
{
if ( !pServer->GetRecorderInitialised() )
{
// everything should be hidden.
return;
}
Qt::CheckState csIsEnabled;
QString currentSessionDir = edtCurrentSessionDir->text();
bool bIsRecording = false;
QString strRecorderStatus;
if ( pServer->GetRecordingEnabled() )
{
csIsEnabled = Qt::CheckState::Checked;
if ( pServer->IsRunning() )
{
currentSessionDir = sessionDir != QString::null ? sessionDir : "";
strRecorderStatus = tr ( "Recording" );
bIsRecording = true;
}
else
{
strRecorderStatus = tr ( "Not recording" );
}
}
else
{
csIsEnabled = Qt::CheckState::Unchecked;
strRecorderStatus = tr ( "Not enabled" );
}
chbEnableRecorder->setCheckState ( csIsEnabled );
edtCurrentSessionDir->setEnabled ( bIsRecording );
edtCurrentSessionDir->setText ( currentSessionDir );
lblRecorderStatus->setText ( strRecorderStatus );
pbtNewRecording->setEnabled ( bIsRecording );
}
void CServerDlg::changeEvent ( QEvent* pEvent )
{
// if we have a system tray icon, we make the window invisible if it is
// minimized
if ( bSystemTrayIconAvaialbe &&
( pEvent->type() == QEvent::WindowStateChange ) )
{
if ( isMinimized() )
{
// we have to call the hide function from another thread -> use
// the timer for this purpose
QTimer::singleShot ( 0, this, SLOT ( hide() ) );
}
}
}