Return correct size.
[kdenetwork.git] / krdc / vnc / vncview.cpp
blob147149d3df4374da21b5bdf0181339247c6043b7
1 /****************************************************************************
2 **
3 ** Copyright (C) 2007-2008 Urs Wolfer <uwolfer @ kde.org>
4 **
5 ** This file is part of KDE.
6 **
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 ****************************************************************************/
24 #include "vncview.h"
26 #ifdef QTONLY
27 #include <QMessageBox>
28 #include <QInputDialog>
29 #define KMessageBox QMessageBox
30 #define error(parent, message, caption) \
31 critical(parent, caption, message)
32 #else
33 #include <KMessageBox>
34 #include <KPasswordDialog>
35 #endif
37 #include <QApplication>
38 #include <QImage>
39 #include <QPainter>
40 #include <QMouseEvent>
42 VncView::VncView(QWidget *parent, const KUrl &url)
43 : RemoteView(parent),
44 m_initDone(false),
45 m_buttonMask(0),
46 m_repaint(false),
47 m_quitFlag(false),
48 m_firstPasswordTry(true),
49 m_authenticaionCanceled(false),
50 m_dontSendClipboard(false),
51 m_horizontalFactor(1.0),
52 m_verticalFactor(1.0),
53 m_forceLocalCursor(false)
55 m_url = url;
56 m_host = url.host();
57 m_port = url.port();
59 connect(&vncThread, SIGNAL(imageUpdated(int, int, int, int)), this, SLOT(updateImage(int, int, int, int)), Qt::BlockingQueuedConnection);
60 connect(&vncThread, SIGNAL(gotCut(const QString&)), this, SLOT(setCut(const QString&)), Qt::BlockingQueuedConnection);
61 connect(&vncThread, SIGNAL(passwordRequest()), this, SLOT(requestPassword()), Qt::BlockingQueuedConnection);
62 connect(&vncThread, SIGNAL(outputErrorMessage(QString)), this, SLOT(outputErrorMessage(QString)));
64 m_clipboard = QApplication::clipboard();
65 connect(m_clipboard, SIGNAL(selectionChanged()), this, SLOT(clipboardSelectionChanged()));
66 connect(m_clipboard, SIGNAL(dataChanged()), this, SLOT(clipboardDataChanged()));
69 VncView::~VncView()
71 startQuitting();
74 bool VncView::eventFilter(QObject *obj, QEvent *event)
76 if (m_viewOnly) {
77 if (event->type() == QEvent::KeyPress ||
78 event->type() == QEvent::KeyRelease ||
79 event->type() == QEvent::MouseButtonDblClick ||
80 event->type() == QEvent::MouseButtonPress ||
81 event->type() == QEvent::MouseButtonRelease ||
82 event->type() == QEvent::Wheel ||
83 event->type() == QEvent::MouseMove)
84 return true;
87 return RemoteView::eventFilter(obj, event);
90 QSize VncView::framebufferSize()
92 return m_frame.size();
95 QSize VncView::sizeHint() const
97 return size();
100 QSize VncView::minimumSizeHint() const
102 return size();
105 void VncView::scaleResize(int w, int h)
107 kDebug(5011) << w << h;
108 if (m_scale)
109 resize(w, h);
112 void VncView::startQuitting()
114 kDebug(5011) << "about to quit";
116 bool connected = status() == RemoteView::Connected;
118 setStatus(Disconnecting);
120 m_quitFlag = true;
122 if (connected) {
123 vncThread.stop();
124 } else {
125 vncThread.quit();
128 vncThread.wait(500);
130 setStatus(Disconnected);
133 bool VncView::isQuitting()
135 return m_quitFlag;
138 bool VncView::start()
140 vncThread.setHost(m_host);
141 vncThread.setPort(m_port);
142 #ifdef QTONLY
143 int quality = (QCoreApplication::arguments().count() > 2) ? QCoreApplication::arguments().at(2).toInt() : 2;
144 vncThread.setQuality((RemoteView::Quality)quality);
145 #else
146 m_hostPreferences = new VncHostPreferences(m_url.prettyUrl(KUrl::RemoveTrailingSlash), false, this);
147 vncThread.setQuality(m_hostPreferences->quality());
148 #endif
150 setStatus(Connecting);
152 vncThread.start();
153 return true;
156 bool VncView::supportsScaling() const
158 return true;
161 bool VncView::supportsLocalCursor() const
163 return true;
166 void VncView::requestPassword()
168 kDebug(5011) << "request password";
170 if (m_authenticaionCanceled) {
171 startQuitting();
172 return;
175 setStatus(Authenticating);
177 #ifndef QTONLY
178 if (m_hostPreferences->walletSupport()) {
179 QString walletPassword = readWalletPassword();
181 if (!walletPassword.isNull()) {
182 vncThread.setPassword(walletPassword);
183 return;
186 #endif
188 if (!m_url.password().isNull()) {
189 vncThread.setPassword(m_url.password());
190 return;
193 #ifdef QTONLY
194 bool ok;
195 QString password = QInputDialog::getText(this, //krazy:exclude=qclasses
196 tr("Password required"),
197 tr("Please enter the password for the remote desktop:"),
198 QLineEdit::Password, QString(), &ok);
199 m_firstPasswordTry = false;
200 if (ok)
201 vncThread.setPassword(password);
202 else
203 m_authenticaionCanceled = true;
204 #else
205 KPasswordDialog dialog(this);
206 dialog.setPrompt(m_firstPasswordTry ? i18n("Access to the system requires a password.")
207 : i18n("Authentication failed. Please try again."));
208 if (dialog.exec() == KPasswordDialog::Accepted) {
209 m_firstPasswordTry = false;
210 vncThread.setPassword(dialog.password());
211 } else {
212 kDebug(5011) << "password dialog not accepted";
213 m_authenticaionCanceled = true;
215 #endif
218 void VncView::outputErrorMessage(const QString &message)
220 kDebug(5011) << message;
222 if (message == "INTERNAL:APPLE_VNC_COMPATIBILTY") {
223 setCursor(localDotCursor());
224 m_forceLocalCursor = true;
225 return;
228 startQuitting();
230 KMessageBox::error(this, message, i18n("VNC failure"));
233 void VncView::updateImage(int x, int y, int w, int h)
235 // kDebug(5011) << "got update";
237 m_x = x;
238 m_y = y;
239 m_w = w;
240 m_h = h;
242 m_frame = vncThread.image();
244 if (!m_initDone) {
245 setAttribute(Qt::WA_StaticContents);
246 setAttribute(Qt::WA_OpaquePaintEvent);
247 installEventFilter(this);
249 setCursor(((m_dotCursorState == CursorOn) || m_forceLocalCursor) ? localDotCursor() : Qt::BlankCursor);
251 setMouseTracking(true); // get mouse events even when there is no mousebutton pressed
252 setFocusPolicy(Qt::WheelFocus);
253 resize(m_frame.width(), m_frame.height());
254 setStatus(Connected);
255 emit changeSize(m_frame.width(), m_frame.height());
256 emit connected();
257 m_initDone = true;
259 #ifndef QTONLY
260 if (m_hostPreferences->walletSupport()) {
261 saveWalletPassword(vncThread.password());
263 #endif
266 if ((y == 0 && x == 0) && (m_frame.size() != size())) {
267 resize(m_frame.width(), m_frame.height());
268 emit changeSize(m_frame.width(), m_frame.height());
271 m_repaint = true;
272 repaint(qRound(x * m_horizontalFactor), qRound(y * m_verticalFactor), qRound(w * m_horizontalFactor), qRound(h * m_verticalFactor));
273 m_repaint = false;
276 void VncView::setViewOnly(bool viewOnly)
278 RemoteView::setViewOnly(viewOnly);
280 if (viewOnly)
281 setCursor(Qt::ArrowCursor);
282 else
283 setCursor(m_dotCursorState == CursorOn ? localDotCursor() : Qt::BlankCursor);
286 void VncView::showDotCursor(DotCursorState state)
288 RemoteView::showDotCursor(state);
290 setCursor(state == CursorOn ? localDotCursor() : Qt::BlankCursor);
293 void VncView::enableScaling(bool scale)
295 RemoteView::enableScaling(scale);
297 if (scale) {
298 if (parentWidget())
299 resize(parentWidget()->width(), parentWidget()->height());
300 } else {
301 resize(m_frame.width(), m_frame.height());
302 emit changeSize(m_frame.width(), m_frame.height());
306 void VncView::setCut(const QString &text)
308 m_dontSendClipboard = true;
309 m_clipboard->setText(text, QClipboard::Clipboard);
310 m_clipboard->setText(text, QClipboard::Selection);
311 m_dontSendClipboard = false;
314 void VncView::paintEvent(QPaintEvent *event)
316 // kDebug(5011) << "paint event: x: " << m_x << ", y: " << m_y << ", w: " << m_w << ", h: " << m_h;
317 if (m_frame.isNull() || m_frame.format() == QImage::Format_Invalid) {
318 kDebug(5011) << "no valid image to paint";
319 RemoteView::paintEvent(event);
320 return;
323 event->accept();
325 QPainter painter(this);
327 if (m_repaint) {
328 // kDebug(5011) << "normal repaint";
329 painter.drawImage(QRect(qRound(m_x*m_horizontalFactor), qRound(m_y*m_verticalFactor),
330 qRound(m_w*m_horizontalFactor), qRound(m_h*m_verticalFactor)),
331 m_frame.copy(m_x, m_y, m_w, m_h).scaled(qRound(m_w*m_horizontalFactor),
332 qRound(m_h*m_verticalFactor),
333 Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
334 } else {
335 // kDebug(5011) << "resize repaint";
336 painter.drawImage(QRect(0, 0, width(), height()), m_frame.scaled(width(), height(),
337 Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
340 RemoteView::paintEvent(event);
343 void VncView::resizeEvent(QResizeEvent *event)
345 RemoteView::resizeEvent(event);
347 m_verticalFactor = (qreal) height() / m_frame.height();
348 m_horizontalFactor = (qreal) width() / m_frame.width();
350 update();
353 void VncView::focusOutEvent(QFocusEvent *event)
355 // kDebug(5011) << "focusOutEvent";
357 if (event->reason() == Qt::TabFocusReason) {
358 // kDebug(5011) << "event->reason() == Qt::TabFocusReason";
359 event->ignore();
360 setFocus(); // get focus back and send tab key event to remote desktop
361 vncThread.keyEvent(XK_Tab, true);
362 vncThread.keyEvent(XK_Tab, false);
365 RemoteView::focusOutEvent(event);
368 void VncView::mouseMoveEvent(QMouseEvent *event)
370 // kDebug(5011) << "mouse move";
372 mouseEvent(event);
374 RemoteView::mouseMoveEvent(event);
377 void VncView::mousePressEvent(QMouseEvent *event)
379 // kDebug(5011) << "mouse press";
381 mouseEvent(event);
383 RemoteView::mousePressEvent(event);
386 void VncView::mouseDoubleClickEvent(QMouseEvent *event)
388 // kDebug(5011) << "mouse double click";
390 mouseEvent(event);
392 RemoteView::mouseDoubleClickEvent(event);
395 void VncView::mouseReleaseEvent(QMouseEvent *event)
397 // kDebug(5011) << "mouse release";
399 mouseEvent(event);
401 RemoteView::mouseReleaseEvent(event);
404 void VncView::mouseEvent(QMouseEvent *e)
406 if (e->type() != QEvent::MouseMove) {
407 if ((e->type() == QEvent::MouseButtonPress) ||
408 (e->type() == QEvent::MouseButtonDblClick)) {
409 if (e->button() & Qt::LeftButton)
410 m_buttonMask |= 0x01;
411 if (e->button() & Qt::MidButton)
412 m_buttonMask |= 0x02;
413 if (e->button() & Qt::RightButton)
414 m_buttonMask |= 0x04;
415 } else if (e->type() == QEvent::MouseButtonRelease) {
416 if (e->button() & Qt::LeftButton)
417 m_buttonMask &= 0xfe;
418 if (e->button() & Qt::MidButton)
419 m_buttonMask &= 0xfd;
420 if (e->button() & Qt::RightButton)
421 m_buttonMask &= 0xfb;
425 vncThread.mouseEvent(qRound(e->x() / m_horizontalFactor), qRound(e->y() / m_verticalFactor), m_buttonMask);
428 void VncView::wheelEvent(QWheelEvent *event)
430 int eb = 0;
431 if (event->delta() < 0)
432 eb |= 0x10;
433 else
434 eb |= 0x8;
436 int x = event->x();
437 int y = event->y();
439 vncThread.mouseEvent(x, y, eb | m_buttonMask);
440 vncThread.mouseEvent(x, y, m_buttonMask);
442 RemoteView::wheelEvent(event);
445 void VncView::keyEvent(QKeyEvent *e)
447 rfbKeySym k = 0;
448 switch (e->key()) {
449 case Qt::Key_Backspace: k = XK_BackSpace; break;
450 case Qt::Key_Tab: k = XK_Tab; break;
451 case Qt::Key_Clear: k = XK_Clear; break;
452 case Qt::Key_Return: k = XK_Return; break;
453 case Qt::Key_Pause: k = XK_Pause; break;
454 case Qt::Key_Escape: k = XK_Escape; break;
455 case Qt::Key_Space: k = XK_space; break;
456 case Qt::Key_Delete: k = XK_Delete; break;
457 case Qt::Key_Enter: k = XK_KP_Enter; break;
458 case Qt::Key_Equal: k = XK_KP_Equal; break;
459 case Qt::Key_Up: k = XK_Up; break;
460 case Qt::Key_Down: k = XK_Down; break;
461 case Qt::Key_Right: k = XK_Right; break;
462 case Qt::Key_Left: k = XK_Left; break;
463 case Qt::Key_Insert: k = XK_Insert; break;
464 case Qt::Key_Home: k = XK_Home; break;
465 case Qt::Key_End: k = XK_End; break;
466 case Qt::Key_PageUp: k = XK_Page_Up; break;
467 case Qt::Key_PageDown: k = XK_Page_Down; break;
468 case Qt::Key_F1: k = XK_F1; break;
469 case Qt::Key_F2: k = XK_F2; break;
470 case Qt::Key_F3: k = XK_F3; break;
471 case Qt::Key_F4: k = XK_F4; break;
472 case Qt::Key_F5: k = XK_F5; break;
473 case Qt::Key_F6: k = XK_F6; break;
474 case Qt::Key_F7: k = XK_F7; break;
475 case Qt::Key_F8: k = XK_F8; break;
476 case Qt::Key_F9: k = XK_F9; break;
477 case Qt::Key_F10: k = XK_F10; break;
478 case Qt::Key_F11: k = XK_F11; break;
479 case Qt::Key_F12: k = XK_F12; break;
480 case Qt::Key_F13: k = XK_F13; break;
481 case Qt::Key_F14: k = XK_F14; break;
482 case Qt::Key_F15: k = XK_F15; break;
483 case Qt::Key_NumLock: k = XK_Num_Lock; break;
484 case Qt::Key_CapsLock: k = XK_Caps_Lock; break;
485 case Qt::Key_ScrollLock: k = XK_Scroll_Lock; break;
486 case Qt::Key_Shift: k = XK_Shift_L; break;
487 case Qt::Key_Control: k = XK_Control_L; break;
488 case Qt::Key_AltGr: k = XK_Alt_R; break;
489 case Qt::Key_Alt: k = XK_Alt_L; break;
490 case Qt::Key_Meta: k = XK_Meta_L; break;
491 case Qt::Key_Mode_switch: k = XK_Mode_switch; break;
492 case Qt::Key_Help: k = XK_Help; break;
493 case Qt::Key_Print: k = XK_Print; break;
494 case Qt::Key_SysReq: k = XK_Sys_Req; break;
495 default: break;
498 if (k == 0) {
499 if (e->key() < 0x100)
500 k = QChar(e->text().at(0)).unicode(); //respect upper- / lowercase
501 else
502 rfbClientLog("Unknown keysym: %d\n", e->key());
505 if (k < 26) // workaround for modified keys by pressing CTRL
506 k += 96;
508 vncThread.keyEvent(k, (e->type() == QEvent::KeyPress) ? true : false);
510 RemoteView::keyEvent(e);
513 void VncView::keyPressEvent(QKeyEvent *event)
515 // kDebug(5011) << "key press" << event->key();
517 keyEvent(event);
519 RemoteView::keyPressEvent(event);
522 void VncView::keyReleaseEvent(QKeyEvent *event)
524 // kDebug(5011) << "key release" << event->key();
526 keyEvent(event);
528 RemoteView::keyReleaseEvent(event);
531 void VncView::clipboardSelectionChanged()
533 kDebug(5011);
535 if (m_status != Connected)
536 return;
538 if (m_clipboard->ownsSelection() || m_dontSendClipboard)
539 return;
541 QString text = m_clipboard->text(QClipboard::Selection);
543 vncThread.clientCut(text);
546 void VncView::clipboardDataChanged()
548 kDebug(5011);
550 if (m_status != Connected)
551 return;
553 if (m_clipboard->ownsClipboard() || m_dontSendClipboard)
554 return;
556 QString text = m_clipboard->text(QClipboard::Clipboard);
558 vncThread.clientCut(text);
561 #include "moc_vncview.cpp"