~ubuntu-branches/debian/lenny/italc/lenny

« back to all changes in this revision

Viewing changes to lib/src/vncview.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Patrick Winnertz
  • Date: 2008-06-17 13:46:54 UTC
  • mto: This revision was merged to the branch mainline in revision 5.
  • Revision ID: james.westby@ubuntu.com-20080617134654-2y5m7ki93r5c1ysf
Tags: upstream-1.0.9~rc3
ImportĀ upstreamĀ versionĀ 1.0.9~rc3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * vncview.cpp - VNC-viewer-widget
 
3
 *
 
4
 * Copyright (c) 2006-2008 Tobias Doerffel <tobydox/at/users/dot/sf/dot/net>
 
5
 *  
 
6
 * This file is part of iTALC - http://italc.sourceforge.net
 
7
 *
 
8
 * This program is free software; you can redistribute it and/or
 
9
 * modify it under the terms of the GNU General Public
 
10
 * License as published by the Free Software Foundation; either
 
11
 * version 2 of the License, or (at your option) any later version.
 
12
 *
 
13
 * This program is distributed in the hope that it will be useful,
 
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
16
 * General Public License for more details.
 
17
 *
 
18
 * You should have received a copy of the GNU General Public
 
19
 * License along with this program (see COPYING); if not, write to the
 
20
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 
21
 * Boston, MA 02111-1307, USA.
 
22
 *
 
23
 */
 
24
 
 
25
 
 
26
#define XK_KOREAN
 
27
#include "rfb/keysym.h"
 
28
 
 
29
#include "vncview.h"
 
30
#include "ivs_connection.h"
 
31
#include "messagebox.h"
 
32
#include "qt_user_events.h"
 
33
#include "progress_widget.h"
 
34
#include "system_key_trapper.h"
 
35
#include "qt_features.h"
 
36
#include "lock_widget.h"
 
37
 
 
38
#include <QtCore/QTimer>
 
39
#include <QtGui/QApplication>
 
40
#include <QtGui/QMouseEvent>
 
41
#include <QtGui/QPainter>
 
42
 
 
43
 
 
44
 
 
45
vncView::vncView( const QString & _host, QWidget * _parent,
 
46
                                                bool _progress_widget ) :
 
47
        QWidget( _parent ),
 
48
        m_connection( NULL ),
 
49
        m_viewOnly( TRUE ),
 
50
        m_viewOnlyFocus( TRUE ),
 
51
        m_scaledView( TRUE ),
 
52
        m_running( FALSE ),
 
53
        m_viewOffset( QPoint( 0, 0 ) ),
 
54
        m_buttonMask( 0 ),
 
55
        m_establishingConnection( NULL ),
 
56
        m_sysKeyTrapper( new systemKeyTrapper( FALSE ) )
 
57
{
 
58
        if( _progress_widget )
 
59
        {
 
60
                m_establishingConnection = new progressWidget(
 
61
                        tr( "Establishing connection to %1 ..." ).arg( _host ),
 
62
                                        ":/resources/watch%1.png", 16, this );
 
63
        }
 
64
 
 
65
        m_connection = new ivsConnection( _host, ivsConnection::QualityMedium,
 
66
                                                                FALSE, this );
 
67
        connect( m_connection, SIGNAL( cursorShapeChanged() ),
 
68
                                        this, SLOT( updateCursorShape() ) );
 
69
        setMouseTracking( TRUE );
 
70
        //setWidgetAttribute( Qt::WA_OpaquePaintEvent );
 
71
        setAttribute( Qt::WA_NoSystemBackground, true );
 
72
        setAttribute( Qt::WA_DeleteOnClose, true );
 
73
        showMaximized();
 
74
 
 
75
        QSize parent_size = size();
 
76
        if( parentWidget() != NULL )
 
77
        {
 
78
                parent_size = parentWidget()->size();
 
79
        }
 
80
        resize( parent_size );
 
81
 
 
82
        setFocusPolicy( Qt::StrongFocus );
 
83
        setFocus();
 
84
 
 
85
        new vncViewThread( this );
 
86
 
 
87
        framebufferUpdate();
 
88
}
 
89
 
 
90
 
 
91
 
 
92
 
 
93
vncView::~vncView()
 
94
{
 
95
        unpressModifiers();
 
96
        findChild<vncViewThread *>()->quit();
 
97
        findChild<vncViewThread *>()->wait();
 
98
        delete m_connection;
 
99
        delete m_sysKeyTrapper;
 
100
}
 
101
 
 
102
 
 
103
 
 
104
 
 
105
QSize vncView::scaledSize( const QSize & _default ) const
 
106
{
 
107
        const QSize s = size();
 
108
        QSize fbs = m_connection->framebufferSize();
 
109
        if( ( s.width() >= fbs.width() && s.height() >= fbs.height() ) ||
 
110
                                                        m_scaledView == FALSE )
 
111
        {
 
112
                return( _default );
 
113
        }
 
114
        fbs.scale( s, Qt::KeepAspectRatio );
 
115
        return( fbs );
 
116
}
 
117
 
 
118
 
 
119
 
 
120
 
 
121
void vncView::setViewOnly( bool _vo )
 
122
{
 
123
        if( _vo == m_viewOnly )
 
124
        {
 
125
                return;
 
126
        }
 
127
 
 
128
        m_viewOnly = _vo;
 
129
 
 
130
        if( m_viewOnly )
 
131
        {
 
132
                releaseKeyboard();
 
133
                m_sysKeyTrapper->setEnabled( FALSE );
 
134
                setCursor( Qt::ArrowCursor );
 
135
        }
 
136
        else
 
137
        {
 
138
#ifdef BUILD_LINUX
 
139
                // for some reason we have to grab mouse and then release
 
140
                // again to make complete keyboard-grabbing working ... ??
 
141
                grabMouse();
 
142
                releaseMouse();
 
143
#endif
 
144
                grabKeyboard();
 
145
                m_sysKeyTrapper->setEnabled( TRUE );
 
146
                updateCursorShape();
 
147
        }
 
148
}
 
149
 
 
150
 
 
151
 
 
152
 
 
153
void vncView::setScaledView( bool _sv )
 
154
{
 
155
        m_scaledView = _sv;
 
156
        if( m_connection != NULL )
 
157
        {
 
158
                m_connection->setScaledSize( scaledSize() );
 
159
        }
 
160
        update();
 
161
}
 
162
 
 
163
 
 
164
 
 
165
 
 
166
void vncView::framebufferUpdate( void )
 
167
{
 
168
        if( m_connection == NULL )
 
169
        {
 
170
                QTimer::singleShot( 40, this, SLOT( framebufferUpdate() ) );
 
171
                return;
 
172
        }
 
173
 
 
174
        const QPoint mp = mapFromGlobal( QCursor::pos() );
 
175
        // not yet connected or connection lost while handling messages?
 
176
        if( m_connection->state() != ivsConnection::Connected && m_running )
 
177
        {
 
178
                m_running = FALSE;
 
179
                if( m_establishingConnection )
 
180
                {
 
181
                        m_establishingConnection->show();
 
182
                }
 
183
                emit startConnection();
 
184
                QTimer::singleShot( 40, this, SLOT( framebufferUpdate() ) );
 
185
                if( mp.y() < 2 )
 
186
                {
 
187
                        // special signal for allowing parent-widgets to
 
188
                        // show a toolbar etc.
 
189
                        emit mouseAtTop();
 
190
                }
 
191
                return;
 
192
        }
 
193
 
 
194
        if( m_connection->state() == ivsConnection::Connected && !m_running )
 
195
        {
 
196
                if( m_establishingConnection )
 
197
                {
 
198
                        m_establishingConnection->hide();
 
199
                }
 
200
                m_running = TRUE;
 
201
                emit connectionEstablished();
 
202
 
 
203
                m_connection->setScaledSize( scaledSize() );
 
204
 
 
205
                if( parentWidget() )
 
206
                {
 
207
                        // if we have a parent it's likely remoteControlWidget
 
208
                        // which needs resize-events for updating its toolbar
 
209
                        // properly
 
210
                        parentWidget()->resize( parentWidget()->size() );
 
211
                }
 
212
        }
 
213
 
 
214
        if( m_scaledView == FALSE )
 
215
        {
 
216
                // check whether to scroll because mouse-cursor is at an egde which
 
217
                // doesn't correspond to the framebuffer's edge
 
218
                const QPoint old_vo = m_viewOffset;
 
219
                const int MAGIC_MARGIN = 15;
 
220
                if( mp.x() <= MAGIC_MARGIN && m_viewOffset.x() > 0 )
 
221
                {
 
222
                        m_viewOffset.setX( qMax( 0, m_viewOffset.x() -
 
223
                                                ( MAGIC_MARGIN - mp.x() ) ) );
 
224
                }
 
225
                else if( mp.x() > width() - MAGIC_MARGIN && m_viewOffset.x() <=
 
226
                                m_connection->framebufferSize().width() -
 
227
                                                                width() )
 
228
                {
 
229
                        m_viewOffset.setX( qMin( m_viewOffset.x() +
 
230
                                        ( MAGIC_MARGIN + mp.x() - width() ),
 
231
                                m_connection->framebufferSize().width() -
 
232
                                                                width() ) );
 
233
                }
 
234
 
 
235
                if( mp.y() <= MAGIC_MARGIN )
 
236
                {
 
237
                        if( m_viewOffset.y() > 0 )
 
238
                        {
 
239
                                m_viewOffset.setY( qMax( 0, m_viewOffset.y() -
 
240
                                                ( MAGIC_MARGIN - mp.y() ) ) );
 
241
                        }
 
242
                        else if( mp.y() < 2 )
 
243
                        {
 
244
                                // special signal for allowing parent-widgets to
 
245
                                // show a toolbar etc.
 
246
                                emit mouseAtTop();
 
247
                        }
 
248
                }
 
249
                else if( mp.y() > height() - MAGIC_MARGIN && m_viewOffset.y() <=
 
250
                                m_connection->framebufferSize().height() -
 
251
                                                                height() )
 
252
                {
 
253
                        m_viewOffset.setY( qMin( m_viewOffset.y() +
 
254
                                        ( MAGIC_MARGIN + mp.y() - height() ),
 
255
                                m_connection->framebufferSize().height() -
 
256
                                                                height() ) );
 
257
                }
 
258
 
 
259
                if( old_vo != m_viewOffset )
 
260
                {
 
261
                        update();
 
262
                }
 
263
        }
 
264
        else if( mp.y() <= 2 )
 
265
        {
 
266
                emit mouseAtTop();
 
267
        }
 
268
 
 
269
        QTimer::singleShot( 40, this, SLOT( framebufferUpdate() ) );
 
270
}
 
271
 
 
272
 
 
273
 
 
274
 
 
275
void vncView::updateCursorShape( void )
 
276
{
 
277
        if( !viewOnly() && !m_connection->cursorShape().isNull() )
 
278
        {
 
279
                setCursor( QCursor( QPixmap::fromImage(
 
280
                                                m_connection->cursorShape() ),
 
281
                        m_connection->cursorHotSpot().x(),
 
282
                        m_connection->cursorHotSpot().y() ) );
 
283
        }
 
284
}
 
285
 
 
286
 
 
287
 
 
288
 
 
289
// we have to filter key-events as QWidget's event()-implementation filters out
 
290
// Tab and Shift-Tab for changing focus but as we need Tab, we have to do
 
291
// key-event-dispatching on our own
 
292
bool vncView::event( QEvent * e )
 
293
{
 
294
        if( !m_viewOnly )
 
295
        {
 
296
                switch( e->type() )
 
297
                {
 
298
                        case QEvent::KeyPress:
 
299
                        case QEvent::KeyRelease:
 
300
                                keyEvent( (QKeyEvent *)( e ) );
 
301
                                return( e->isAccepted() );
 
302
                        default:
 
303
                                break;
 
304
                }
 
305
        }
 
306
        return( QWidget::event( e ) );
 
307
}
 
308
 
 
309
 
 
310
 
 
311
 
 
312
void vncView::focusInEvent( QFocusEvent * _e )
 
313
{
 
314
        if( !m_viewOnlyFocus )
 
315
        {
 
316
                setViewOnly( FALSE );
 
317
        }
 
318
        QWidget::focusInEvent( _e );
 
319
}
 
320
 
 
321
 
 
322
 
 
323
 
 
324
void vncView::focusOutEvent( QFocusEvent * _e )
 
325
{
 
326
        m_viewOnlyFocus = viewOnly();
 
327
        if( !viewOnly() )
 
328
        {
 
329
                setViewOnly( TRUE );
 
330
        }
 
331
        QWidget::focusOutEvent( _e );
 
332
}
 
333
 
 
334
 
 
335
 
 
336
 
 
337
// our builtin keyboard-handler
 
338
void vncView::keyEvent( QKeyEvent * _ke )
 
339
{
 
340
        bool pressed = _ke->type() == QEvent::KeyPress;
 
341
 
 
342
#ifdef NATIVE_VIRTUAL_KEY_SUPPORT
 
343
        // the Trolls seem to love us! With Qt 4.2 they introduced this cute
 
344
        // function returning the key-code of the key-event (platform-dependent)
 
345
        // so when operating under Linux/X11, key-codes are equal to the ones
 
346
        // used by VNC-protocol
 
347
        int key = _ke->nativeVirtualKey();
 
348
 
 
349
        // we do not handle Key_Backtab separately as the Shift-modifier
 
350
        // is already enabled
 
351
        if( _ke->key() == Qt::Key_Backtab )
 
352
        {
 
353
                key = XK_Tab;
 
354
        }
 
355
 
 
356
#else
 
357
        // hmm, either Win32-platform or too old Qt so we have to handle and
 
358
        // translate Qt-key-codes to X-keycodes
 
359
        int key = 0;
 
360
        switch( _ke->key() )
 
361
        {
 
362
                // modifiers are handled separately
 
363
                case Qt::Key_Shift: key = XK_Shift_L; break;
 
364
                case Qt::Key_Control: key = XK_Control_L; break;
 
365
                case Qt::Key_Meta: key = XK_Meta_L; break;
 
366
                case Qt::Key_Alt: key = XK_Alt_L; break;
 
367
                case Qt::Key_Escape: key = XK_Escape; break;
 
368
                case Qt::Key_Tab: key = XK_Tab; break;
 
369
                case Qt::Key_Backtab: key = XK_Tab; break;
 
370
                case Qt::Key_Backspace: key = XK_BackSpace; break;
 
371
                case Qt::Key_Return: key = XK_Return; break;
 
372
                case Qt::Key_Insert: key = XK_Insert; break;
 
373
                case Qt::Key_Delete: key = XK_Delete; break;
 
374
                case Qt::Key_Pause: key = XK_Pause; break;
 
375
                case Qt::Key_Print: key = XK_Print; break;
 
376
                case Qt::Key_Home: key = XK_Home; break;
 
377
                case Qt::Key_End: key = XK_End; break;
 
378
                case Qt::Key_Left: key = XK_Left; break;
 
379
                case Qt::Key_Up: key = XK_Up; break;
 
380
                case Qt::Key_Right: key = XK_Right; break;
 
381
                case Qt::Key_Down: key = XK_Down; break;
 
382
                case Qt::Key_PageUp: key = XK_Prior; break;
 
383
                case Qt::Key_PageDown: key = XK_Next; break;
 
384
                case Qt::Key_CapsLock: key = XK_Caps_Lock; break;
 
385
                case Qt::Key_NumLock: key = XK_Num_Lock; break;
 
386
                case Qt::Key_ScrollLock: key = XK_Scroll_Lock; break;
 
387
                case Qt::Key_Super_L: key = XK_Super_L; break;
 
388
                case Qt::Key_Super_R: key = XK_Super_R; break;
 
389
                case Qt::Key_Menu: key = XK_Menu; break;
 
390
                case Qt::Key_Hyper_L: key = XK_Hyper_L; break;
 
391
                case Qt::Key_Hyper_R: key = XK_Hyper_R; break;
 
392
                case Qt::Key_Help: key = XK_Help; break;
 
393
                case Qt::Key_AltGr: key = XK_ISO_Level3_Shift; break;
 
394
                case Qt::Key_Multi_key: key = XK_Multi_key; break;
 
395
                case Qt::Key_SingleCandidate: key = XK_SingleCandidate; break;
 
396
                case Qt::Key_MultipleCandidate: key = XK_MultipleCandidate; break;
 
397
                case Qt::Key_PreviousCandidate: key = XK_PreviousCandidate; break;
 
398
                case Qt::Key_Mode_switch: key = XK_Mode_switch; break;
 
399
                case Qt::Key_Kanji: key = XK_Kanji; break;
 
400
                case Qt::Key_Muhenkan: key = XK_Muhenkan; break;
 
401
                case Qt::Key_Henkan: key = XK_Henkan; break;
 
402
                case Qt::Key_Romaji: key = XK_Romaji; break;
 
403
                case Qt::Key_Hiragana: key = XK_Hiragana; break;
 
404
                case Qt::Key_Katakana: key = XK_Katakana; break;
 
405
                case Qt::Key_Hiragana_Katakana: key = XK_Hiragana_Katakana; break;
 
406
                case Qt::Key_Zenkaku: key = XK_Zenkaku; break;
 
407
                case Qt::Key_Hankaku: key = XK_Hankaku; break;
 
408
                case Qt::Key_Zenkaku_Hankaku: key = XK_Zenkaku_Hankaku; break;
 
409
                case Qt::Key_Touroku: key = XK_Touroku; break;
 
410
                case Qt::Key_Massyo: key = XK_Massyo; break;
 
411
                case Qt::Key_Kana_Lock: key = XK_Kana_Lock; break;
 
412
                case Qt::Key_Kana_Shift: key = XK_Kana_Shift; break;
 
413
                case Qt::Key_Eisu_Shift: key = XK_Eisu_Shift; break;
 
414
                case Qt::Key_Eisu_toggle: key = XK_Eisu_toggle; break;
 
415
                case Qt::Key_Hangul: key = XK_Hangul; break;
 
416
                case Qt::Key_Hangul_Start: key = XK_Hangul_Start; break;
 
417
                case Qt::Key_Hangul_End: key = XK_Hangul_End; break;
 
418
                case Qt::Key_Hangul_Hanja: key = XK_Hangul_Hanja; break;
 
419
                case Qt::Key_Hangul_Jamo: key = XK_Hangul_Jamo; break;
 
420
                case Qt::Key_Hangul_Romaja: key = XK_Hangul_Romaja; break;
 
421
                case Qt::Key_Hangul_Jeonja: key = XK_Hangul_Jeonja; break;
 
422
                case Qt::Key_Hangul_Banja: key = XK_Hangul_Banja; break;
 
423
                case Qt::Key_Hangul_PreHanja: key = XK_Hangul_PreHanja; break;
 
424
                case Qt::Key_Hangul_PostHanja: key = XK_Hangul_PostHanja; break;
 
425
                case Qt::Key_Hangul_Special: key = XK_Hangul_Special; break;
 
426
                case Qt::Key_Dead_Grave: key = XK_dead_grave; break;
 
427
                case Qt::Key_Dead_Acute: key = XK_dead_acute; break;
 
428
                case Qt::Key_Dead_Circumflex: key = XK_dead_circumflex; break;
 
429
                case Qt::Key_Dead_Tilde: key = XK_dead_tilde; break;
 
430
                case Qt::Key_Dead_Macron: key = XK_dead_macron; break;
 
431
                case Qt::Key_Dead_Breve: key = XK_dead_breve; break;
 
432
                case Qt::Key_Dead_Abovedot: key = XK_dead_abovedot; break;
 
433
                case Qt::Key_Dead_Diaeresis: key = XK_dead_diaeresis; break;
 
434
                case Qt::Key_Dead_Abovering: key = XK_dead_abovering; break;
 
435
                case Qt::Key_Dead_Doubleacute: key = XK_dead_doubleacute; break;
 
436
                case Qt::Key_Dead_Caron: key = XK_dead_caron; break;
 
437
                case Qt::Key_Dead_Cedilla: key = XK_dead_cedilla; break;
 
438
                case Qt::Key_Dead_Ogonek: key = XK_dead_ogonek; break;
 
439
                case Qt::Key_Dead_Iota: key = XK_dead_iota; break;
 
440
                case Qt::Key_Dead_Voiced_Sound: key = XK_dead_voiced_sound; break;
 
441
                case Qt::Key_Dead_Semivoiced_Sound: key = XK_dead_semivoiced_sound; break;
 
442
                case Qt::Key_Dead_Belowdot: key = XK_dead_belowdot; break;
 
443
        }
 
444
 
 
445
        if( _ke->key() >= Qt::Key_F1 && _ke->key() <= Qt::Key_F35 )
 
446
        {
 
447
                key = XK_F1 + _ke->key() - Qt::Key_F1;
 
448
        }
 
449
        else if( key == 0 )
 
450
        {
 
451
                if( m_mods.contains( XK_Control_L ) &&
 
452
                        QKeySequence( _ke->key() ).toString().length() == 1 )
 
453
                {
 
454
                        QString s = QKeySequence( _ke->key() ).toString();
 
455
                        if( !m_mods.contains( XK_Shift_L ) )
 
456
                        {
 
457
                                s = s.toLower();
 
458
                        }
 
459
                        key = s.utf16()[0];
 
460
                }
 
461
                else
 
462
                {
 
463
                        key = _ke->text().utf16()[0];
 
464
                }
 
465
                
 
466
        }
 
467
        // correct translation of AltGr+<character key> (non-US-keyboard layout
 
468
        // such as German keyboard layout)
 
469
        if( m_mods.contains( XK_Alt_L ) && m_mods.contains( XK_Control_L ) &&
 
470
                                                key >= 64 && key < 0xF000 )
 
471
        {
 
472
                unpressModifiers();
 
473
                emit keyEvent( XK_ISO_Level3_Shift, TRUE );
 
474
        }
 
475
#endif
 
476
 
 
477
        // handle modifiers
 
478
        if( key == XK_Shift_L || key == XK_Control_L || key == XK_Meta_L ||
 
479
                                                        key == XK_Alt_L )
 
480
        {
 
481
                if( pressed )
 
482
                {
 
483
                        m_mods[key] = true;
 
484
                }
 
485
                else if( m_mods.contains( key ) )
 
486
                {
 
487
                        m_mods.remove( key );
 
488
                }
 
489
                else
 
490
                {
 
491
                        unpressModifiers();
 
492
                }
 
493
        }
 
494
 
 
495
        if( key )
 
496
        {
 
497
                emit keyEvent( key, pressed );
 
498
                _ke->accept();
 
499
        }
 
500
}
 
501
 
 
502
 
 
503
 
 
504
 
 
505
void vncView::unpressModifiers( void )
 
506
{
 
507
        QList<unsigned int> keys = m_mods.keys();
 
508
        QList<unsigned int>::const_iterator it = keys.begin();
 
509
        while( it != keys.end() )
 
510
        {
 
511
                emit keyEvent( *it, FALSE );
 
512
                it++;
 
513
        }
 
514
        m_mods.clear();
 
515
}
 
516
 
 
517
 
 
518
 
 
519
 
 
520
QPoint vncView::mapToFramebuffer( const QPoint & _pos )
 
521
{
 
522
        const QSize fbs = m_connection ? m_connection->framebufferSize() :
 
523
                                                                        QSize();
 
524
        const int x = m_scaledView && fbs.isValid() ?
 
525
                        _pos.x() * fbs.width() / scaledSize( fbs ).width()
 
526
                :
 
527
                        _pos.x() + m_viewOffset.x();
 
528
        const int y = m_scaledView && m_connection ?
 
529
                        _pos.y() * fbs.height() / scaledSize( fbs ).height()
 
530
                :
 
531
                        _pos.y() + m_viewOffset.y();
 
532
        return( QPoint( x, y ) );
 
533
}
 
534
 
 
535
 
 
536
 
 
537
 
 
538
QRect vncView::mapFromFramebuffer( const QRect & _r )
 
539
{
 
540
        if( m_scaledView && m_connection )
 
541
        {
 
542
                const float dx = width() / (float)
 
543
                                m_connection->framebufferSize().width();
 
544
                const float dy = height() / (float)
 
545
                                m_connection->framebufferSize().height();
 
546
                return( QRect( (int)(_r.x()*dx), (int)(_r.y()*dy),
 
547
                                        (int)(_r.width()*dx), (int)(_r.height()*dy) ) );
 
548
        }
 
549
        return( _r.translated( -m_viewOffset ) );
 
550
}
 
551
 
 
552
 
 
553
 
 
554
 
 
555
void vncView::mouseMoveEvent( QMouseEvent * _me )
 
556
{
 
557
        mouseEvent( _me );
 
558
        _me->ignore();
 
559
}
 
560
 
 
561
 
 
562
 
 
563
 
 
564
void vncView::mousePressEvent( QMouseEvent * _me )
 
565
{
 
566
        mouseEvent( _me );
 
567
        _me->accept();
 
568
}
 
569
 
 
570
 
 
571
 
 
572
 
 
573
void vncView::mouseReleaseEvent( QMouseEvent * _me )
 
574
{
 
575
        mouseEvent( _me );
 
576
        _me->accept();
 
577
}
 
578
 
 
579
 
 
580
 
 
581
 
 
582
void vncView::mouseDoubleClickEvent( QMouseEvent * _me )
 
583
{
 
584
        mouseEvent( _me );
 
585
        _me->accept();
 
586
}
 
587
 
 
588
 
 
589
 
 
590
 
 
591
 
 
592
void vncView::paintEvent( QPaintEvent * _pe )
 
593
{
 
594
        QPainter p( this );
 
595
 
 
596
        // avoid nasty through-shining-window-effect when not connected yet
 
597
        if( m_connection->screen().isNull() )
 
598
        {
 
599
                p.fillRect( _pe->rect(), Qt::black );
 
600
                return;
 
601
        }
 
602
 
 
603
        const QSize ss = scaledSize();
 
604
 
 
605
        // only paint requested region of image
 
606
        p.drawImage( _pe->rect().topLeft(),
 
607
                        ss.isValid() ?
 
608
                                m_connection->scaledScreen() :
 
609
                                                m_connection->screen(),
 
610
                        _pe->rect().translated( m_viewOffset ),
 
611
                        Qt::ThresholdDither );
 
612
 
 
613
        if( viewOnly() && !m_connection->cursorShape().isNull() )
 
614
        {
 
615
                const QImage & cursor = m_connection->cursorShape();
 
616
                const QRect cursor_rect = mapFromFramebuffer(
 
617
                        QRect( m_connection->cursorPos() -
 
618
                                                m_connection->cursorHotSpot(),
 
619
                                                        cursor.size() ) );
 
620
                // parts of cursor within updated region?
 
621
                if( _pe->rect().intersects( cursor_rect ) )
 
622
                {
 
623
                        // then repaint it
 
624
                        p.drawImage( cursor_rect.topLeft(), cursor );
 
625
                }
 
626
        }
 
627
 
 
628
        // draw black borders if neccessary
 
629
        const int fbw = ss.isValid() ? ss.width() :
 
630
                                m_connection->framebufferSize().width();
 
631
        if( fbw < width() )
 
632
        {
 
633
                p.fillRect( fbw, 0, width() - fbw, height(), Qt::black );
 
634
        }
 
635
        const int fbh = ss.isValid() ? ss.height() :
 
636
                                m_connection->framebufferSize().height();
 
637
        if( fbh < height() )
 
638
        {
 
639
                p.fillRect( 0, fbh, fbw, height() - fbh, Qt::black );
 
640
        }
 
641
}
 
642
 
 
643
 
 
644
 
 
645
 
 
646
void vncView::resizeEvent( QResizeEvent * _re )
 
647
{
 
648
        m_connection->setScaledSize( scaledSize() );
 
649
        const int max_x = m_connection->framebufferSize().width() - width();
 
650
        const int max_y = m_connection->framebufferSize().height() - height();
 
651
        if( m_viewOffset.x() > max_x || m_viewOffset.y() > max_y )
 
652
        {
 
653
                m_viewOffset = QPoint(
 
654
                                qMax( 0, qMin( m_viewOffset.x(), max_x ) ),
 
655
                                qMax( 0, qMin( m_viewOffset.y(), max_y ) ) );
 
656
                update();
 
657
        }
 
658
 
 
659
        if( m_establishingConnection )
 
660
        {
 
661
                m_establishingConnection->move( 10, 10 );
 
662
        }
 
663
 
 
664
        QWidget::resizeEvent( _re );
 
665
}
 
666
 
 
667
 
 
668
 
 
669
 
 
670
void vncView::wheelEvent( QWheelEvent * _we )
 
671
{
 
672
        const QPoint p = mapToFramebuffer( _we->pos() );
 
673
        emit pointerEvent( p.x(), p.y(), m_buttonMask |
 
674
                ( ( _we->delta() < 0 ) ? rfbButton5Mask : rfbButton4Mask ) );
 
675
        emit pointerEvent( p.x(), p.y(), m_buttonMask );
 
676
        
 
677
        _we->accept();
 
678
}
 
679
 
 
680
 
 
681
 
 
682
 
 
683
void vncView::customEvent( QEvent * _e )
 
684
{
 
685
        if( _e->type() == regionChangedEvent().type() )
 
686
        {
 
687
                update();
 
688
                _e->accept();
 
689
        }
 
690
        else
 
691
        {
 
692
                QWidget::customEvent( _e );
 
693
        }
 
694
}
 
695
 
 
696
 
 
697
 
 
698
 
 
699
void vncView::mouseEvent( QMouseEvent * _me )
 
700
{
 
701
        struct buttonXlate
 
702
        {
 
703
                Qt::MouseButton qt;
 
704
                int rfb;
 
705
        } const map[] =
 
706
                {
 
707
                        { Qt::LeftButton, rfbButton1Mask },
 
708
                        { Qt::MidButton, rfbButton2Mask },
 
709
                        { Qt::RightButton, rfbButton3Mask }
 
710
                } ;
 
711
 
 
712
        if( _me->type() != QEvent::MouseMove )
 
713
        {
 
714
                for( Q_UINT8 i = 0; i < sizeof(map)/sizeof(buttonXlate); ++i )
 
715
                {
 
716
                        if( _me->button() == map[i].qt )
 
717
                        {
 
718
                                if( _me->type() == QEvent::MouseButtonPress ||
 
719
                                _me->type() == QEvent::MouseButtonDblClick )
 
720
                                {
 
721
                                        m_buttonMask |= map[i].rfb;
 
722
                                }
 
723
                                else
 
724
                                {
 
725
                                        m_buttonMask &= ~map[i].rfb;
 
726
                                }
 
727
                        }
 
728
                }
 
729
        }
 
730
 
 
731
        const QPoint p = mapToFramebuffer( _me->pos() );
 
732
        emit pointerEvent( p.x(), p.y(), m_buttonMask );
 
733
}
 
734
 
 
735
 
 
736
 
 
737
 
 
738
 
 
739
 
 
740
 
 
741
 
 
742
vncViewThread::vncViewThread( vncView * _vv ) :
 
743
        QThread( _vv ),
 
744
        m_vncView( _vv )
 
745
{
 
746
        start( QThread::HighPriority );
 
747
}
 
748
 
 
749
 
 
750
 
 
751
 
 
752
void vncViewThread::run( void )
 
753
{
 
754
        vncWorker vw( m_vncView );
 
755
        exec();
 
756
}
 
757
 
 
758
 
 
759
 
 
760
 
 
761
 
 
762
 
 
763
vncWorker::vncWorker( vncView * _vv ) :
 
764
        QObject(),
 
765
        m_vncView( _vv )
 
766
{
 
767
        qRegisterMetaType<Q_UINT16>( "Q_UINT16" );
 
768
        qRegisterMetaType<Q_UINT32>( "Q_UINT32" );
 
769
        connect( m_vncView->m_sysKeyTrapper,
 
770
                                SIGNAL( keyEvent( Q_UINT32, bool ) ),
 
771
                                this, SLOT( sendKeyEvent( Q_UINT32, bool ) ) );
 
772
 
 
773
        connect( m_vncView,
 
774
                SIGNAL( pointerEvent( Q_UINT16, Q_UINT16, Q_UINT16 ) ),
 
775
                this, SLOT( sendPointerEvent( Q_UINT16, Q_UINT16,
 
776
                                                                Q_UINT16 ) ) );
 
777
        connect( m_vncView, SIGNAL( keyEvent( Q_UINT32, bool ) ),
 
778
                                this, SLOT( sendKeyEvent( Q_UINT32, bool ) ) );
 
779
 
 
780
 
 
781
        ivsConnection * conn = m_vncView->m_connection;
 
782
        QTimer * t = new QTimer( this );
 
783
        connect( t, SIGNAL( timeout() ), conn,
 
784
                        SLOT( sendIncrementalFramebufferUpdateRequest() ),
 
785
                                                        Qt::DirectConnection );
 
786
        t->start( 50 );
 
787
 
 
788
        t = new QTimer( this );
 
789
        connect( t, SIGNAL( timeout() ), this,
 
790
                        SLOT( framebufferUpdate() ) );
 
791
        t->start( 25 );
 
792
}
 
793
 
 
794
 
 
795
 
 
796
 
 
797
vncWorker::~vncWorker()
 
798
{
 
799
        // have to close the connection here for destroying/closing everything
 
800
        // within the same thread - otherwise Qt might complain or even let us
 
801
        // crash...
 
802
        m_vncView->m_connection->close();
 
803
}
 
804
 
 
805
 
 
806
 
 
807
 
 
808
void vncWorker::framebufferUpdate( void )
 
809
{
 
810
        ivsConnection * conn = m_vncView->m_connection;
 
811
        if( conn->state() != ivsConnection::Connected ||
 
812
                                !conn->handleServerMessages( FALSE, 3 ) )
 
813
        {
 
814
                conn->open();
 
815
        }
 
816
}
 
817
 
 
818
 
 
819
 
 
820
 
 
821
void vncWorker::sendPointerEvent( Q_UINT16 _x, Q_UINT16 _y,
 
822
                                                        Q_UINT16 _button_mask )
 
823
{
 
824
        if( !m_vncView->viewOnly() )
 
825
        {
 
826
                m_vncView->m_connection->sendPointerEvent( _x, _y,
 
827
                                                                _button_mask );
 
828
        }
 
829
}
 
830
 
 
831
 
 
832
 
 
833
 
 
834
void vncWorker::sendKeyEvent( Q_UINT32 _key, bool _down )
 
835
{
 
836
        if( !m_vncView->viewOnly() )
 
837
        {
 
838
                m_vncView->m_connection->sendKeyEvent( _key, _down );
 
839
        }
 
840
}
 
841
 
 
842
 
 
843
 
 
844
 
 
845
#include "vncview.moc"
 
846