1 /****************************************************************************
3 ** Copyright (C) 2007-2008 Urs Wolfer <uwolfer @ kde.org>
5 ** This file is part of KDE.
7 ** This program is free software; you can redistribute it and/or modify
8 ** it under the terms of the GNU General Public License as published by
9 ** the Free Software Foundation; either version 2 of the License, or
10 ** (at your option) any later version.
12 ** This program is distributed in the hope that it will be useful,
13 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 ** GNU General Public License for more details.
17 ** You should have received a copy of the GNU General Public License
18 ** along with this program; see the file COPYING. If not, write to
19 ** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 ** Boston, MA 02110-1301, USA.
22 ****************************************************************************/
27 #include <QMessageBox>
28 #include <QInputDialog>
29 #define KMessageBox QMessageBox
30 #define error(parent, message, caption) \
31 critical(parent, caption, message)
33 #include <KMessageBox>
34 #include <KPasswordDialog>
37 #include <QApplication>
40 #include <QMouseEvent>
42 VncView::VncView(QWidget
*parent
, const KUrl
&url
)
48 m_firstPasswordTry(true),
49 m_dontSendClipboard(false),
50 m_horizontalFactor(1.0),
57 connect(&vncThread
, SIGNAL(imageUpdated(int, int, int, int)), this, SLOT(updateImage(int, int, int, int)), Qt::BlockingQueuedConnection
);
58 connect(&vncThread
, SIGNAL(gotCut(const QString
&)), this, SLOT(setCut(const QString
&)), Qt::BlockingQueuedConnection
);
59 connect(&vncThread
, SIGNAL(passwordRequest()), this, SLOT(requestPassword()), Qt::BlockingQueuedConnection
);
60 connect(&vncThread
, SIGNAL(outputErrorMessage(QString
)), this, SLOT(outputErrorMessage(QString
)));
62 m_clipboard
= QApplication::clipboard();
63 connect(m_clipboard
, SIGNAL(selectionChanged()), this, SLOT(clipboardSelectionChanged()));
64 connect(m_clipboard
, SIGNAL(dataChanged()), this, SLOT(clipboardDataChanged()));
72 bool VncView::eventFilter(QObject
*obj
, QEvent
*event
)
75 if (event
->type() == QEvent::KeyPress
||
76 event
->type() == QEvent::KeyRelease
||
77 event
->type() == QEvent::MouseButtonDblClick
||
78 event
->type() == QEvent::MouseButtonPress
||
79 event
->type() == QEvent::MouseButtonRelease
||
80 event
->type() == QEvent::Wheel
||
81 event
->type() == QEvent::MouseMove
)
85 return RemoteView::eventFilter(obj
, event
);
88 QSize
VncView::framebufferSize()
93 QSize
VncView::sizeHint() const
98 QSize
VncView::minimumSizeHint() const
103 void VncView::scaleResize(int w
, int h
)
105 kDebug(5011) << w
<< h
;
110 void VncView::startQuitting()
112 kDebug(5011) << "about to quit";
114 bool connected
= status() == RemoteView::Connected
;
116 setStatus(Disconnecting
);
128 setStatus(Disconnected
);
131 bool VncView::isQuitting()
136 bool VncView::start()
138 vncThread
.setHost(m_host
);
139 vncThread
.setPort(m_port
);
141 int quality
= (QCoreApplication::arguments().count() > 2) ? QCoreApplication::arguments().at(2).toInt() : 2;
142 vncThread
.setQuality((RemoteView::Quality
)quality
);
144 m_hostPreferences
= new VncHostPreferences(m_url
.prettyUrl(KUrl::RemoveTrailingSlash
), false, this);
145 vncThread
.setQuality(m_hostPreferences
->quality());
148 setStatus(Connecting
);
154 bool VncView::supportsScaling() const
159 bool VncView::supportsLocalCursor() const
164 void VncView::requestPassword()
166 kDebug(5011) << "request password";
168 setStatus(Authenticating
);
171 if (m_hostPreferences
->walletSupport()) {
172 QString walletPassword
= readWalletPassword();
174 if (!walletPassword
.isNull()) {
175 vncThread
.setPassword(walletPassword
);
181 if (!m_url
.password().isNull()) {
182 vncThread
.setPassword(m_url
.password());
187 QString password
= QInputDialog::getText(this, //krazy:exclude=qclasses
188 tr("Password required"),
189 tr("Please enter the password for the remote desktop:"),
190 QLineEdit::Password
);
191 vncThread
.setPassword(password
);
193 KPasswordDialog
dialog(this);
194 dialog
.setPixmap(KIcon("dialog-password").pixmap(48));
195 dialog
.setPrompt(m_firstPasswordTry
? i18n("Access to the system requires a password.")
196 : i18n("Authentication failed. Please try again."));
197 if (dialog
.exec() == KPasswordDialog::Accepted
) {
198 m_firstPasswordTry
= false;
199 vncThread
.setPassword(dialog
.password());
204 void VncView::outputErrorMessage(const QString
&message
)
206 kDebug(5011) << message
;
210 KMessageBox::error(this, message
, i18n("VNC failure"));
213 void VncView::updateImage(int x
, int y
, int w
, int h
)
215 // kDebug(5011) << "got update";
222 m_frame
= vncThread
.image();
225 setAttribute(Qt::WA_StaticContents
);
226 setAttribute(Qt::WA_OpaquePaintEvent
);
227 installEventFilter(this);
229 setCursor(m_dotCursorState
== CursorOn
? localDotCursor() : Qt::BlankCursor
);
231 setMouseTracking(true); // get mouse events even when there is no mousebutton pressed
232 setFocusPolicy(Qt::WheelFocus
);
233 resize(m_frame
.width(), m_frame
.height());
234 setStatus(Connected
);
235 emit
changeSize(m_frame
.width(), m_frame
.height());
240 if (m_hostPreferences
->walletSupport()) {
241 saveWalletPassword(vncThread
.password());
246 if ((y
== 0 && x
== 0) && (m_frame
.size() != size())) {
247 resize(m_frame
.width(), m_frame
.height());
248 emit
changeSize(m_frame
.width(), m_frame
.height());
252 repaint(qRound(x
* m_horizontalFactor
), qRound(y
* m_verticalFactor
), qRound(w
* m_horizontalFactor
), qRound(h
* m_verticalFactor
));
256 void VncView::setViewOnly(bool viewOnly
)
258 RemoteView::setViewOnly(viewOnly
);
261 setCursor(Qt::ArrowCursor
);
263 setCursor(m_dotCursorState
== CursorOn
? localDotCursor() : Qt::BlankCursor
);
266 void VncView::showDotCursor(DotCursorState state
)
268 RemoteView::showDotCursor(state
);
270 setCursor(state
== CursorOn
? localDotCursor() : Qt::BlankCursor
);
273 void VncView::enableScaling(bool scale
)
275 RemoteView::enableScaling(scale
);
279 resize(parentWidget()->width(), parentWidget()->height());
281 resize(m_frame
.width(), m_frame
.height());
282 emit
changeSize(m_frame
.width(), m_frame
.height());
286 void VncView::setCut(const QString
&text
)
288 m_dontSendClipboard
= true;
289 m_clipboard
->setText(text
, QClipboard::Clipboard
);
290 m_clipboard
->setText(text
, QClipboard::Selection
);
291 m_dontSendClipboard
= false;
294 void VncView::paintEvent(QPaintEvent
*event
)
296 // kDebug(5011) << "paint event: x: " << m_x << ", y: " << m_y << ", w: " << m_w << ", h: " << m_h;
297 if (m_frame
.isNull() || m_frame
.format() == QImage::Format_Invalid
) {
298 kDebug(5011) << "no valid image to paint";
299 RemoteView::paintEvent(event
);
305 QPainter
painter(this);
308 // kDebug(5011) << "normal repaint";
309 painter
.drawImage(QRect(qRound(m_x
*m_horizontalFactor
), qRound(m_y
*m_verticalFactor
),
310 qRound(m_w
*m_horizontalFactor
), qRound(m_h
*m_verticalFactor
)),
311 m_frame
.copy(m_x
, m_y
, m_w
, m_h
).scaled(qRound(m_w
*m_horizontalFactor
),
312 qRound(m_h
*m_verticalFactor
),
313 Qt::IgnoreAspectRatio
, Qt::SmoothTransformation
));
315 // kDebug(5011) << "resize repaint";
316 painter
.drawImage(QRect(0, 0, width(), height()), m_frame
.scaled(width(), height(),
317 Qt::IgnoreAspectRatio
, Qt::SmoothTransformation
));
320 RemoteView::paintEvent(event
);
323 void VncView::resizeEvent(QResizeEvent
*event
)
325 RemoteView::resizeEvent(event
);
327 m_verticalFactor
= (qreal
) height() / m_frame
.height();
328 m_horizontalFactor
= (qreal
) width() / m_frame
.width();
333 void VncView::focusOutEvent(QFocusEvent
*event
)
335 // kDebug(5011) << "focusOutEvent";
337 if (event
->reason() == Qt::TabFocusReason
) {
338 // kDebug(5011) << "event->reason() == Qt::TabFocusReason";
340 setFocus(); // get focus back and send tab key event to remote desktop
341 vncThread
.keyEvent(XK_Tab
, true);
342 vncThread
.keyEvent(XK_Tab
, false);
345 RemoteView::focusOutEvent(event
);
348 void VncView::mouseMoveEvent(QMouseEvent
*event
)
350 // kDebug(5011) << "mouse move";
354 RemoteView::mouseMoveEvent(event
);
357 void VncView::mousePressEvent(QMouseEvent
*event
)
359 // kDebug(5011) << "mouse press";
363 RemoteView::mousePressEvent(event
);
366 void VncView::mouseDoubleClickEvent(QMouseEvent
*event
)
368 // kDebug(5011) << "mouse double click";
372 RemoteView::mouseDoubleClickEvent(event
);
375 void VncView::mouseReleaseEvent(QMouseEvent
*event
)
377 // kDebug(5011) << "mouse release";
381 RemoteView::mouseReleaseEvent(event
);
384 void VncView::mouseEvent(QMouseEvent
*e
)
386 if (e
->type() != QEvent::MouseMove
) {
387 if ((e
->type() == QEvent::MouseButtonPress
) ||
388 (e
->type() == QEvent::MouseButtonDblClick
)) {
389 if (e
->button() & Qt::LeftButton
)
390 m_buttonMask
|= 0x01;
391 if (e
->button() & Qt::MidButton
)
392 m_buttonMask
|= 0x02;
393 if (e
->button() & Qt::RightButton
)
394 m_buttonMask
|= 0x04;
395 } else if (e
->type() == QEvent::MouseButtonRelease
) {
396 if (e
->button() & Qt::LeftButton
)
397 m_buttonMask
&= 0xfe;
398 if (e
->button() & Qt::MidButton
)
399 m_buttonMask
&= 0xfd;
400 if (e
->button() & Qt::RightButton
)
401 m_buttonMask
&= 0xfb;
405 vncThread
.mouseEvent(qRound(e
->x() / m_horizontalFactor
), qRound(e
->y() / m_verticalFactor
), m_buttonMask
);
408 void VncView::wheelEvent(QWheelEvent
*event
)
411 if (event
->delta() < 0)
419 vncThread
.mouseEvent(x
, y
, eb
| m_buttonMask
);
420 vncThread
.mouseEvent(x
, y
, m_buttonMask
);
422 RemoteView::wheelEvent(event
);
425 void VncView::keyEvent(QKeyEvent
*e
)
429 case Qt::Key_Backspace
: k
= XK_BackSpace
; break;
430 case Qt::Key_Tab
: k
= XK_Tab
; break;
431 case Qt::Key_Clear
: k
= XK_Clear
; break;
432 case Qt::Key_Return
: k
= XK_Return
; break;
433 case Qt::Key_Pause
: k
= XK_Pause
; break;
434 case Qt::Key_Escape
: k
= XK_Escape
; break;
435 case Qt::Key_Space
: k
= XK_space
; break;
436 case Qt::Key_Delete
: k
= XK_Delete
; break;
437 case Qt::Key_Enter
: k
= XK_KP_Enter
; break;
438 case Qt::Key_Equal
: k
= XK_KP_Equal
; break;
439 case Qt::Key_Up
: k
= XK_Up
; break;
440 case Qt::Key_Down
: k
= XK_Down
; break;
441 case Qt::Key_Right
: k
= XK_Right
; break;
442 case Qt::Key_Left
: k
= XK_Left
; break;
443 case Qt::Key_Insert
: k
= XK_Insert
; break;
444 case Qt::Key_Home
: k
= XK_Home
; break;
445 case Qt::Key_End
: k
= XK_End
; break;
446 case Qt::Key_PageUp
: k
= XK_Page_Up
; break;
447 case Qt::Key_PageDown
: k
= XK_Page_Down
; break;
448 case Qt::Key_F1
: k
= XK_F1
; break;
449 case Qt::Key_F2
: k
= XK_F2
; break;
450 case Qt::Key_F3
: k
= XK_F3
; break;
451 case Qt::Key_F4
: k
= XK_F4
; break;
452 case Qt::Key_F5
: k
= XK_F5
; break;
453 case Qt::Key_F6
: k
= XK_F6
; break;
454 case Qt::Key_F7
: k
= XK_F7
; break;
455 case Qt::Key_F8
: k
= XK_F8
; break;
456 case Qt::Key_F9
: k
= XK_F9
; break;
457 case Qt::Key_F10
: k
= XK_F10
; break;
458 case Qt::Key_F11
: k
= XK_F11
; break;
459 case Qt::Key_F12
: k
= XK_F12
; break;
460 case Qt::Key_F13
: k
= XK_F13
; break;
461 case Qt::Key_F14
: k
= XK_F14
; break;
462 case Qt::Key_F15
: k
= XK_F15
; break;
463 case Qt::Key_NumLock
: k
= XK_Num_Lock
; break;
464 case Qt::Key_CapsLock
: k
= XK_Caps_Lock
; break;
465 case Qt::Key_ScrollLock
: k
= XK_Scroll_Lock
; break;
466 case Qt::Key_Shift
: k
= XK_Shift_L
; break;
467 case Qt::Key_Control
: k
= XK_Control_L
; break;
468 case Qt::Key_AltGr
: k
= XK_Alt_R
; break;
469 case Qt::Key_Alt
: k
= XK_Alt_L
; break;
470 case Qt::Key_Meta
: k
= XK_Meta_L
; break;
471 case Qt::Key_Mode_switch
: k
= XK_Mode_switch
; break;
472 case Qt::Key_Help
: k
= XK_Help
; break;
473 case Qt::Key_Print
: k
= XK_Print
; break;
474 case Qt::Key_SysReq
: k
= XK_Sys_Req
; break;
479 if (e
->key() < 0x100)
480 k
= QChar(e
->text().at(0)).unicode(); //respect upper- / lowercase
482 rfbClientLog("Unknown keysym: %d\n", e
->key());
485 if (k
< 26) // workaround for modified keys by pressing CTRL
488 vncThread
.keyEvent(k
, (e
->type() == QEvent::KeyPress
) ? true : false);
490 RemoteView::keyEvent(e
);
493 void VncView::keyPressEvent(QKeyEvent
*event
)
495 // kDebug(5011) << "key press" << event->key();
499 RemoteView::keyPressEvent(event
);
502 void VncView::keyReleaseEvent(QKeyEvent
*event
)
504 // kDebug(5011) << "key release" << event->key();
508 RemoteView::keyReleaseEvent(event
);
511 void VncView::clipboardSelectionChanged()
515 if (m_status
!= Connected
)
518 if (m_clipboard
->ownsSelection() || m_dontSendClipboard
)
521 QString text
= m_clipboard
->text(QClipboard::Selection
);
523 vncThread
.clientCut(text
);
526 void VncView::clipboardDataChanged()
530 if (m_status
!= Connected
)
533 if (m_clipboard
->ownsClipboard() || m_dontSendClipboard
)
536 QString text
= m_clipboard
->text(QClipboard::Clipboard
);
538 vncThread
.clientCut(text
);
541 #include "moc_vncview.cpp"