From 6534027c5ce5579c4293aa346cadf0850aa02157 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Wed, 19 Oct 2016 23:56:34 +0200 Subject: Implement "Attention" feature (virtual hand-raising) --- src/client/informationdialog/informationdialog.cpp | 3 +- src/client/net/serverconnection.cpp | 29 ++++++++++---- src/client/net/serverconnection.h | 3 +- src/client/toolbar/toolbar.cpp | 46 +++++++++++++++++----- src/client/toolbar/toolbar.h | 3 +- src/server/connectionframe/connectionframe.cpp | 16 +++++++- src/server/connectionframe/connectionframe.h | 5 --- src/server/mainwindow/mainwindow.cpp | 10 +++-- src/server/net/client.cpp | 21 +++++++--- src/server/net/client.h | 6 ++- src/shared/networkmessage.h | 1 + 11 files changed, 106 insertions(+), 37 deletions(-) (limited to 'src') diff --git a/src/client/informationdialog/informationdialog.cpp b/src/client/informationdialog/informationdialog.cpp index 6a8a6b7..275259b 100644 --- a/src/client/informationdialog/informationdialog.cpp +++ b/src/client/informationdialog/informationdialog.cpp @@ -31,9 +31,10 @@ void InformationDialog::initTable() _tableLayout->addRow(new QLabel(tr("hostname")), new QLabel(QHostInfo::localHostName())); /* ips */ for (QHostAddress a : QNetworkInterface::allAddresses()) { + if (a == QHostAddress::Null || a == QHostAddress::Broadcast || a == QHostAddress::LocalHost || a == QHostAddress::AnyIPv6) + continue; QString ip = a.toString(); - if (ip == "::1" || ip == "127.0.0.1") { continue;} QLabel* label = new QLabel(tr("IP") ); QLabel* value = new QLabel(ip); diff --git a/src/client/net/serverconnection.cpp b/src/client/net/serverconnection.cpp index 1275921..02c35fd 100644 --- a/src/client/net/serverconnection.cpp +++ b/src/client/net/serverconnection.cpp @@ -66,6 +66,14 @@ void ServerConnection::sendMessage(NetworkMessage& message) } } +void ServerConnection::sendAttention(bool on) +{ + NetworkMessage msg; + msg.setField(_ID, _ATTENTION); + msg.setField(_ENABLE, _BOOL(on)); + sendMessage(msg); +} + /** * Disconnect from current server. * Do some cleanup also, like stopping any VNC server/client @@ -177,18 +185,21 @@ void ServerConnection::handleMsg() } int x = _fromServer.getFieldString(_X).toInt(); int y = _fromServer.getFieldString(_Y).toInt(); - if (x < 32) - x = 32; - else if (x > 400) - x = 400; - if (y < 18) - y = 18; - else if (y > 300) - y = 300; // Get rect of primary screen const QDesktopWidget primary; const QRect primaryRect = primary.screenGeometry(); + // Limit requested size so it won't easily leak sensitive information + if (x < 32) { + x = 32; + } else if (x > primaryRect.width() / 8) { + x = primaryRect.width() / 8; + } + if (y < 18) { + y = 18; + } else if (y > primaryRect.height() / 8) { + y = primaryRect.height() / 8; + } QPixmap desktop( QPixmap::grabWindow( @@ -255,6 +266,8 @@ void ServerConnection::handleMsg() _blank->lock(_fromServer.getFieldString("MESSAGE")); else _blank->unlock(); + } else if (id == _ATTENTION) { + emit attentionChanged(_fromServer.getFieldString(_ENABLE) == __TRUE); } } diff --git a/src/client/net/serverconnection.h b/src/client/net/serverconnection.h index aa1d0b4..e299a04 100644 --- a/src/client/net/serverconnection.h +++ b/src/client/net/serverconnection.h @@ -43,6 +43,7 @@ public: return _socket->peerAddress().toString(); } void sendMessage(NetworkMessage& message); + void sendAttention(bool on); protected: void timerEvent(QTimerEvent *event); @@ -63,7 +64,7 @@ signals: void closeVnc(); void stateChange(ConnectWindow::ConnectionState state); void disconnected(); - + void attentionChanged(bool state); }; #endif diff --git a/src/client/toolbar/toolbar.cpp b/src/client/toolbar/toolbar.cpp index 5fe34e4..10f9d22 100644 --- a/src/client/toolbar/toolbar.cpp +++ b/src/client/toolbar/toolbar.cpp @@ -92,8 +92,6 @@ void Toolbar::init() /* Initialize the GUI */ _ui->setupUi(this); - _onWorkspace2 = false; - /* Set window properties */ setWindowFlags(Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint | Qt::FramelessWindowHint); setAttribute(Qt::WA_AlwaysShowToolTips); @@ -115,7 +113,7 @@ void Toolbar::init() /* setup manager button */ _isManagerPc = isManagerPc(); if (_isManagerPc) { - connect(_ui->btnManager, SIGNAL(clicked()), this, SLOT(onBtnManager())); + connect(_ui->btnManager, SIGNAL(toggled(bool)), this, SLOT(onBtnManager())); } else { setFixedWidth(width() - _ui->btnManager->width()); _ui->btnManager->setVisible(false); @@ -130,6 +128,8 @@ void Toolbar::init() _ui->btnLockDesktop->setVisible(false); } + connect(_ui->btnAttention, SIGNAL(toggled(bool)), this, SLOT(onBtnAttention())); + /* Connect the signals from vnc server */ connect(VncServer::instance(), SIGNAL(started(int, QString&, QString&)), this, SLOT(onVncServerIsRunning(int))); @@ -379,6 +379,8 @@ void Toolbar::onDisconnected() this->_acnConnect->setEnabled(true); this->_acnDisconnect->setEnabled(false); + onBtnAttention(); + _hideTimer.start(); } /***************************************************************************//** @@ -392,7 +394,7 @@ void Toolbar::onConnected(ServerConnection* connection) this->_acnConnect->setEnabled(false); this->_acnDisconnect->setEnabled(true); - + _ui->btnAttention->setChecked(false); _ui->lblStatus->setStyleSheet("color:green"); _ui->lblStatus->setText(tr("Online")); // @@ -406,6 +408,7 @@ void Toolbar::onConnected(ServerConnection* connection) connect(_connection, SIGNAL(openVnc(const QString&, int, const QString&, bool, bool, const QString&, const int, const QByteArray&)), _vnc, SLOT(open(const QString&, int, const QString&, bool, bool, const QString&, const int, const QByteArray&))); connect(_connection, SIGNAL(closeVnc()), _vnc, SLOT(close())); + connect(_connection, SIGNAL(attentionChanged(const bool)), this, SLOT(onServerAttentionChanged(const bool))); connect(_vnc, SIGNAL(running(const bool, const int)), _connection, SLOT(onVncViewerStartStop(const bool, const int))); } @@ -418,6 +421,16 @@ void Toolbar::onDoDisconnect() _connection->disconnectFromServer(); } +void Toolbar::onServerAttentionChanged(const bool on) +{ + _ui->btnAttention->setChecked(on); + if (on) { + showBar(); + } else { + hideBar(); + } +} + /***************************************************************************//** * This slot hides the toolbar. Places the toolbar hidden behind the edge of the * screen just showing 2 pixels. @@ -425,7 +438,7 @@ void Toolbar::onDoDisconnect() void Toolbar::hideBar() { // Don't hide window if any menu is open or VNC Server is running from this client. - if (_menu->isVisible() || VncServer::instance()->isVncServerRunning()) + if (_menu->isVisible() || _ui->btnAttention->isChecked() || VncServer::instance()->isVncServerRunning()) return; const QDesktopWidget desktop; const QRect primaryScreen = desktop.screenGeometry(); @@ -465,17 +478,30 @@ void Toolbar::showBar() const QRect primaryScreen = desktop.screenGeometry(); move(x(), primaryScreen.top()); } + +void Toolbar::onBtnAttention() +{ + const bool on = _connection != NULL && _ui->btnAttention->isChecked(); + if (on != _ui->btnAttention->isChecked()) { + _ui->btnAttention->setChecked(on); + return; + } + if (_connection != NULL) { + _connection->sendAttention(on); + } + _ui->btnAttention->setStyleSheet(on ? "color:red" : ""); +} + /** call script to switch to workspace of the manager */ void Toolbar::onBtnManager() { QProcess switchP; - if (_onWorkspace2) { - switchP.start("/bin/sh", QStringList() << "/opt/openslx/pvs2/switchBack.sh"); - } else { + const bool on = _ui->btnAttention->isChecked(); + if (on) { switchP.start("/bin/sh", QStringList() << "/opt/openslx/pvs2/switchToManager.sh"); + } else { + switchP.start("/bin/sh", QStringList() << "/opt/openslx/pvs2/switchBack.sh"); } - _ui->btnManager->setDown(_onWorkspace2); - _onWorkspace2 = !_onWorkspace2; switchP.waitForFinished(); } diff --git a/src/client/toolbar/toolbar.h b/src/client/toolbar/toolbar.h index eb05f5f..5fb4ea5 100644 --- a/src/client/toolbar/toolbar.h +++ b/src/client/toolbar/toolbar.h @@ -51,7 +51,6 @@ private: ServerConnection *_connection; QTimer _blinkTimer; VncWindow *_vnc; - bool _onWorkspace2; bool _isManagerPc; const QPixmap _cam32, _beWatchedEye; @@ -69,9 +68,11 @@ private slots: void onVncServerIsRunning(int port); void onDisconnected(); void onConnected(ServerConnection* connection); + void onServerAttentionChanged(const bool on); void onDoDisconnect(); void onBtnManager(); void onBtnLockDesktop(); + void onBtnAttention(); void exit(); void cameraBlink(); void showBar(); diff --git a/src/server/connectionframe/connectionframe.cpp b/src/server/connectionframe/connectionframe.cpp index a7427c6..4228441 100644 --- a/src/server/connectionframe/connectionframe.cpp +++ b/src/server/connectionframe/connectionframe.cpp @@ -28,13 +28,21 @@ static QString style_tutor( "QLabel{ background-color: #FFF; border-radius: 2px; color: black;} \ QGroupBox { background-color: #70C670; margin: 2px; border-radius: 4px}" ); +static QString style_attention( + "QLabel{ background-color: #FFF; border-radius: 2px; color: black;} \ + QGroupBox { background-color: #C88; margin: 2px; border-radius: 4px}" +); static QString style_selectedStudent( "QLabel{ background-color: #FFF; border-radius: 2px; color: black; } \ QGroupBox { background-color: #ccebff; margin: 0px; border-radius: 4px; border: 4px solid #6C8CF0;}" ); static QString style_selectedTutor( "QLabel{ background-color: #FFF; border-radius: 2px; color: black;} \ - QGroupBox { background-color: #99ff99; margin: 0px; border-radius: 4px; border: 4px solid #6C8CF0;}" + QGroupBox { background-color: #9f9; margin: 0px; border-radius: 4px; border: 4px solid #6C8CF0;}" +); +static QString style_selectedAttention( + "QLabel{ background-color: #FFF; border-radius: 2px; color: black;} \ + QGroupBox { background-color: #E99; margin: 0px; border-radius: 4px; border: 4px solid #6C8CF0;}" ); static QString style_exam ( "QLabel{ background-color: #919191; color: black; } \ @@ -45,7 +53,7 @@ static QString style_exam_selected ( QGroupBox { background-color: #cc743a; margin: 1px; border-radius: 4px}" ); static QString style_disconnected( - "QLabel{ background-color: #919191; color: black; } \ + "QLabel{ background-color: #919191; border-radius: 2px; color: black; } \ QGroupBox { background-color: #7F7F7F; margin: 1px; border-radius: 4px}" ); @@ -355,6 +363,10 @@ void ConnectionFrame::updateAppearance() this->setStyleSheet(style_selectedTutor); } else if (_isTutor) { this->setStyleSheet(style_tutor); + } else if (_isSelected && _client->wantsAttention()) { + this->setStyleSheet(style_selectedAttention); + } else if (_client->wantsAttention()) { + this->setStyleSheet(style_attention); } else if (_client->isExamMode()) { if (_isSelected) { this->setStyleSheet(style_exam_selected); diff --git a/src/server/connectionframe/connectionframe.h b/src/server/connectionframe/connectionframe.h index 4f4decb..56cde9c 100644 --- a/src/server/connectionframe/connectionframe.h +++ b/src/server/connectionframe/connectionframe.h @@ -45,11 +45,6 @@ private: void showDefaultThumb(); QLabel* addIcon(const QIcon* icon); - // Static stylesheets - static const QString studentLblStyle, studentBgStyle; - static const QString tutorLblStyle, tutorBgStyle; - static const QString selectedBgStyle; - public: ConnectionFrame(QWidget* parent, int width, int height); virtual ~ConnectionFrame(); diff --git a/src/server/mainwindow/mainwindow.cpp b/src/server/mainwindow/mainwindow.cpp index b54a190..ded64b9 100644 --- a/src/server/mainwindow/mainwindow.cpp +++ b/src/server/mainwindow/mainwindow.cpp @@ -689,8 +689,10 @@ void MainWindow::reset() // Unlock all clients for (QList::iterator it(_clientFrames.begin()); it != _clientFrames.end(); ++it) - if ((*it)->client() != NULL) + if ((*it)->client() != NULL) { (*it)->client()->lockScreen(false); + (*it)->client()->removeAttention(); + } // Stop server (Clients get stopped on ACK) if (getClientFromId(_streamingSource) != NULL) @@ -791,10 +793,12 @@ void MainWindow::startVncServerIfNecessary(int from) // If streaming source is already active avoid a restart if (ns != NULL) { - if (ns->isActiveVncServer()) + if (ns->isActiveVncServer()) { this->onVncServerStateChange(ns); - else // Could not take shortcut, (re)start VNC server on source + } else { // Could not take shortcut, (re)start VNC server on source ns->startVncServer(); + } + ns->removeAttention(); } } diff --git a/src/server/net/client.cpp b/src/server/net/client.cpp index 59211b7..7224339 100644 --- a/src/server/net/client.cpp +++ b/src/server/net/client.cpp @@ -90,6 +90,17 @@ void Client::sendMessage(NetworkMessage& message) } } +/******************************************************************************/ +void Client::removeAttentionInternal() +{ + NetworkMessage msg; + _wantsAttention = false; + msg.setField(_ID, _ATTENTION); + msg.setField(_ENABLE, __FALSE); + sendMessage(msg); + emit stateChanged(); +} + /******************************************************************************/ void Client::requestThumb(const int width, const int height) { @@ -113,9 +124,8 @@ void Client::onDataArrival() return; } - bool ret; while (_socket->bytesAvailable() > 0) { - ret = _fromClient.readMessage(_socket); // let the message read data from socket + int ret = _fromClient.readMessage(_socket); // let the message read data from socket if (ret == NM_READ_FAILED) { // error parsing msg, disconnect client! this->disconnect(); return; @@ -175,7 +185,6 @@ void Client::handleMsg() const int projectionSource = (int)_fromClient.getFieldString("CLIENTID").toInt(); if (_fromClient.getFieldString("ENABLED").toInt() != 0) { qDebug() << "Client " << _name << " started its VNC client (watching " << projectionSource << ")"; - _projectionSource = projectionSource; _isActiveVncClient = true; emit vncClientStateChange(this); } else { @@ -184,6 +193,9 @@ void Client::handleMsg() emit vncClientStateChange(this); } emit stateChanged(); + } else if (id == _ATTENTION) { + _wantsAttention = _fromClient.getFieldString(_ENABLE) == __TRUE; + emit stateChanged(); } return; } @@ -301,7 +313,6 @@ bool Client::isManagerMachine() { foreach (const QHostAddress & address, QNetworkInterface::allAddresses()) if (address != QHostAddress(QHostAddress::LocalHost) - && this != NULL && this->ip() == address.toString()) return true; return false; @@ -314,7 +325,7 @@ void Client::lockScreen(bool lock) _locked = lock; NetworkMessage msg; msg.setField(_ID, _LOCK); - msg.setField(_ENABLE, lock ? __TRUE : __FALSE); + msg.setField(_ENABLE, _BOOL(lock)); sendMessage(msg); } emit stateChanged(); diff --git a/src/server/net/client.h b/src/server/net/client.h index e7c9c5c..81f5346 100644 --- a/src/server/net/client.h +++ b/src/server/net/client.h @@ -41,6 +41,8 @@ public: inline const int desiredProjectionSource() { return _desiredSource; } inline const int projectionSource() const { return _projectionSource; } inline const int isExamMode() const { return _isExamMode; } + inline const bool wantsAttention() const { return _wantsAttention; } + inline const void removeAttention() { if (!_wantsAttention) return; removeAttentionInternal(); } // Setters inline void setTutor(bool enable) { _isTutor = enable; } @@ -73,7 +75,8 @@ private: int _projectionSource; // The source the client was or is connected to (depends on _isActiveVncClient) bool _isActiveVncClient; // VNCclient state. indicating that the client is displaying a remote screen via VNC bool _isTutor; // Flag indicating that the client has been set as a tutor - bool _isExamMode; + bool _isExamMode; + bool _wantsAttention; // Flag telling whether the client activated the "i want attention" button QByteArray _rawRemoteScreen; @@ -83,6 +86,7 @@ private: void handleMsg(); void sendMessage(NetworkMessage& message); + void removeAttentionInternal(); protected: void timerEvent(QTimerEvent* event); diff --git a/src/shared/networkmessage.h b/src/shared/networkmessage.h index ddc810a..290e3b5 100644 --- a/src/shared/networkmessage.h +++ b/src/shared/networkmessage.h @@ -39,6 +39,7 @@ MSGTYPE(ENABLE); MSGTYPE(ERROR); MSGTYPE(TUTOR); MSGTYPE(EXAMMODE); +MSGTYPE(ATTENTION); static const QByteArray __TRUE("1"); -- cgit v1.2.3-55-g7522