Consistent code format and small code optimizations.
[kdenetwork.git] / krdc / vnc / vncview.cpp
blob58d263699097586cd2357237f46f2f452dfdfa52
1 /****************************************************************************
2 **
3 ** Copyright (C) 2007 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 #include <KLocale>
27 #include <KMessageBox>
28 #include <KPasswordDialog>
29 #include <KDebug>
31 #include <QApplication>
32 #include <QImage>
33 #include <QPainter>
34 #include <QMouseEvent>
36 VncView::VncView(QWidget *parent, const KUrl &url)
37 : RemoteView(parent),
38 m_initDone(false),
39 m_buttonMask(0),
40 m_repaint(false),
41 m_quitFlag(false),
42 m_firstPasswordTry(true),
43 m_dontSendClipboard(false)
45 m_url = url;
46 m_host = url.host();
47 m_port = url.port();
49 connect(&vncThread, SIGNAL(imageUpdated(int, int, int, int)), this, SLOT(updateImage(int, int, int, int)), Qt::BlockingQueuedConnection);
50 connect(&vncThread, SIGNAL(gotCut(const QString&)), this, SLOT(setCut(const QString&)), Qt::BlockingQueuedConnection);
51 connect(&vncThread, SIGNAL(passwordRequest()), this, SLOT(requestPassword()), Qt::BlockingQueuedConnection);
52 connect(&vncThread, SIGNAL(outputErrorMessage(QString)), this, SLOT(outputErrorMessage(QString)));
54 m_clipboard = QApplication::clipboard();
55 connect(m_clipboard, SIGNAL(selectionChanged()), this, SLOT(clipboardSelectionChanged()));
56 connect(m_clipboard, SIGNAL(dataChanged()), this, SLOT(clipboardDataChanged()));
59 VncView::~VncView()
61 startQuitting();
64 bool VncView::eventFilter(QObject *obj, QEvent *event)
66 if (m_viewOnly) {
67 setCursor(Qt::ArrowCursor);
69 if (event->type() == QEvent::KeyPress ||
70 event->type() == QEvent::KeyRelease ||
71 event->type() == QEvent::MouseButtonDblClick ||
72 event->type() == QEvent::MouseButtonPress ||
73 event->type() == QEvent::MouseButtonRelease ||
74 event->type() == QEvent::Wheel ||
75 event->type() == QEvent::MouseMove)
76 return true;
79 setCursor(m_dotCursorState == CursorOn ? localDotCursor() : Qt::BlankCursor);
81 return RemoteView::eventFilter(obj, event);
84 QSize VncView::framebufferSize()
86 return size();
89 QSize VncView::sizeHint() const
91 return size();
94 QSize VncView::minimumSizeHint() const
96 return size();
99 void VncView::startQuitting()
101 kDebug(5011) << "about to quit";
103 bool connected = status() == RemoteView::Connected;
105 setStatus(Disconnecting);
107 m_quitFlag = true;
109 if (connected) {
110 vncThread.stop();
111 } else {
112 vncThread.quit();
115 vncThread.wait(500);
117 setStatus(Disconnected);
120 bool VncView::isQuitting()
122 return m_quitFlag;
125 bool VncView::start()
127 m_hostPreferences = new VncHostPreferences(m_url.prettyUrl(KUrl::RemoveTrailingSlash), false, this);
129 vncThread.setHost(m_host);
130 vncThread.setPort(m_port);
131 vncThread.setQuality(m_hostPreferences->quality());
133 setStatus(Connecting);
135 vncThread.start();
136 return true;
139 bool VncView::supportsLocalCursor() const
141 return true;
144 void VncView::requestPassword()
146 kDebug(5011) << "request password";
148 setStatus(Authenticating);
150 if (m_hostPreferences->walletSupport()) {
151 QString walletPassword = readWalletPassword();
153 if (!walletPassword.isNull()) {
154 vncThread.setPassword(walletPassword);
155 return;
159 if (!m_url.password().isNull()) {
160 vncThread.setPassword(m_url.password());
161 return;
164 KPasswordDialog dialog(this);
165 dialog.setPixmap(KIcon("dialog-password").pixmap(48));
166 dialog.setPrompt(m_firstPasswordTry ? i18n("Access to the system requires a password.")
167 : i18n("Authentication failed. Please try again."));
168 if (dialog.exec() == KPasswordDialog::Accepted) {
169 m_firstPasswordTry = false;
170 vncThread.setPassword(dialog.password());
174 void VncView::outputErrorMessage(const QString &message)
176 kDebug(5011) << message;
178 startQuitting();
180 KMessageBox::error(this, message, i18n("VNC failure"));
183 void VncView::updateImage(int x, int y, int w, int h)
185 // kDebug(5011) << "got update";
187 m_x = x;
188 m_y = y;
189 m_w = w;
190 m_h = h;
192 if (!m_initDone) {
193 setAttribute(Qt::WA_StaticContents);
194 setAttribute(Qt::WA_OpaquePaintEvent);
195 installEventFilter(this);
197 setCursor(m_dotCursorState == CursorOn ? localDotCursor() : Qt::BlankCursor);
199 setMouseTracking(true); // get mouse events even when there is no mousebutton pressed
200 setFocusPolicy(Qt::WheelFocus);
201 QImage frame = vncThread.image();
202 setFixedSize(frame.width(), frame.height());
203 setStatus(Connected);
204 emit changeSize(frame.width(), frame.height());
205 emit connected();
206 m_initDone = true;
208 if (m_hostPreferences->walletSupport()) {
209 saveWalletPassword(vncThread.password());
213 m_repaint = true;
214 repaint(x, y, w, h);
215 m_repaint = false;
218 void VncView::setCut(const QString &text)
220 m_dontSendClipboard = true;
221 m_clipboard->setText(text, QClipboard::Clipboard);
222 m_clipboard->setText(text, QClipboard::Selection);
223 m_dontSendClipboard = false;
226 void VncView::paintEvent(QPaintEvent *event)
228 // kDebug(5011) << "paint event: x: " << m_x << ", y: " << m_y << ", w: " << m_w << ", h: " << m_h;
230 event->accept();
232 QPainter painter(this);
235 if (m_repaint) {
236 // kDebug(5011) << "normal repaint";
237 painter.drawImage(QRect(m_x, m_y, m_w, m_h), vncThread.image(m_x, m_y, m_w, m_h));
238 } else {
239 // kDebug(5011) << "resize repaint";
240 QImage frame = vncThread.image();
241 painter.drawImage(frame.rect(), frame);
244 QWidget::paintEvent(event);
247 void VncView::focusOutEvent(QFocusEvent *event)
249 // kDebug(5011) << "focusOutEvent";
251 if (event->reason() == Qt::TabFocusReason) {
252 // kDebug(5011) << "event->reason() == Qt::TabFocusReason";
253 event->ignore();
254 setFocus(); // get focus back and send tab key event to remote desktop
255 keyEvent(new QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier));
256 keyEvent(new QKeyEvent(QEvent::KeyRelease, Qt::Key_Tab, Qt::NoModifier));
259 event->accept();
262 void VncView::mouseMoveEvent(QMouseEvent *event)
264 // kDebug(5011) << "mouse move";
266 mouseEvent(event);
268 event->accept();
271 void VncView::mousePressEvent(QMouseEvent *event)
273 // kDebug(5011) << "mouse press";
275 mouseEvent(event);
277 event->accept();
280 void VncView::mouseDoubleClickEvent(QMouseEvent *event)
282 // kDebug(5011) << "mouse double click";
284 mouseEvent(event);
286 event->accept();
289 void VncView::mouseReleaseEvent(QMouseEvent *event)
291 // kDebug(5011) << "mouse release";
293 mouseEvent(event);
295 event->accept();
298 void VncView::mouseEvent(QMouseEvent *e)
300 if (e->type() != QEvent::MouseMove) {
301 if ((e->type() == QEvent::MouseButtonPress) ||
302 (e->type() == QEvent::MouseButtonDblClick)) {
303 if (e->button() & Qt::LeftButton)
304 m_buttonMask |= 0x01;
305 if (e->button() & Qt::MidButton)
306 m_buttonMask |= 0x02;
307 if (e->button() & Qt::RightButton)
308 m_buttonMask |= 0x04;
309 } else if (e->type() == QEvent::MouseButtonRelease) {
310 if (e->button() & Qt::LeftButton)
311 m_buttonMask &= 0xfe;
312 if (e->button() & Qt::MidButton)
313 m_buttonMask &= 0xfd;
314 if (e->button() & Qt::RightButton)
315 m_buttonMask &= 0xfb;
319 vncThread.mouseEvent(e->x(), e->y(), m_buttonMask);
322 void VncView::wheelEvent(QWheelEvent *event)
324 int eb = 0;
325 if (event->delta() < 0)
326 eb |= 0x10;
327 else
328 eb |= 0x8;
330 int x = event->x();
331 int y = event->y();
333 vncThread.mouseEvent(x, y, eb | m_buttonMask);
334 vncThread.mouseEvent(x, y, m_buttonMask);
335 event->accept();
338 void VncView::keyEvent(QKeyEvent *e)
340 rfbKeySym k = 0;
341 switch (e->key()) {
342 case Qt::Key_Backspace: k = XK_BackSpace; break;
343 case Qt::Key_Tab: k = XK_Tab; break;
344 case Qt::Key_Clear: k = XK_Clear; break;
345 case Qt::Key_Return: k = XK_Return; break;
346 case Qt::Key_Pause: k = XK_Pause; break;
347 case Qt::Key_Escape: k = XK_Escape; break;
348 case Qt::Key_Space: k = XK_space; break;
349 case Qt::Key_Delete: k = XK_Delete; break;
350 case Qt::Key_Enter: k = XK_KP_Enter; break;
351 case Qt::Key_Equal: k = XK_KP_Equal; break;
352 case Qt::Key_Up: k = XK_Up; break;
353 case Qt::Key_Down: k = XK_Down; break;
354 case Qt::Key_Right: k = XK_Right; break;
355 case Qt::Key_Left: k = XK_Left; break;
356 case Qt::Key_Insert: k = XK_Insert; break;
357 case Qt::Key_Home: k = XK_Home; break;
358 case Qt::Key_End: k = XK_End; break;
359 case Qt::Key_PageUp: k = XK_Page_Up; break;
360 case Qt::Key_PageDown: k = XK_Page_Down; break;
361 case Qt::Key_F1: k = XK_F1; break;
362 case Qt::Key_F2: k = XK_F2; break;
363 case Qt::Key_F3: k = XK_F3; break;
364 case Qt::Key_F4: k = XK_F4; break;
365 case Qt::Key_F5: k = XK_F5; break;
366 case Qt::Key_F6: k = XK_F6; break;
367 case Qt::Key_F7: k = XK_F7; break;
368 case Qt::Key_F8: k = XK_F8; break;
369 case Qt::Key_F9: k = XK_F9; break;
370 case Qt::Key_F10: k = XK_F10; break;
371 case Qt::Key_F11: k = XK_F11; break;
372 case Qt::Key_F12: k = XK_F12; break;
373 case Qt::Key_F13: k = XK_F13; break;
374 case Qt::Key_F14: k = XK_F14; break;
375 case Qt::Key_F15: k = XK_F15; break;
376 case Qt::Key_NumLock: k = XK_Num_Lock; break;
377 case Qt::Key_CapsLock: k = XK_Caps_Lock; break;
378 case Qt::Key_ScrollLock: k = XK_Scroll_Lock; break;
379 case Qt::Key_Shift: k = XK_Shift_L; break;
380 case Qt::Key_Control: k = XK_Control_L; break;
381 case Qt::Key_AltGr: k = XK_Alt_R; break;
382 case Qt::Key_Alt: k = XK_Alt_L; break;
383 case Qt::Key_Meta: k = XK_Meta_L; break;
384 case Qt::Key_Mode_switch: k = XK_Mode_switch; break;
385 case Qt::Key_Help: k = XK_Help; break;
386 case Qt::Key_Print: k = XK_Print; break;
387 case Qt::Key_SysReq: k = XK_Sys_Req; break;
388 default: break;
391 if (k == 0) {
392 if (e->key() < 0x100)
393 k = QChar(e->text().at(0)).unicode(); //respect upper- / lowercase
394 else
395 rfbClientLog("Unknown keysym: %d\n", e->key());
398 if (k < 26) // workaround for modified keys by pressing CTRL
399 k += 96;
401 vncThread.keyEvent(k, (e->type() == QEvent::KeyPress) ? true : false);
404 void VncView::keyPressEvent(QKeyEvent *event)
406 // kDebug(5011) << "key press" << event->key();
408 keyEvent(event);
410 event->accept();
413 void VncView::keyReleaseEvent(QKeyEvent *event)
415 // kDebug(5011) << "key release" << event->key();
417 keyEvent(event);
419 event->accept();
422 void VncView::clipboardSelectionChanged()
424 kDebug(5011);
426 if (m_status != Connected)
427 return;
429 if (m_clipboard->ownsSelection() || m_dontSendClipboard)
430 return;
432 QString text = m_clipboard->text(QClipboard::Selection);
434 vncThread.clientCut(text);
437 void VncView::clipboardDataChanged()
439 kDebug(5011);
441 if (m_status != Connected)
442 return;
444 if (m_clipboard->ownsClipboard() || m_dontSendClipboard)
445 return;
447 QString text = m_clipboard->text(QClipboard::Clipboard);
449 vncThread.clientCut(text);
452 #include "vncview.moc"