|
|
|
/***************************************************************************
|
|
|
|
kvncview.cpp - main widget
|
|
|
|
-------------------
|
|
|
|
begin : Thu Dec 20 15:11:42 CET 2001
|
|
|
|
copyright : (C) 2001-2003 by Tim Jansen
|
|
|
|
email : tim@tjansen.de
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
* *
|
|
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
|
|
* it under the terms of the GNU General Public License as published by *
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
|
|
* (at your option) any later version. *
|
|
|
|
* *
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
#include "kvncview.h"
|
|
|
|
#include "vncprefs.h"
|
|
|
|
#include "vnchostpref.h"
|
|
|
|
|
|
|
|
#include <kapplication.h>
|
|
|
|
#include <kdebug.h>
|
|
|
|
#include <klocale.h>
|
|
|
|
#include <kmessagebox.h>
|
|
|
|
#include <kstandarddirs.h>
|
|
|
|
#include <kpassdlg.h>
|
|
|
|
#include <kdialogbase.h>
|
|
|
|
#include <kwallet.h>
|
|
|
|
|
|
|
|
#include <tqdatastream.h>
|
|
|
|
#include <dcopclient.h>
|
|
|
|
#include <tqclipboard.h>
|
|
|
|
#include <tqbitmap.h>
|
|
|
|
#include <tqmutex.h>
|
|
|
|
#include <tqvbox.h>
|
|
|
|
#include <tqwaitcondition.h>
|
|
|
|
|
|
|
|
#include "vncviewer.h"
|
|
|
|
|
|
|
|
#include <X11/Xlib.h>
|
|
|
|
|
|
|
|
bool launch_Fullscreen_vnc = false;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* appData is our application-specific data which can be set by the user with
|
|
|
|
* application resource specs. The AppData structure is defined in the header
|
|
|
|
* file.
|
|
|
|
*/
|
|
|
|
AppData appData;
|
|
|
|
bool appDataConfigured = false;
|
|
|
|
|
|
|
|
Display* dpy;
|
|
|
|
|
|
|
|
static KVncView *kvncview;
|
|
|
|
|
|
|
|
//Passwords and KWallet data
|
|
|
|
extern KWallet::Wallet *wallet;
|
|
|
|
bool useKWallet = false;
|
|
|
|
static TQCString password;
|
|
|
|
static TQMutex passwordLock;
|
|
|
|
static TQWaitCondition passwordWaiter;
|
|
|
|
|
|
|
|
const unsigned int MAX_SELECTION_LENGTH = 4096;
|
|
|
|
|
|
|
|
|
|
|
|
KVncView::KVncView(TQWidget *parent,
|
|
|
|
const char *name,
|
|
|
|
const TQString &_host,
|
|
|
|
int _port,
|
|
|
|
const TQString &_password,
|
|
|
|
Quality quality,
|
|
|
|
DotCursorState dotCursorState,
|
|
|
|
const TQString &encodings) :
|
|
|
|
KRemoteView(parent, name, Qt::WResizeNoErase | Qt::WRepaintNoErase | Qt::WStaticContents),
|
|
|
|
m_cthread(this, m_wthread, m_quitFlag),
|
|
|
|
m_wthread(this, m_quitFlag),
|
|
|
|
m_quitFlag(false),
|
|
|
|
m_enableFramebufferLocking(false),
|
|
|
|
m_scaling(false),
|
|
|
|
m_remoteMouseTracking(false),
|
|
|
|
m_viewOnly(false),
|
|
|
|
m_buttonMask(0),
|
|
|
|
m_host(_host),
|
|
|
|
m_port(_port),
|
|
|
|
m_dontSendCb(false),
|
|
|
|
m_cursorState(dotCursorState)
|
|
|
|
{
|
|
|
|
kvncview = this;
|
|
|
|
password = _password.latin1();
|
|
|
|
dpy = qt_xdisplay();
|
|
|
|
setFixedSize(16,16);
|
|
|
|
setFocusPolicy(TQWidget::StrongFocus);
|
|
|
|
|
|
|
|
m_cb = TQApplication::clipboard();
|
|
|
|
connect(m_cb, TQT_SIGNAL(selectionChanged()), this, TQT_SLOT(selectionChanged()));
|
|
|
|
connect(m_cb, TQT_SIGNAL(dataChanged()), this, TQT_SLOT(clipboardChanged()));
|
|
|
|
|
|
|
|
KStandardDirs *dirs = KGlobal::dirs();
|
|
|
|
TQBitmap cursorBitmap(dirs->findResource("appdata",
|
|
|
|
"pics/pointcursor.png"));
|
|
|
|
TQBitmap cursorMask(dirs->findResource("appdata",
|
|
|
|
"pics/pointcursormask.png"));
|
|
|
|
m_cursor = TQCursor(cursorBitmap, cursorMask);
|
|
|
|
|
|
|
|
if ((quality != QUALITY_UNKNOWN) ||
|
|
|
|
!encodings.isNull())
|
|
|
|
configureApp(quality, encodings);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KVncView::showDotCursor(DotCursorState state) {
|
|
|
|
if (state == m_cursorState)
|
|
|
|
return;
|
|
|
|
|
|
|
|
m_cursorState = state;
|
|
|
|
showDotCursorInternal();
|
|
|
|
}
|
|
|
|
|
|
|
|
DotCursorState KVncView::dotCursorState() const {
|
|
|
|
return m_cursorState;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KVncView::showDotCursorInternal() {
|
|
|
|
switch (m_cursorState) {
|
|
|
|
case DOT_CURSOR_ON:
|
|
|
|
setCursor(m_cursor);
|
|
|
|
break;
|
|
|
|
case DOT_CURSOR_OFF:
|
|
|
|
setCursor(TQCursor(Qt::BlankCursor));
|
|
|
|
break;
|
|
|
|
case DOT_CURSOR_AUTO:
|
|
|
|
if (m_enableClientCursor)
|
|
|
|
setCursor(TQCursor(Qt::BlankCursor));
|
|
|
|
else
|
|
|
|
setCursor(m_cursor);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString KVncView::host() {
|
|
|
|
return m_host;
|
|
|
|
}
|
|
|
|
|
|
|
|
int KVncView::port() {
|
|
|
|
return m_port;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KVncView::startQuitting() {
|
|
|
|
m_quitFlag = true;
|
|
|
|
m_wthread.kick();
|
|
|
|
m_cthread.kick();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KVncView::isQuitting() {
|
|
|
|
return m_quitFlag;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KVncView::configureApp(Quality q, const TQString specialEncodings) {
|
|
|
|
appDataConfigured = true;
|
|
|
|
appData.shareDesktop = 1;
|
|
|
|
appData.viewOnly = 0;
|
|
|
|
|
|
|
|
if (q == QUALITY_LOW) {
|
|
|
|
appData.useBGR233 = 1;
|
|
|
|
appData.encodingsString = "background copyrect softcursor tight zlib hextile raw";
|
|
|
|
appData.compressLevel = -1;
|
|
|
|
appData.qualityLevel = 1;
|
|
|
|
appData.dotCursor = 1;
|
|
|
|
}
|
|
|
|
else if (q == QUALITY_MEDIUM) {
|
|
|
|
appData.useBGR233 = 0;
|
|
|
|
appData.encodingsString = "background copyrect softcursor tight zlib hextile raw";
|
|
|
|
appData.compressLevel = -1;
|
|
|
|
appData.qualityLevel = 7;
|
|
|
|
appData.dotCursor = 1;
|
|
|
|
}
|
|
|
|
else if ((q == QUALITY_HIGH) || (q == QUALITY_UNKNOWN)) {
|
|
|
|
appData.useBGR233 = 0;
|
|
|
|
appData.encodingsString = "copyrect softcursor hextile raw";
|
|
|
|
appData.compressLevel = -1;
|
|
|
|
appData.qualityLevel = 9;
|
|
|
|
appData.dotCursor = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!specialEncodings.isNull())
|
|
|
|
appData.encodingsString = specialEncodings.latin1();
|
|
|
|
|
|
|
|
appData.nColours = 256;
|
|
|
|
appData.useSharedColours = 1;
|
|
|
|
appData.requestedDepth = 0;
|
|
|
|
|
|
|
|
appData.rawDelay = 0;
|
|
|
|
appData.copyRectDelay = 0;
|
|
|
|
|
|
|
|
if (!appData.dotCursor)
|
|
|
|
m_cursorState = DOT_CURSOR_OFF;
|
|
|
|
showDotCursorInternal();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KVncView::checkLocalKRfb() {
|
|
|
|
if ( m_host != "localhost" && !m_host.isEmpty() )
|
|
|
|
return true;
|
|
|
|
DCOPClient *d = KApplication::dcopClient();
|
|
|
|
|
|
|
|
int portNum;
|
|
|
|
TQByteArray sdata, rdata;
|
|
|
|
TQCString replyType;
|
|
|
|
TQDataStream arg(sdata, IO_WriteOnly);
|
|
|
|
arg << TQString("krfb");
|
|
|
|
if (!d->call ("kded", "kinetd", "port(TQString)", sdata, replyType, rdata))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (replyType != "int")
|
|
|
|
return true;
|
|
|
|
|
|
|
|
TQDataStream answer(rdata, IO_ReadOnly);
|
|
|
|
answer >> portNum;
|
|
|
|
|
|
|
|
if (m_port != portNum)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
setStatus(REMOTE_VIEW_DISCONNECTED);
|
|
|
|
KMessageBox::error(0,
|
|
|
|
i18n("It is not possible to connect to a local desktop sharing service."),
|
|
|
|
i18n("Connection Failure"));
|
|
|
|
emit disconnectedError();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KVncView::editPreferences( HostPrefPtr host )
|
|
|
|
{
|
|
|
|
SmartPtr<VncHostPref> hp( host );
|
|
|
|
|
|
|
|
int ci = hp->quality();
|
|
|
|
bool kwallet = hp->useKWallet();
|
|
|
|
|
|
|
|
// show preferences dialog
|
|
|
|
KDialogBase *dlg = new KDialogBase( 0L, "dlg", true,
|
|
|
|
i18n( "VNC Host Preferences for %1" ).arg( host->host() ),
|
|
|
|
KDialogBase::Ok|KDialogBase::Cancel, KDialogBase::Ok, true );
|
|
|
|
|
|
|
|
TQVBox *vbox = dlg->makeVBoxMainWidget();
|
|
|
|
VncPrefs *prefs = new VncPrefs( vbox );
|
|
|
|
TQWidget *spacer = new TQWidget( vbox );
|
|
|
|
vbox->setStretchFactor( spacer, 10 );
|
|
|
|
|
|
|
|
prefs->setQuality( ci );
|
|
|
|
prefs->setShowPrefs(true);
|
|
|
|
prefs->setUseKWallet(kwallet);
|
|
|
|
|
|
|
|
if ( dlg->exec() == TQDialog::Rejected )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
ci = prefs->quality();
|
|
|
|
hp->setAskOnConnect(prefs->showPrefs());
|
|
|
|
hp->setQuality(ci);
|
|
|
|
hp->setUseKWallet(prefs->useKWallet());
|
|
|
|
|
|
|
|
delete dlg;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KVncView::start() {
|
|
|
|
|
|
|
|
if (!checkLocalKRfb())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!appDataConfigured) {
|
|
|
|
|
|
|
|
HostPreferences *hps = HostPreferences::instance();
|
|
|
|
SmartPtr<VncHostPref> hp =
|
|
|
|
SmartPtr<VncHostPref>(hps->createHostPref(m_host,
|
|
|
|
VncHostPref::VncType));
|
|
|
|
if (hp->askOnConnect()) {
|
|
|
|
if (!editPreferences(hp))
|
|
|
|
return false;
|
|
|
|
hps->sync();
|
|
|
|
}
|
|
|
|
|
|
|
|
int ci = hp->quality();
|
|
|
|
|
|
|
|
Quality quality;
|
|
|
|
if (ci == 0)
|
|
|
|
quality = QUALITY_HIGH;
|
|
|
|
else if (ci == 1)
|
|
|
|
quality = QUALITY_MEDIUM;
|
|
|
|
else if (ci == 2)
|
|
|
|
quality = QUALITY_LOW;
|
|
|
|
else {
|
|
|
|
kdDebug() << "Unknown quality";
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
configureApp(quality);
|
|
|
|
useKWallet = hp->useKWallet();
|
|
|
|
}
|
|
|
|
|
|
|
|
setStatus(REMOTE_VIEW_CONNECTING);
|
|
|
|
|
|
|
|
m_cthread.start();
|
|
|
|
setBackgroundMode(Qt::NoBackground);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
KVncView::~KVncView()
|
|
|
|
{
|
|
|
|
startQuitting();
|
|
|
|
m_cthread.wait();
|
|
|
|
m_wthread.wait();
|
|
|
|
freeResources();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KVncView::supportsLocalCursor() const {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KVncView::supportsScaling() const {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KVncView::scaling() const {
|
|
|
|
return m_scaling;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KVncView::viewOnly() {
|
|
|
|
return m_viewOnly;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KVncView::startFullscreen()
|
|
|
|
{
|
|
|
|
return launch_Fullscreen_vnc;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQSize KVncView::framebufferSize() {
|
|
|
|
return m_framebufferSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KVncView::setViewOnly(bool s) {
|
|
|
|
m_viewOnly = s;
|
|
|
|
|
|
|
|
if (s)
|
|
|
|
setCursor(Qt::ArrowCursor);
|
|
|
|
else
|
|
|
|
showDotCursorInternal();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KVncView::enableScaling(bool s) {
|
|
|
|
bool os = m_scaling;
|
|
|
|
m_scaling = s;
|
|
|
|
if (s != os) {
|
|
|
|
if (s) {
|
|
|
|
setMaximumSize(m_framebufferSize);
|
|
|
|
setMinimumSize(m_framebufferSize.width()/16,
|
|
|
|
m_framebufferSize.height()/16);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
setFixedSize(m_framebufferSize);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KVncView::paintEvent(TQPaintEvent *e) {
|
|
|
|
drawRegion(e->rect().x(),
|
|
|
|
e->rect().y(),
|
|
|
|
e->rect().width(),
|
|
|
|
e->rect().height());
|
|
|
|
}
|
|
|
|
|
|
|
|
void KVncView::drawRegion(int x, int y, int w, int h) {
|
|
|
|
if (m_scaling)
|
|
|
|
DrawZoomedScreenRegionX11Thread(winId(), width(), height(),
|
|
|
|
x, y, w, h);
|
|
|
|
else
|
|
|
|
DrawScreenRegionX11Thread(winId(), x, y, w, h);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KVncView::customEvent(TQCustomEvent *e)
|
|
|
|
{
|
|
|
|
if (e->type() == ScreenRepaintEventType) {
|
|
|
|
ScreenRepaintEvent *sre = (ScreenRepaintEvent*) e;
|
|
|
|
drawRegion(sre->x(), sre->y(),sre->width(), sre->height());
|
|
|
|
}
|
|
|
|
else if (e->type() == ScreenResizeEventType) {
|
|
|
|
ScreenResizeEvent *sre = (ScreenResizeEvent*) e;
|
|
|
|
m_framebufferSize = TQSize(sre->width(), sre->height());
|
|
|
|
setFixedSize(m_framebufferSize);
|
|
|
|
emit changeSize(sre->width(), sre->height());
|
|
|
|
}
|
|
|
|
else if (e->type() == DesktopInitEventType) {
|
|
|
|
m_cthread.desktopInit();
|
|
|
|
}
|
|
|
|
else if (e->type() == StatusChangeEventType) {
|
|
|
|
StatusChangeEvent *sce = (StatusChangeEvent*) e;
|
|
|
|
setStatus(sce->status());
|
|
|
|
if (m_status == REMOTE_VIEW_CONNECTED) {
|
|
|
|
emit connected();
|
|
|
|
setFocus();
|
|
|
|
setMouseTracking(true);
|
|
|
|
}
|
|
|
|
else if (m_status == REMOTE_VIEW_DISCONNECTED) {
|
|
|
|
setMouseTracking(false);
|
|
|
|
emit disconnected();
|
|
|
|
}
|
|
|
|
else if (m_status == REMOTE_VIEW_PREPARING) {
|
|
|
|
//Login was successfull: Write KWallet password if necessary.
|
|
|
|
if ( useKWallet && !password.isNull() && wallet && wallet->isOpen() && !wallet->hasEntry(host())) {
|
|
|
|
wallet->writePassword(host(), password);
|
|
|
|
}
|
|
|
|
delete wallet; wallet=0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (e->type() == PasswordRequiredEventType) {
|
|
|
|
emit showingPasswordDialog(true);
|
|
|
|
|
|
|
|
if (KPasswordDialog::getPassword(password, i18n("Access to the system requires a password.")) != KPasswordDialog::Accepted)
|
|
|
|
password = TQCString();
|
|
|
|
|
|
|
|
emit showingPasswordDialog(false);
|
|
|
|
|
|
|
|
passwordLock.lock(); // to guarantee that thread is waiting
|
|
|
|
passwordWaiter.wakeAll();
|
|
|
|
passwordLock.unlock();
|
|
|
|
}
|
|
|
|
else if (e->type() == WalletOpenEventType) {
|
|
|
|
TQString krdc_folder = "KRDC-VNC";
|
|
|
|
emit showingPasswordDialog(true); //Bad things happen if you don't do this.
|
|
|
|
|
|
|
|
// Bugfix: Check if wallet has been closed by an outside source
|
|
|
|
if ( wallet && !wallet->isOpen() ) {
|
|
|
|
delete wallet; wallet=0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Do we need to open the wallet?
|
|
|
|
if ( !wallet ) {
|
|
|
|
TQString walletName = KWallet::Wallet::NetworkWallet();
|
|
|
|
wallet = KWallet::Wallet::openWallet(walletName);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (wallet && wallet->isOpen()) {
|
|
|
|
bool walletOK = wallet->hasFolder(krdc_folder);
|
|
|
|
if (walletOK == false) {
|
|
|
|
walletOK = wallet->createFolder(krdc_folder);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (walletOK == true) {
|
|
|
|
wallet->setFolder(krdc_folder);
|
|
|
|
TQString newPass;
|
|
|
|
if ( wallet->hasEntry(kvncview->host()) && !wallet->readPassword(kvncview->host(), newPass) ) {
|
|
|
|
password=newPass.latin1();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
passwordLock.lock(); // to guarantee that thread is waiting
|
|
|
|
passwordWaiter.wakeAll();
|
|
|
|
passwordLock.unlock();
|
|
|
|
|
|
|
|
emit showingPasswordDialog(false);
|
|
|
|
}
|
|
|
|
else if (e->type() == FatalErrorEventType) {
|
|
|
|
FatalErrorEvent *fee = (FatalErrorEvent*) e;
|
|
|
|
setStatus(REMOTE_VIEW_DISCONNECTED);
|
|
|
|
switch (fee->errorCode()) {
|
|
|
|
case ERROR_CONNECTION:
|
|
|
|
KMessageBox::error(0,
|
|
|
|
i18n("Connection attempt to host failed."),
|
|
|
|
i18n("Connection Failure"));
|
|
|
|
break;
|
|
|
|
case ERROR_PROTOCOL:
|
|
|
|
KMessageBox::error(0,
|
|
|
|
i18n("Remote host is using an incompatible protocol."),
|
|
|
|
i18n("Connection Failure"));
|
|
|
|
break;
|
|
|
|
case ERROR_IO:
|
|
|
|
KMessageBox::error(0,
|
|
|
|
i18n("The connection to the host has been interrupted."),
|
|
|
|
i18n("Connection Failure"));
|
|
|
|
break;
|
|
|
|
case ERROR_SERVER_BLOCKED:
|
|
|
|
KMessageBox::error(0,
|
|
|
|
i18n("Connection failed. The server does not accept new connections."),
|
|
|
|
i18n("Connection Failure"));
|
|
|
|
break;
|
|
|
|
case ERROR_NAME:
|
|
|
|
KMessageBox::error(0,
|
|
|
|
i18n("Connection failed. A server with the given name cannot be found."),
|
|
|
|
i18n("Connection Failure"));
|
|
|
|
break;
|
|
|
|
case ERROR_NO_SERVER:
|
|
|
|
KMessageBox::error(0,
|
|
|
|
i18n("Connection failed. No server running at the given address and port."),
|
|
|
|
i18n("Connection Failure"));
|
|
|
|
break;
|
|
|
|
case ERROR_AUTHENTICATION:
|
|
|
|
//Login failed: Remove wallet entry if there is one.
|
|
|
|
if ( useKWallet && wallet && wallet->isOpen() && wallet->hasEntry(host()) ) {
|
|
|
|
wallet->removeEntry(host());
|
|
|
|
}
|
|
|
|
KMessageBox::error(0,
|
|
|
|
i18n("Authentication failed. Connection aborted."),
|
|
|
|
i18n("Authentication Failure"));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
KMessageBox::error(0,
|
|
|
|
i18n("Unknown error."),
|
|
|
|
i18n("Unknown Error"));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
emit disconnectedError();
|
|
|
|
}
|
|
|
|
else if (e->type() == BeepEventType) {
|
|
|
|
TQApplication::beep();
|
|
|
|
}
|
|
|
|
else if (e->type() == ServerCutEventType) {
|
|
|
|
ServerCutEvent *sce = (ServerCutEvent*) e;
|
|
|
|
TQString ctext = TQString::fromUtf8(sce->bytes(), sce->length());
|
|
|
|
m_dontSendCb = true;
|
|
|
|
m_cb->setText(ctext, QClipboard::Clipboard);
|
|
|
|
m_cb->setText(ctext, QClipboard::Selection);
|
|
|
|
m_dontSendCb = false;
|
|
|
|
}
|
|
|
|
else if (e->type() == MouseStateEventType) {
|
|
|
|
MouseStateEvent *mse = (MouseStateEvent*) e;
|
|
|
|
emit mouseStateChanged(mse->x(), mse->y(), mse->buttonMask());
|
|
|
|
bool show = m_plom.handlePointerEvent(mse->x(), mse->y());
|
|
|
|
if (m_cursorState != DOT_CURSOR_ON)
|
|
|
|
showDotCursor(show ? DOT_CURSOR_AUTO : DOT_CURSOR_OFF);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KVncView::mouseEvent(TQMouseEvent *e) {
|
|
|
|
if (m_status != REMOTE_VIEW_CONNECTED)
|
|
|
|
return;
|
|
|
|
if (m_viewOnly)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if ( e->type() != TQEvent::MouseMove ) {
|
|
|
|
if ( (e->type() == TQEvent::MouseButtonPress) ||
|
|
|
|
(e->type() == TQEvent::MouseButtonDblClick)) {
|
|
|
|
if ( e->button() & LeftButton )
|
|
|
|
m_buttonMask |= 0x01;
|
|
|
|
if ( e->button() & MidButton )
|
|
|
|
m_buttonMask |= 0x02;
|
|
|
|
if ( e->button() & RightButton )
|
|
|
|
m_buttonMask |= 0x04;
|
|
|
|
}
|
|
|
|
else if ( e->type() == TQEvent::MouseButtonRelease ) {
|
|
|
|
if ( e->button() & LeftButton )
|
|
|
|
m_buttonMask &= 0xfe;
|
|
|
|
if ( e->button() & MidButton )
|
|
|
|
m_buttonMask &= 0xfd;
|
|
|
|
if ( e->button() & RightButton )
|
|
|
|
m_buttonMask &= 0xfb;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int x = e->x();
|
|
|
|
int y = e->y();
|
|
|
|
m_plom.registerPointerState(x, y);
|
|
|
|
if (m_scaling) {
|
|
|
|
x = (x * m_framebufferSize.width()) / width();
|
|
|
|
y = (y * m_framebufferSize.height()) / height();
|
|
|
|
}
|
|
|
|
m_wthread.queueMouseEvent(x, y, m_buttonMask);
|
|
|
|
|
|
|
|
if (m_enableClientCursor)
|
|
|
|
DrawCursorX11Thread(x, y); // in rfbproto.c
|
|
|
|
}
|
|
|
|
|
|
|
|
void KVncView::mousePressEvent(TQMouseEvent *e) {
|
|
|
|
mouseEvent(e);
|
|
|
|
e->accept();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KVncView::mouseDoubleClickEvent(TQMouseEvent *e) {
|
|
|
|
mouseEvent(e);
|
|
|
|
e->accept();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KVncView::mouseReleaseEvent(TQMouseEvent *e) {
|
|
|
|
mouseEvent(e);
|
|
|
|
e->accept();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KVncView::mouseMoveEvent(TQMouseEvent *e) {
|
|
|
|
mouseEvent(e);
|
|
|
|
e->ignore();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KVncView::wheelEvent(TQWheelEvent *e) {
|
|
|
|
if (m_status != REMOTE_VIEW_CONNECTED)
|
|
|
|
return;
|
|
|
|
if (m_viewOnly)
|
|
|
|
return;
|
|
|
|
|
|
|
|
int eb = 0;
|
|
|
|
if ( e->delta() < 0 )
|
|
|
|
eb |= 0x10;
|
|
|
|
else
|
|
|
|
eb |= 0x8;
|
|
|
|
|
|
|
|
int x = e->pos().x();
|
|
|
|
int y = e->pos().y();
|
|
|
|
if (m_scaling) {
|
|
|
|
x = (x * m_framebufferSize.width()) / width();
|
|
|
|
y = (y * m_framebufferSize.height()) / height();
|
|
|
|
}
|
|
|
|
m_wthread.queueMouseEvent(x, y, eb|m_buttonMask);
|
|
|
|
m_wthread.queueMouseEvent(x, y, m_buttonMask);
|
|
|
|
e->accept();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KVncView::pressKey(XEvent *xe) {
|
|
|
|
KKeyNative k(xe);
|
|
|
|
uint mod = k.mod();
|
|
|
|
if (mod & KKeyNative::modX(KKey::SHIFT))
|
|
|
|
m_wthread.queueKeyEvent(XK_Shift_L, true);
|
|
|
|
if (mod & KKeyNative::modX(KKey::CTRL))
|
|
|
|
m_wthread.queueKeyEvent(XK_Control_L, true);
|
|
|
|
if (mod & KKeyNative::modX(KKey::ALT))
|
|
|
|
m_wthread.queueKeyEvent(XK_Alt_L, true);
|
|
|
|
if (mod & KKeyNative::modX(KKey::WIN))
|
|
|
|
m_wthread.queueKeyEvent(XK_Meta_L, true);
|
|
|
|
|
|
|
|
m_wthread.queueKeyEvent(k.sym(), true);
|
|
|
|
m_wthread.queueKeyEvent(k.sym(), false);
|
|
|
|
|
|
|
|
if (mod & KKeyNative::modX(KKey::WIN))
|
|
|
|
m_wthread.queueKeyEvent(XK_Meta_L, false);
|
|
|
|
if (mod & KKeyNative::modX(KKey::ALT))
|
|
|
|
m_wthread.queueKeyEvent(XK_Alt_L, false);
|
|
|
|
if (mod & KKeyNative::modX(KKey::CTRL))
|
|
|
|
m_wthread.queueKeyEvent(XK_Control_L, false);
|
|
|
|
if (mod & KKeyNative::modX(KKey::SHIFT))
|
|
|
|
m_wthread.queueKeyEvent(XK_Shift_L, false);
|
|
|
|
|
|
|
|
m_mods.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KVncView::x11Event(XEvent *e) {
|
|
|
|
bool pressed;
|
|
|
|
if (e->type == KeyPress)
|
|
|
|
pressed = true;
|
|
|
|
else if (e->type == KeyRelease)
|
|
|
|
pressed = false;
|
|
|
|
else
|
|
|
|
return TQWidget::x11Event(e);
|
|
|
|
|
|
|
|
if (!m_viewOnly) {
|
|
|
|
unsigned int s = KKeyNative(e).sym();
|
|
|
|
|
|
|
|
switch (s) {
|
|
|
|
case XK_Meta_L:
|
|
|
|
case XK_Alt_L:
|
|
|
|
case XK_Control_L:
|
|
|
|
case XK_Shift_L:
|
|
|
|
case XK_Meta_R:
|
|
|
|
case XK_Alt_R:
|
|
|
|
case XK_Control_R:
|
|
|
|
case XK_Shift_R:
|
|
|
|
if (pressed)
|
|
|
|
m_mods[s] = true;
|
|
|
|
else if (m_mods.contains(s))
|
|
|
|
m_mods.remove(s);
|
|
|
|
else
|
|
|
|
unpressModifiers();
|
|
|
|
}
|
|
|
|
m_wthread.queueKeyEvent(s, pressed);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KVncView::unpressModifiers() {
|
|
|
|
TQValueList<unsigned int> keys = m_mods.keys();
|
|
|
|
TQValueList<unsigned int>::const_iterator it = keys.begin();
|
|
|
|
while (it != keys.end()) {
|
|
|
|
m_wthread.queueKeyEvent(*it, false);
|
|
|
|
it++;
|
|
|
|
}
|
|
|
|
m_mods.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KVncView::focusOutEvent(TQFocusEvent *) {
|
|
|
|
unpressModifiers();
|
|
|
|
}
|
|
|
|
|
|
|
|
TQSize KVncView::sizeHint() {
|
|
|
|
return maximumSize();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KVncView::setRemoteMouseTracking(bool s) {
|
|
|
|
m_remoteMouseTracking = s;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KVncView::remoteMouseTracking() {
|
|
|
|
return m_remoteMouseTracking;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KVncView::clipboardChanged() {
|
|
|
|
if (m_status != REMOTE_VIEW_CONNECTED)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (m_cb->ownsClipboard() || m_dontSendCb)
|
|
|
|
return;
|
|
|
|
|
|
|
|
TQString text = m_cb->text(QClipboard::Clipboard);
|
|
|
|
if (text.length() > MAX_SELECTION_LENGTH)
|
|
|
|
return;
|
|
|
|
|
|
|
|
m_wthread.queueClientCut(text);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KVncView::selectionChanged() {
|
|
|
|
if (m_status != REMOTE_VIEW_CONNECTED)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (m_cb->ownsSelection() || m_dontSendCb)
|
|
|
|
return;
|
|
|
|
|
|
|
|
TQString text = m_cb->text(QClipboard::Selection);
|
|
|
|
if (text.length() > MAX_SELECTION_LENGTH)
|
|
|
|
return;
|
|
|
|
|
|
|
|
m_wthread.queueClientCut(text);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KVncView::lockFramebuffer() {
|
|
|
|
if (m_enableFramebufferLocking)
|
|
|
|
m_framebufferLock.lock();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KVncView::unlockFramebuffer() {
|
|
|
|
if (m_enableFramebufferLocking)
|
|
|
|
m_framebufferLock.unlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KVncView::enableClientCursor(bool enable) {
|
|
|
|
if (enable) {
|
|
|
|
m_enableFramebufferLocking = true; // cant be turned off
|
|
|
|
}
|
|
|
|
m_enableClientCursor = enable;
|
|
|
|
lockFramebuffer();
|
|
|
|
showDotCursorInternal();
|
|
|
|
unlockFramebuffer();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\brief Get a password for this host.
|
|
|
|
Tries to get a password from the url or wallet if at all possible. If
|
|
|
|
both of these fail, it then asks the user to enter a password.
|
|
|
|
\note Lots of dialogs can be popped up during this process. The thread
|
|
|
|
locks and signals are there to protect against deadlocks and other
|
|
|
|
horribleness. Be careful making changes here.
|
|
|
|
*/
|
|
|
|
int getPassword(char *passwd, int pwlen) {
|
|
|
|
int retV = 0;
|
|
|
|
|
|
|
|
//Prepare the system
|
|
|
|
passwordLock.lock();
|
|
|
|
|
|
|
|
//Try #1: Did the user give a password in the URL?
|
|
|
|
if (!password.isNull()) {
|
|
|
|
retV = 1; //got it!
|
|
|
|
}
|
|
|
|
|
|
|
|
//Try #2: Is there something in the wallet?
|
|
|
|
if ( !retV && useKWallet ) {
|
|
|
|
TQApplication::postEvent(kvncview, new WalletOpenEvent());
|
|
|
|
passwordWaiter.wait(&passwordLock); //block
|
|
|
|
if (!password.isNull()) retV = 1; //got it!
|
|
|
|
}
|
|
|
|
|
|
|
|
//Last try: Ask the user
|
|
|
|
if (!retV) {
|
|
|
|
TQApplication::postEvent(kvncview, new PasswordRequiredEvent());
|
|
|
|
passwordWaiter.wait(&passwordLock); //block
|
|
|
|
if (!password.isNull()) retV = 1; //got it!
|
|
|
|
}
|
|
|
|
|
|
|
|
//Process the password if we got it, clear it if we didn't
|
|
|
|
if (retV) {
|
|
|
|
strncpy(passwd, (const char*)password, pwlen);
|
|
|
|
} else {
|
|
|
|
passwd[0] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Pack up and go home
|
|
|
|
passwordLock.unlock();
|
|
|
|
if (!retV) kvncview->startQuitting();
|
|
|
|
|
|
|
|
return retV;
|
|
|
|
}
|
|
|
|
|
|
|
|
extern int isQuitFlagSet() {
|
|
|
|
return kvncview->isQuitting() ? 1 : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
extern void DrawScreenRegion(int x, int y, int width, int height) {
|
|
|
|
/* KApplication::kApplication()->lock();
|
|
|
|
kvncview->drawRegion(x, y, width, height);
|
|
|
|
KApplication::kApplication()->unlock();
|
|
|
|
*/
|
|
|
|
TQApplication::postEvent(kvncview, new ScreenRepaintEvent(x, y, width, height));
|
|
|
|
}
|
|
|
|
|
|
|
|
// call only from x11 thread!
|
|
|
|
extern void DrawAnyScreenRegionX11Thread(int x, int y, int width, int height) {
|
|
|
|
kvncview->drawRegion(x, y, width, height);
|
|
|
|
}
|
|
|
|
|
|
|
|
extern void EnableClientCursor(int enable) {
|
|
|
|
kvncview->enableClientCursor(enable);
|
|
|
|
}
|
|
|
|
|
|
|
|
extern void LockFramebuffer() {
|
|
|
|
kvncview->lockFramebuffer();
|
|
|
|
}
|
|
|
|
|
|
|
|
extern void UnlockFramebuffer() {
|
|
|
|
kvncview->unlockFramebuffer();
|
|
|
|
}
|
|
|
|
|
|
|
|
extern void beep() {
|
|
|
|
TQApplication::postEvent(kvncview, new BeepEvent());
|
|
|
|
}
|
|
|
|
|
|
|
|
extern void newServerCut(char *bytes, int length) {
|
|
|
|
TQApplication::postEvent(kvncview, new ServerCutEvent(bytes, length));
|
|
|
|
}
|
|
|
|
|
|
|
|
extern void postMouseEvent(int x, int y, int buttonMask) {
|
|
|
|
TQApplication::postEvent(kvncview, new MouseStateEvent(x, y, buttonMask));
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "kvncview.moc"
|