26 #include <QApplication>
29 #include <QMouseEvent>
32 #include <QMessageBox>
33 #include <QInputDialog>
34 #define KMessageBox QMessageBox
35 #define error(parent, message, caption) \
36 critical(parent, caption, message)
39 #include <KActionCollection>
40 #include <KMainWindow>
41 #include <KMessageBox>
42 #include <KPasswordDialog>
43 #include <KXMLGUIClient>
47 #define KMOD_Alt_R 0x01
48 #define KMOD_Alt_L 0x02
49 #define KMOD_Meta_L 0x04
50 #define KMOD_Control_L 0x08
51 #define KMOD_Shift_L 0x10
59 m_firstPasswordTry(true),
60 m_dontSendClipboard(false),
61 m_horizontalFactor(1.0),
62 m_verticalFactor(1.0),
63 m_forceLocalCursor(false)
70 connect(&vncThread, SIGNAL(imageUpdated(
int,
int,
int,
int)),
this, SLOT(updateImage(
int,
int,
int,
int)), Qt::BlockingQueuedConnection);
71 connect(&vncThread, SIGNAL(gotCut(QString)),
this, SLOT(setCut(QString)), Qt::BlockingQueuedConnection);
72 connect(&vncThread, SIGNAL(passwordRequest(
bool)),
this, SLOT(requestPassword(
bool)), Qt::BlockingQueuedConnection);
73 connect(&vncThread, SIGNAL(outputErrorMessage(QString)),
this, SLOT(outputErrorMessage(QString)));
75 m_clipboard = QApplication::clipboard();
76 connect(m_clipboard, SIGNAL(dataChanged()),
this, SLOT(clipboardDataChanged()));
81 Q_UNUSED(configGroup);
93 if (event->type() == QEvent::KeyPress ||
94 event->type() == QEvent::KeyRelease ||
95 event->type() == QEvent::MouseButtonDblClick ||
96 event->type() == QEvent::MouseButtonPress ||
97 event->type() == QEvent::MouseButtonRelease ||
98 event->type() == QEvent::Wheel ||
99 event->type() == QEvent::MouseMove)
103 return RemoteView::eventFilter(obj, event);
108 return m_frame.size();
125 kDebug(5011) << w << h;
127 m_verticalFactor = (qreal) h / m_frame.height();
128 m_horizontalFactor = (qreal) w / m_frame.width();
132 m_verticalFactor = m_horizontalFactor = qMin(m_verticalFactor, m_horizontalFactor);
135 m_verticalFactor = m_horizontalFactor = qMin(m_verticalFactor, m_horizontalFactor);
138 const qreal newW = m_frame.width() * m_horizontalFactor;
139 const qreal newH = m_frame.height() * m_verticalFactor;
140 setMaximumSize(newW, newH);
150 scaleResize(parentWidget()->width(), parentWidget()->height());
155 kDebug(5011) <<
"about to quit";
166 vncThread.disconnect();
170 const bool quitSuccess = vncThread.wait(500);
175 if (!loop.processEvents()) {
176 kDebug(5011) <<
"BUG: deadlocked, but no events to deliver?";
181 kDebug(5011) <<
"Quit VNC thread success:" << quitSuccess;
198 QCoreApplication::arguments().at(2).toInt() : 2);
200 quality = m_hostPreferences->
quality();
210 KXMLGUIClient *mainWindow =
dynamic_cast<KXMLGUIClient*
>(KMainWindow::memberList().at(0));
212 mainWindow->actionCollection()->action(
"show_local_cursor")->setChecked(
true);
232 void VncView::requestPassword(
bool includingUsername)
234 kDebug(5011) <<
"request password";
238 if (m_firstPasswordTry && !
m_url.userName().isNull()) {
244 if (m_firstPasswordTry && m_hostPreferences->
walletSupport()) {
247 if (!walletPassword.isNull()) {
249 m_firstPasswordTry =
false;
255 if (m_firstPasswordTry && !
m_url.password().isNull()) {
257 m_firstPasswordTry =
false;
263 if (includingUsername) {
264 QString username = QInputDialog::getText(
this,
265 tr(
"Username required"),
266 tr(
"Please enter the username for the remote desktop:"),
267 QLineEdit::Normal,
m_url.userName(), &ok);
274 QString password = QInputDialog::getText(
this,
275 tr(
"Password required"),
276 tr(
"Please enter the password for the remote desktop:"),
277 QLineEdit::Password, QString(), &ok);
278 m_firstPasswordTry =
false;
284 KPasswordDialog dialog(
this, includingUsername ? KPasswordDialog::ShowUsernameLine : KPasswordDialog::NoFlags);
285 dialog.setPrompt(m_firstPasswordTry ? i18n(
"Access to the system requires a password.")
286 : i18n(
"Authentication failed. Please try again."));
287 if (includingUsername) dialog.setUsername(
m_url.userName());
288 if (dialog.exec() == KPasswordDialog::Accepted) {
289 m_firstPasswordTry =
false;
291 if (includingUsername) vncThread.
setUsername(dialog.username());
293 kDebug(5011) <<
"password dialog not accepted";
299 void VncView::outputErrorMessage(
const QString &message)
301 kDebug(5011) << message;
303 if (message ==
"INTERNAL:APPLE_VNC_COMPATIBILTY") {
305 m_forceLocalCursor =
true;
311 KMessageBox::error(
this, message, i18n(
"VNC failure"));
319 return m_hostPreferences;
323 void VncView::updateImage(
int x,
int y,
int w,
int h)
332 if (m_horizontalFactor != 1.0 || m_verticalFactor != 1.0) {
340 m_frame = vncThread.
image();
343 if (!vncThread.
username().isEmpty()) {
346 setAttribute(Qt::WA_StaticContents);
347 setAttribute(Qt::WA_OpaquePaintEvent);
348 installEventFilter(
this);
352 setMouseTracking(
true);
353 setFocusPolicy(Qt::WheelFocus);
359 kDebug(5011) <<
"Setting initial size w:" <<m_hostPreferences->
width() <<
" h:" << m_hostPreferences->
height();
362 kDebug() <<
"m_frame.size():" << m_frame.size() <<
"size()" << size();
377 if ((y == 0 && x == 0) && (m_frame.size() != size())) {
378 kDebug(5011) <<
"Updating framebuffer size";
380 setMaximumSize(QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX));
382 scaleResize(parentWidget()->width(), parentWidget()->height());
384 kDebug(5011) <<
"Resizing: " << m_frame.width() << m_frame.height();
385 resize(m_frame.width(), m_frame.height());
386 setMaximumSize(m_frame.width(), m_frame.height());
387 setMinimumSize(m_frame.width(), m_frame.height());
393 repaint(qRound(m_x * m_horizontalFactor), qRound(m_y * m_verticalFactor), qRound(m_w * m_horizontalFactor), qRound(m_h * m_verticalFactor));
404 setCursor(Qt::ArrowCursor);
421 setMaximumSize(QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX));
422 setMinimumSize(1, 1);
424 scaleResize(parentWidget()->width(), parentWidget()->height());
426 m_verticalFactor = 1.0;
427 m_horizontalFactor = 1.0;
429 setMaximumSize(m_frame.width(), m_frame.height());
430 setMinimumSize(m_frame.width(), m_frame.height());
431 resize(m_frame.width(), m_frame.height());
435 void VncView::setCut(
const QString &text)
437 m_dontSendClipboard =
true;
438 m_clipboard->setText(text, QClipboard::Clipboard);
439 m_dontSendClipboard =
false;
445 if (m_frame.isNull() || m_frame.format() == QImage::Format_Invalid) {
446 kDebug(5011) <<
"no valid image to paint";
447 RemoteView::paintEvent(event);
453 QPainter painter(
this);
457 painter.drawImage(QRect(qRound(m_x*m_horizontalFactor), qRound(m_y*m_verticalFactor),
458 qRound(m_w*m_horizontalFactor), qRound(m_h*m_verticalFactor)),
459 m_frame.copy(m_x, m_y, m_w, m_h).scaled(qRound(m_w*m_horizontalFactor),
460 qRound(m_h*m_verticalFactor),
461 Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
464 QRect rect =
event->rect();
465 if (rect.width() != width() || rect.height() != height()) {
467 const int sx = rect.x()/m_horizontalFactor;
468 const int sy = rect.y()/m_verticalFactor;
469 const int sw = rect.width()/m_horizontalFactor;
470 const int sh = rect.height()/m_verticalFactor;
471 painter.drawImage(rect,
472 m_frame.copy(sx, sy, sw, sh).scaled(rect.width(), rect.height(),
473 Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
476 painter.drawImage(QRect(0, 0, width(), height()),
477 m_frame.scaled(m_frame.width() * m_horizontalFactor, m_frame.height() * m_verticalFactor,
478 Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
482 RemoteView::paintEvent(event);
487 RemoteView::resizeEvent(event);
493 switch (event->type()) {
494 case QEvent::KeyPress:
495 case QEvent::KeyRelease:
497 keyEventHandler(static_cast<QKeyEvent*>(event));
500 case QEvent::MouseButtonDblClick:
501 case QEvent::MouseButtonPress:
502 case QEvent::MouseButtonRelease:
503 case QEvent::MouseMove:
505 mouseEventHandler(static_cast<QMouseEvent*>(event));
510 wheelEventHandler(static_cast<QWheelEvent*>(event));
514 return RemoteView::event(event);
518 void VncView::mouseEventHandler(QMouseEvent *e)
520 if (e->type() != QEvent::MouseMove) {
521 if ((e->type() == QEvent::MouseButtonPress) ||
522 (e->type() == QEvent::MouseButtonDblClick)) {
523 if (e->button() & Qt::LeftButton)
524 m_buttonMask |= 0x01;
525 if (e->button() & Qt::MidButton)
526 m_buttonMask |= 0x02;
527 if (e->button() & Qt::RightButton)
528 m_buttonMask |= 0x04;
529 }
else if (e->type() == QEvent::MouseButtonRelease) {
530 if (e->button() & Qt::LeftButton)
531 m_buttonMask &= 0xfe;
532 if (e->button() & Qt::MidButton)
533 m_buttonMask &= 0xfd;
534 if (e->button() & Qt::RightButton)
535 m_buttonMask &= 0xfb;
539 vncThread.
mouseEvent(qRound(e->x() / m_horizontalFactor), qRound(e->y() / m_verticalFactor), m_buttonMask);
542 void VncView::wheelEventHandler(QWheelEvent *event)
545 if (event->delta() < 0)
550 const int x = qRound(event->x() / m_horizontalFactor);
551 const int y = qRound(event->y() / m_verticalFactor);
553 vncThread.
mouseEvent(x, y, eb | m_buttonMask);
557 void VncView::keyEventHandler(QKeyEvent *e)
560 if (e->isAutoRepeat() && (e->type() == QEvent::KeyRelease))
564 rfbKeySym k = e->nativeVirtualKey();
568 if (e->key() == Qt::Key_Backtab) {
572 const bool pressed = (e->type() == QEvent::KeyPress);
575 if (k == XK_Shift_L || k == XK_Control_L || k == XK_Meta_L || k == XK_Alt_L) {
578 }
else if (m_mods.contains(k)) {
590 void VncView::unpressModifiers()
592 const QList<unsigned int> keys = m_mods.keys();
593 QList<unsigned int>::const_iterator it = keys.constBegin();
594 while (it != keys.end()) {
601 void VncView::clipboardDataChanged()
608 if (m_clipboard->ownsClipboard() || m_dontSendClipboard)
611 const QString text = m_clipboard->text(QClipboard::Clipboard);
616 #include "moc_vncview.cpp"
void paintEvent(QPaintEvent *event)
void scaleResize(int w, int h)
void mouseEvent(int x, int y, int buttonMask)
virtual void showDotCursor(DotCursorState state)
Sets the state of the dot cursor, if supported by the backend.
void setQuality(RemoteView::Quality quality)
const QString password() const
void setUsername(const QString &username)
void startQuitting()
Initiate the disconnection.
QCursor localDotCursor() const
void keyEvent(int key, bool pressed)
QString readWalletPassword(bool fromUserNameOnly=false)
QSize minimumSizeHint() const
HostPreferences * hostPreferences()
Returns the current host preferences of this view.
void setViewOnly(bool viewOnly)
Enables/disables the view-only mode.
void connected()
Emitted when the view connected successfully.
Always show local cursor (and the remote one).
Generic widget that displays a remote framebuffer.
static bool keepAspectRatio()
Get KeepAspectRatio.
VncView(QWidget *parent=0, const KUrl &url=KUrl(), KConfigGroup configGroup=KConfigGroup())
void resizeEvent(QResizeEvent *event)
void framebufferSizeChanged(int w, int h)
Emitted when the size of the remote screen changes.
bool event(QEvent *event)
QSize framebufferSize()
Returns the resolution of the remote framebuffer.
int height()
Saved height.
bool supportsLocalCursor() const
Checks whether the backend supports the concept of local cursors.
void errorMessage(const QString &title, const QString &message)
Emitted when the view has a specific error.
virtual void setViewOnly(bool viewOnly)
Enables/disables the view-only mode.
const QString username() const
void setHost(const QString &host)
const QImage image(int x=0, int y=0, int w=0, int h=0)
void saveWalletPassword(const QString &password, bool fromUserNameOnly=false)
RemoteStatus m_status
The status of the remote view.
void setPassword(const QString &password)
void showDotCursor(DotCursorState state)
Sets the state of the dot cursor, if supported by the backend.
virtual bool viewOnly()
Checks whether the view is in view-only mode.
bool isQuitting()
Checks whether the view is currently quitting.
void clientCut(const QString &text)
virtual void scaleResize(int w, int h)
Called when the visible place changed so remote view can resize itself.
bool eventFilter(QObject *obj, QEvent *event)
bool supportsScaling() const
Checks whether the backend supports scaling.
virtual void enableScaling(bool scale)
Called to enable or disable scaling.
virtual void updateConfiguration()
Called when the configuration is changed.
virtual void updateConfiguration()
Called when the configuration is changed.
void enableScaling(bool scale)
Called to enable or disable scaling.
RemoteView::Quality quality()
virtual void setStatus(RemoteStatus s)
Set the status of the connection.
DotCursorState m_dotCursorState
DotCursorState
Describes the state of a local cursor, if there is such a concept in the backend. ...
bool start()
Initialize the view (for example by showing configuration dialogs to the user) and start connecting...