remove unused files, ebn--

svn path=/trunk/KDE/kdenetwork/krfb/; revision=652659
This commit is contained in:
Alessandro Praduroux
2007-04-11 17:32:22 +00:00
parent 0bc68de645
commit a7a7633438
11 changed files with 8 additions and 2364 deletions

View File

@@ -1,492 +0,0 @@
/***************************************************************************
configuration.cpp
-------------------
begin : Tue Dec 11 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 "configuration.h"
#include "kinetinterface.h"
#include <kglobal.h>
#include <klocale.h>
#include <kapplication.h>
#include <kmessagebox.h>
#include <k3process.h>
#include <ksocketaddress.h>
#include <k3activelabel.h>
#include <ktoolinvocation.h>
#include <qdatastream.h>
#include <qlabel.h>
#include <qpushbutton.h>
#include <qlineedit.h>
#include <qcheckbox.h>
#include <krun.h>
/**
* Note that this class is used and provides GUI in every mode:
* - for the invitation dialogs
* - for the kcontrol module
* - for the running krfb instance
*/
Configuration::Configuration(krfb_mode mode) :
m_mode(mode),
invMngDlg(0, 0, true),
invDlg(0),
persInvDlg(0),
portNum(-1)
#ifdef __GNUC__
#warning "Port to DBUS"
#endif
#if 0
kinetdRef("kded", "kinetd")
#endif
{
#if 0
kinetdRef.setDCOPClient(KApplication::dcopClient());
loadFromKConfig();
saveToDialogs();
doKinetdConf();
connectDCOPSignal( 0, "KRFB::ConfigChanged", "KRFB_ConfigChanged()",
"updateKConfig()", false );
#endif
connect(invMngDlg.newPersonalInvitationButton, SIGNAL(clicked()),
SLOT(showPersonalInvitationDialog()));
connect(invMngDlg.newEmailInvitationButton, SIGNAL(clicked()), SLOT(inviteEmail()));
connect(invMngDlg.deleteOneButton, SIGNAL(clicked()), SLOT(invMngDlgDeleteOnePressed()));
connect(invMngDlg.deleteAllButton, SIGNAL(clicked()), SLOT(invMngDlgDeleteAllPressed()));
invMngDlg.listView->setSelectionMode(Q3ListView::Extended);
invMngDlg.listView->setMinimumSize(QSize(400, 100)); // QTs size is much to small
connect(&invDlg, SIGNAL(createInviteClicked()),
SLOT(showPersonalInvitationDialog()));
connect(&invDlg, SIGNAL(emailInviteClicked()),
SLOT(inviteEmail()));
connect(&invDlg, SIGNAL(manageInviteClicked()),
SLOT(showManageInvitationsDialog()));
connect(&invDlg, SIGNAL(configureClicked()),
SLOT(showConfigurationModule()));
connect(this, SIGNAL(invitationNumChanged(int)),
&invDlg, SLOT(setInviteCount(int)));
connect(this, SIGNAL(invitationNumChanged(int)),
&invMngDlg, SLOT(listSizeChanged(int)));
emit invitationNumChanged(invitationList.size());
connect(&refreshTimer, SIGNAL(timeout()), SLOT(refreshTimeout()));
refreshTimer.start(1000*60);
}
Configuration::~Configuration() {
save();
}
#if 0
void Configuration::updateKConfig()
{
loadFromKConfig();
}
#endif
void Configuration::setKInetdEnabled(bool enabled) {
#if 0
kinetdRef.send("setEnabled", QString("krfb"), enabled);
kinetdRef.send("setEnabled", QString("krfb_httpd"), enabled);
#endif
}
void Configuration::setKInetdEnabled(const QDateTime &date) {
#if 0
kinetdRef.send("setEnabled", QString("krfb"), date);
kinetdRef.send("setEnabled", QString("krfb_httpd"), date);
#endif
}
void Configuration::setKInetdServiceRegistrationEnabled(bool enabled) {
#if 0
kinetdRef.send("setServiceRegistrationEnabled",
QString("krfb"), enabled);
kinetdRef.send("setServiceRegistrationEnabled",
QString("krfb_httpd"), enabled);
#endif
}
void Configuration::getPortFromKInetd() {
#if 0
DCOPReply r = kinetdRef.call("port", QString("krfb"));
if (!r.isValid())
return; // nice error msg here?
r.get(portNum);
#endif
}
void Configuration::setKInetdPort(int p) {
#if 0
DCOPReply r = kinetdRef.call("setPort",
QString("krfb"), p, 1);
// nice error msg here?
#endif
}
void Configuration::removeInvitation(QList<Invitation>::iterator it) {
invitationList.remove(it);
save();
}
void Configuration::doKinetdConf() {
setKInetdPort(preferredPortNum);
if (allowUninvitedFlag) {
setKInetdEnabled(true);
setKInetdServiceRegistrationEnabled(enableSLPFlag);
getPortFromKInetd();
return;
}
QDateTime lastExpiration;
QList<Invitation>::iterator it = invitationList.begin();
while (it != invitationList.end()) {
Invitation &ix = (*it);
QDateTime t = ix.expirationTime();
if (t > lastExpiration)
lastExpiration = t;
it++;
}
if (lastExpiration.isNull() || (lastExpiration < QDateTime::currentDateTime())) {
setKInetdEnabled(false);
portNum = -1;
}
else {
setKInetdServiceRegistrationEnabled(false);
setKInetdEnabled(lastExpiration);
getPortFromKInetd();
}
}
void Configuration::loadFromKConfig() {
KConfig c("krfbrc");
allowUninvitedFlag = c.readEntry("allowUninvited", false);
enableSLPFlag = c.readEntry("enableSLP", true);
askOnConnectFlag = c.readEntry("confirmUninvitedConnection", true);
allowDesktopControlFlag = c.readEntry("allowDesktopControl", false);
preferredPortNum = c.readEntry("preferredPort", -1);
disableBackgroundFlag = c.readEntry("disableBackground", false);
disableXShmFlag = c.readEntry("disableXShm", false);
if (c.hasKey("uninvitedPasswordCrypted"))
passwordString = cryptStr(c.readEntry("uninvitedPasswordCrypted", ""));
else
passwordString = c.readEntry("uninvitedPassword", "");
unsigned int invNum = invitationList.size();
invitationList.clear();
c.setGroup("invitations");
int num = c.readEntry("invitation_num", 0);
for (int i = 0; i < num; i++)
invitationList.push_back(Invitation(&c, i));
invalidateOldInvitations();
if (invNum != invitationList.size())
emit invitationNumChanged(invitationList.size());
}
void Configuration::saveToKConfig() {
KConfig c("krfbrc");
c.writeEntry("confirmUninvitedConnection", askOnConnectFlag);
c.writeEntry("allowDesktopControl", allowDesktopControlFlag);
c.writeEntry("allowUninvited", allowUninvitedFlag);
c.writeEntry("enableSLP", enableSLPFlag);
c.writeEntry("preferredPort", preferredPortNum);
c.writeEntry("disableBackground", disableBackgroundFlag);
c.writeEntry("disableXShm", disableXShmFlag);
c.writeEntry("uninvitedPasswordCrypted", cryptStr(passwordString));
c.deleteEntry("uninvitedPassword");
c.setGroup("invitations");
int num = invitationList.count();
c.writeEntry("invitation_num", num);
int i = 0;
while (i < num) {
invitationList[i].save(&c, i);
i++;
}
}
void Configuration::saveToDialogs() {
invalidateOldInvitations();
QList<Invitation>::iterator it = invitationList.begin();
while (it != invitationList.end()) {
Invitation &inv = *(it++);
if (!inv.getViewItem())
inv.setViewItem(new K3ListViewItem(invMngDlg.listView,
inv.creationTime().toString(Qt::LocalDate),
inv.expirationTime().toString(Qt::LocalDate)));
}
invMngDlg.adjustSize();
}
void Configuration::save() {
saveToKConfig();
saveToDialogs();
doKinetdConf();
}
void Configuration::update() {
loadFromKConfig();
saveToDialogs();
}
Invitation Configuration::createInvitation() {
Invitation inv;
invitationList.push_back(inv);
return inv;
}
void Configuration::invalidateOldInvitations() {
QList<Invitation>::iterator it = invitationList.begin();
while (it != invitationList.end()) {
if (!(*it).isValid())
it = invitationList.remove(it);
else
it++;
}
}
void Configuration::refreshTimeout() {
unsigned int invNum = invitationList.size();
loadFromKConfig();
saveToDialogs();
if (invNum != invitationList.size())
emit invitationNumChanged(invitationList.size());
}
QString Configuration::hostname() const
{
KNetwork::KInetSocketAddress *a = KInetInterface::getPublicInetAddress();
QString hostName;
if (a) {
hostName = a->nodeName();
delete a;
}
else
hostName = "localhost";
return hostName;
}
///////// properties ///////////////////////////
krfb_mode Configuration::mode() const {
return m_mode;
}
bool Configuration::askOnConnect() const {
return askOnConnectFlag;
}
bool Configuration::allowDesktopControl() const {
return allowDesktopControlFlag;
}
bool Configuration::allowUninvitedConnections() const {
return allowUninvitedFlag;
}
bool Configuration::enableSLP() const {
return enableSLPFlag;
}
QString Configuration::password() const {
return passwordString;
}
QList<Invitation> &Configuration::invitations() {
return invitationList;
}
bool Configuration::disableBackground() const {
return disableBackgroundFlag;
}
bool Configuration::disableXShm() const {
return disableXShmFlag;
}
void Configuration::setAllowUninvited(bool allowUninvited) {
allowUninvitedFlag = allowUninvited;
}
void Configuration::setEnableSLP(bool e) {
enableSLPFlag = e;
}
void Configuration::setAskOnConnect(bool askOnConnect)
{
askOnConnectFlag = askOnConnect;
}
void Configuration::setAllowDesktopControl(bool allowDesktopControl)
{
allowDesktopControlFlag = allowDesktopControl;
}
void Configuration::setPassword(QString password)
{
passwordString = password;
}
int Configuration::port() const
{
if ((portNum < 5900) || (portNum >= 6000))
return portNum;
else
return portNum - 5900;
}
// use p=-1 for defaults
void Configuration::setPreferredPort(int p)
{
preferredPortNum = p;
}
int Configuration::preferredPort() const
{
return preferredPortNum;
}
void Configuration::setDisableBackground(bool disable) {
disableBackgroundFlag = disable;
}
void Configuration::setDisableXShm(bool disable) {
disableXShmFlag = disable;
}
////////////// invitation manage dialog //////////////////////////
void Configuration::showManageInvitationsDialog() {
loadFromKConfig();
saveToDialogs();
invMngDlg.exec();
}
void Configuration::invMngDlgDeleteOnePressed() {
QList<Invitation>::iterator it = invitationList.begin();
while (it != invitationList.end()) {
Invitation &ix = (*it);
K3ListViewItem *iv = ix.getViewItem();
if (iv && iv->isSelected())
it = invitationList.remove(it);
else
it++;
}
saveToKConfig();
doKinetdConf();
emit invitationNumChanged(invitationList.size());
}
void Configuration::invMngDlgDeleteAllPressed() {
invitationList.clear();
saveToKConfig();
doKinetdConf();
emit invitationNumChanged(invitationList.size());
}
////////////// invitation dialog //////////////////////////
void Configuration::showInvitationDialog() {
invDlg.exec();
emit invitationFinished();
saveToKConfig();
}
////////////// personal invitation dialog //////////////////////////
void Configuration::showPersonalInvitationDialog() {
loadFromKConfig();
Invitation inv = createInvitation();
save();
emit invitationNumChanged(invitationList.size());
invDlg.enableInviteButton(false);
invMngDlg.newPersonalInvitationButton->setEnabled(false);
persInvDlg.setHost(hostname(), port());
persInvDlg.setPassword(inv.password());
persInvDlg.setExpiration(inv.expirationTime());
persInvDlg.exec();
invDlg.enableInviteButton(true);
invMngDlg.newPersonalInvitationButton->setEnabled(true);
}
////////////// invite email //////////////////////////
void Configuration::inviteEmail() {
int r = KMessageBox::warningContinueCancel(0,
i18n("When sending an invitation by email, note that everybody who reads this email "
"will be able to connect to your computer for one hour, or until the first "
"successful connection took place, whichever comes first. \n"
"You should either encrypt the email or at least send it only in a "
"secure network, but not over the Internet."),
i18n("Send Invitation via Email"),
KStandardGuiItem::cont(),
"showEmailInvitationWarning");
if (r == KMessageBox::Cancel)
return;
loadFromKConfig();
Invitation inv = createInvitation();
save();
emit invitationNumChanged(invitationList.size());
KToolInvocation::invokeMailer(QString::null, QString::null, QString::null,
i18n("Desktop Sharing (VNC) invitation"),
ki18n("You have been invited to a VNC session. If you have the KDE Remote "
"Desktop Connection installed, just click on the link below.\n\n"
"vnc://invitation:%1@%2:%3\n\n"
"Otherwise you can use any VNC client with the following parameters:\n\n"
"Host: %4:%5\n"
"Password: %6\n\n"
"Alternatively you can click on the link below to start the VNC session\n"
"within your web browser.\n"
"\n"
" http://%7:%8/\n"
"\n"
"For security reasons this invitation will expire at %9.")
.subs(inv.password())
.subs(hostname())
.subs(port())
.subs(hostname())
.subs(port())
.subs(inv.password())
.subs(hostname())
.subs(5800) // determine with dcop ... later ...
.subs(KGlobal::locale()->formatDateTime(inv.expirationTime()))
.toString());
}
////////////// invoke kcontrol module //////////////////////////
void Configuration::showConfigurationModule() {
KRun::run( "kcmshell kcmkrfb", KUrl::List() );
}
#include "configuration.moc"

View File

@@ -1,139 +0,0 @@
/***************************************************************************
configuration.h
-------------------
begin : Tue Dec 11 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. *
* *
***************************************************************************/
#ifndef CONFIGURATION_H
#define CONFIGURATION_H
#include "invitation.h"
#include "manageinvitations.h"
#include "personalinvitedialog.h"
#include "invitedialog.h"
#include <kconfig.h>
#include <qtimer.h>
#include <qobject.h>
#include <qvalidator.h>
#include <qstring.h>
enum krfb_mode {
KRFB_UNKNOWN_MODE = 0,
KRFB_KINETD_MODE,
KRFB_INVITATION_MODE,
KRFB_CONFIGURATION_MODE
};
/**
* This class stores the app's configuration, manages the
* standalone-config-dialog and all the invitation dialogs
* @author Tim Jansen
*/
class Configuration : public QObject {
Q_OBJECT
public:
Configuration(krfb_mode mode);
virtual ~Configuration();
krfb_mode mode() const;
bool askOnConnect() const;
bool allowDesktopControl() const;
bool allowUninvitedConnections() const;
bool enableSLP() const;
QString password() const;
QString hostname() const;
int port() const;
int preferredPort() const;
bool disableBackground() const;
bool disableXShm() const;
void setAllowUninvited(bool allowUninvited);
void setEnableSLP(bool e);
void setAskOnConnect(bool askOnConnect);
void setPassword(QString password);
void setPreferredPort(int p);
void setDisableBackground(bool disable);
void setDisableXShm(bool disable);
void save();
void update();
QList<Invitation> &invitations();
void removeInvitation(QList<Invitation>::iterator it);
signals:
void invitationFinished();
void invitationNumChanged(int num);
public slots:
void setAllowDesktopControl(bool allowDesktopControl);
void showManageInvitationsDialog();
void showInvitationDialog();
void showPersonalInvitationDialog();
void showConfigurationModule();
void inviteEmail();
private:
void loadFromKConfig();
void loadFromDialogs();
void saveToKConfig();
void saveToDialogs();
Invitation createInvitation();
void closeInvDlg();
void invalidateOldInvitations();
void setKInetdEnabled(const QDateTime &date);
void setKInetdEnabled(bool enabled);
void setKInetdServiceRegistrationEnabled(bool enabled);
void getPortFromKInetd();
void setKInetdPort(int port);
void doKinetdConf();
krfb_mode m_mode;
ManageInvitationsDialog invMngDlg;
InviteDialog invDlg;
PersonalInviteDialog persInvDlg;
QTimer refreshTimer;
bool askOnConnectFlag;
bool allowDesktopControlFlag;
bool allowUninvitedFlag;
bool enableSLPFlag;
int portNum, preferredPortNum;
#if 0
DCOPRef kinetdRef;
#endif
QString passwordString;
QList<Invitation> invitationList;
bool disableBackgroundFlag;
bool disableXShmFlag;
#if 0
k_dcop:
// Connected to the DCOP signal
void updateKConfig();
#endif
private slots:
void refreshTimeout();
void invMngDlgDeleteOnePressed();
void invMngDlgDeleteAllPressed();
};
#endif

View File

@@ -7,6 +7,9 @@
License as published by the Free Software Foundation; version 2
of the License.
*/
#include "connectioncontroller.h"
#include "connectioncontroller.moc"
#include <QX11Info>
#include <QHostInfo>
#include <QApplication>
@@ -20,8 +23,6 @@
#include <KNotification>
#include <KLocale>
#include "connectioncontroller.h"
#include "connectioncontroller.moc"
#include "invitationmanager.h"
#include "connectiondialog.h"

View File

@@ -10,6 +10,8 @@
#ifndef CONNECTIONCONTROLLER_H
#define CONNECTIONCONTROLLER_H
#include <QObject>
#include <rfb/rfb.h>
class KrfbServer;

View File

@@ -8,6 +8,7 @@
of the License.
*/
#include <QApplication>
#include <QX11Info>
#include <QString>

View File

@@ -24,7 +24,7 @@ class FrameBuffer : public QObject
{
Q_OBJECT
public:
FrameBuffer(WId id, QObject *parent = 0);
explicit FrameBuffer(WId id, QObject *parent = 0);
~FrameBuffer();

View File

@@ -108,4 +108,4 @@ void InvitationManager::removeInvitation(const Invitation & inv)
{
invitationList.removeAll(inv);
emit invitationNumChanged(invitationList.size());
}
}

View File

@@ -1,912 +0,0 @@
/***************************************************************************
rfbcontroller.cpp
-------------------
begin : Sun Dec 9 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. *
* *
***************************************************************************/
/*
* Contains keyboard & pointer handling from libvncserver's x11vnc.c
*/
#include "rfbcontroller.h"
#include "kuser.h"
#include <netinet/tcp.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
#include <fcntl.h>
#ifdef USE_SOLARIS
#include <strings.h>
#endif
#include <kdefakes.h> // gethostname
#include <kapplication.h>
#include <KNotification>
#include <kdebug.h>
#include <kmessagebox.h>
#include <klocale.h>
#include <qstring.h>
#include <qcursor.h>
#include <qwindowdefs.h>
#include <qtimer.h>
#include <qcheckbox.h>
#include <qpushbutton.h>
#include <qglobal.h>
#include <qlabel.h>
#include <qmutex.h>
#include <qclipboard.h>
#include <qdesktopwidget.h>
//Added by qt3to4:
#include <Q3CString>
#include <Q3PtrList>
#include <X11/Xutil.h>
#include <X11/extensions/XTest.h>
#include <QX11Info>
#ifndef ASSERT
#define ASSERT(x) Q_ASSERT(x)
#endif
#define IDLE_PAUSE (1000/50)
#define MAX_SELECTION_LENGTH (4096)
static XTestDisabler disabler;
static const char* cur=
" "
" x "
" xx "
" xxx "
" xxxx "
" xxxxx "
" xxxxxx "
" xxxxxxx "
" xxxxxxxx "
" xxxxxxxxx "
" xxxxxxxxxx "
" xxxxx "
" xx xxx "
" x xxx "
" xxx "
" xxx "
" xxx "
" xxx "
" ";
static const char* mask=
"xx "
"xxx "
"xxxx "
"xxxxx "
"xxxxxx "
"xxxxxxx "
"xxxxxxxx "
"xxxxxxxxx "
"xxxxxxxxxx "
"xxxxxxxxxxx "
"xxxxxxxxxxxx "
"xxxxxxxxxx "
"xxxxxxxx "
"xxxxxxxx "
"xx xxxxx "
" xxxxx "
" xxxxx "
" xxxxx "
" xxx ";
static rfbCursorPtr myCursor;
// only one controller exists, so we can do this workaround for functions:
static RFBController *self;
class AppLocker
{
public:
AppLocker() {
KApplication::kApplication()->lock();
}
~AppLocker() {
KApplication::kApplication()->unlock();
}
};
static enum rfbNewClientAction newClientHook(struct _rfbClientRec *cl)
{
AppLocker a;
return self->handleNewClient(cl);
}
static Bool passwordCheck(rfbClientPtr cl,
const char* encryptedPassword,
int len)
{
AppLocker a;
return self->handleCheckPassword(cl, encryptedPassword, len);
}
static void keyboardHook(Bool down, KeySym keySym, rfbClientPtr)
{
self->handleKeyEvent(down ? true : false, keySym);
}
static void pointerHook(int bm, int x, int y, rfbClientPtr)
{
self->handlePointerEvent(bm, x, y);
}
static void clientGoneHook(rfbClientPtr)
{
self->handleClientGone();
}
static void negotiationFinishedHook(rfbClientPtr cl)
{
self->handleNegotiationFinished(cl);
}
static void inetdDisconnectHook()
{
self->handleClientGone();
}
static void clipboardHook(char* str,int len, rfbClientPtr)
{
self->clipboardToServer(QString::fromUtf8(str, len));
}
VNCEvent::~VNCEvent() {
}
Display *KeyboardEvent::dpy;
signed char KeyboardEvent::modifiers[0x100];
KeyCode KeyboardEvent::keycodes[0x100];
KeyCode KeyboardEvent::leftShiftCode;
KeyCode KeyboardEvent::rightShiftCode;
KeyCode KeyboardEvent::altGrCode;
const int KeyboardEvent::LEFTSHIFT = 1;
const int KeyboardEvent::RIGHTSHIFT = 2;
const int KeyboardEvent::ALTGR = 4;
char KeyboardEvent::ModifierState;
KeyboardEvent::KeyboardEvent(bool d, KeySym k) :
down(d),
keySym(k) {
}
void KeyboardEvent::initKeycodes() {
KeySym key,*keymap;
int i,j,minkey,maxkey,syms_per_keycode;
dpy = QX11Info::display();
memset(modifiers,-1,sizeof(modifiers));
XDisplayKeycodes(dpy,&minkey,&maxkey);
ASSERT(minkey >= 8);
ASSERT(maxkey < 256);
keymap = (KeySym*) XGetKeyboardMapping(dpy, minkey,
(maxkey - minkey + 1),
&syms_per_keycode);
ASSERT(keymap);
for (i = minkey; i <= maxkey; i++)
for (j=0; j<syms_per_keycode; j++) {
key = keymap[(i-minkey)*syms_per_keycode+j];
if (key>=' ' && key<0x100 && i==XKeysymToKeycode(dpy,key)) {
keycodes[key]=i;
modifiers[key]=j;
}
}
leftShiftCode = XKeysymToKeycode(dpy, XK_Shift_L);
rightShiftCode = XKeysymToKeycode(dpy, XK_Shift_R);
altGrCode = XKeysymToKeycode(dpy, XK_Mode_switch);
XFree ((char *)keymap);
}
/* this function adjusts the modifiers according to mod (as from modifiers) and ModifierState */
void KeyboardEvent::tweakModifiers(signed char mod, bool down) {
bool isShift = ModifierState & (LEFTSHIFT|RIGHTSHIFT);
if(mod < 0)
return;
if(isShift && mod != 1) {
if(ModifierState & LEFTSHIFT)
XTestFakeKeyEvent(dpy, leftShiftCode,
!down, CurrentTime);
if(ModifierState & RIGHTSHIFT)
XTestFakeKeyEvent(dpy, rightShiftCode,
!down, CurrentTime);
}
if(!isShift && mod==1)
XTestFakeKeyEvent(dpy, leftShiftCode,
down, CurrentTime);
if((ModifierState&ALTGR) && mod != 2)
XTestFakeKeyEvent(dpy, altGrCode,
!down, CurrentTime);
if(!(ModifierState&ALTGR) && mod==2)
XTestFakeKeyEvent(dpy, altGrCode,
down, CurrentTime);
}
void KeyboardEvent::exec() {
#define ADJUSTMOD(sym,state) \
if(keySym==sym) { if(down) ModifierState|=state; else ModifierState&=~state; }
ADJUSTMOD(XK_Shift_L,LEFTSHIFT);
ADJUSTMOD(XK_Shift_R,RIGHTSHIFT);
ADJUSTMOD(XK_Mode_switch,ALTGR);
if(keySym>=' ' && keySym<0x100) {
KeyCode k;
if (down)
tweakModifiers(modifiers[keySym],True);
k = keycodes[keySym];
if (k != NoSymbol)
XTestFakeKeyEvent(dpy, k, down, CurrentTime);
if (down)
tweakModifiers(modifiers[keySym],False);
} else {
KeyCode k = XKeysymToKeycode(dpy, keySym );
if (k != NoSymbol)
XTestFakeKeyEvent(dpy, k, down, CurrentTime);
}
}
bool PointerEvent::initialized = false;
Display *PointerEvent::dpy;
int PointerEvent::buttonMask = 0;
PointerEvent::PointerEvent(int b, int _x, int _y) :
button_mask(b),
x(_x),
y(_y) {
if (!initialized) {
initialized = true;
dpy = QX11Info::display();
buttonMask = 0;
}
}
void PointerEvent::exec() {
QDesktopWidget *desktopWidget = QApplication::desktop();
int screen = desktopWidget->screenNumber();
if (screen < 0)
screen = 0;
XTestFakeMotionEvent(dpy, screen, x, y, CurrentTime);
for(int i = 0; i < 5; i++)
if ((buttonMask&(1<<i))!=(button_mask&(1<<i)))
XTestFakeButtonEvent(dpy,
i+1,
(button_mask&(1<<i))?True:False,
CurrentTime);
buttonMask = button_mask;
}
ClipboardEvent::ClipboardEvent(RFBController *c, const QString &ctext) :
controller(c),
text(ctext) {
}
void ClipboardEvent::exec() {
if ((controller->lastClipboardDirection == RFBController::LAST_SYNC_TO_CLIENT) &&
(controller->lastClipboardText == text)) {
return;
}
controller->lastClipboardDirection = RFBController::LAST_SYNC_TO_SERVER;
controller->lastClipboardText = text;
controller->clipboard->setText(text, QClipboard::Clipboard);
controller->clipboard->setText(text, QClipboard::Selection);
}
KNotifyEvent::KNotifyEvent(const QString &n, const QString &d) :
name(n),
desc(d) {
}
KNotifyEvent::~KNotifyEvent() {
}
void KNotifyEvent::exec() {
KNotification::event(name, desc);
}
SessionEstablishedEvent::SessionEstablishedEvent(RFBController *c) :
controller(c)
{ }
void SessionEstablishedEvent::exec() {
controller->sendSessionEstablished();
}
RFBController::RFBController(Configuration *c) :
allowDesktopControl(false),
lastClipboardDirection(LAST_SYNC_TO_SERVER),
configuration(c),
dialog(0),
disableBackgroundPending(false),
disableBackgroundState(false),
closePending(false),
forcedClose(false)
{
self = this;
connect(&dialog, SIGNAL(okClicked()), SLOT(dialogAccepted()));
connect(&dialog, SIGNAL(cancelClicked()), SLOT(dialogRefused()));
connect(&initIdleTimer, SIGNAL(timeout()), SLOT(checkAsyncEvents()));
connect(&idleTimer, SIGNAL(timeout()), SLOT(idleSlot()));
clipboard = QApplication::clipboard();
connect(clipboard, SIGNAL(selectionChanged()), this, SLOT(selectionChanged()));
connect(clipboard, SIGNAL(dataChanged()), this, SLOT(clipboardChanged()));
asyncQueue.setAutoDelete(true);
KeyboardEvent::initKeycodes();
char hostname[256];
if (gethostname(hostname, 255))
hostname[0] = 0;
hostname[255] = 0;
desktopName = i18n("%1@%2 (shared desktop)", KUser().loginName(), hostname);
}
RFBController::~RFBController()
{
stopServer();
}
void RFBController::startServer(int inetdFd, bool xtestGrab)
{
framebufferImage = XGetImage(QX11Info::display(),
QApplication::desktop()->winId(),
0,
0,
QApplication::desktop()->width(),
QApplication::desktop()->height(),
AllPlanes,
ZPixmap);
int w = framebufferImage->width;
int h = framebufferImage->height;
char *fb = framebufferImage->data;
rfbLogEnable(0);
server = rfbGetScreen(0, 0, w, h,
framebufferImage->bits_per_pixel,
8,
framebufferImage->bits_per_pixel/8);
server->paddedWidthInBytes = framebufferImage->bytes_per_line;
server->rfbServerFormat.bitsPerPixel = framebufferImage->bits_per_pixel;
server->rfbServerFormat.depth = framebufferImage->depth;
server->rfbServerFormat.trueColour = (CARD8) TRUE;
server->rfbServerFormat.bigEndian = (CARD8) ((framebufferImage->bitmap_bit_order == MSBFirst) ? TRUE : FALSE);
if ( server->rfbServerFormat.bitsPerPixel == 8 ) {
server->rfbServerFormat.redShift = 0;
server->rfbServerFormat.greenShift = 3;
server->rfbServerFormat.blueShift = 6;
server->rfbServerFormat.redMax = 7;
server->rfbServerFormat.greenMax = 7;
server->rfbServerFormat.blueMax = 3;
} else {
server->rfbServerFormat.redShift = 0;
if ( framebufferImage->red_mask )
while ( ! ( framebufferImage->red_mask & (1 << server->rfbServerFormat.redShift) ) )
server->rfbServerFormat.redShift++;
server->rfbServerFormat.greenShift = 0;
if ( framebufferImage->green_mask )
while ( ! ( framebufferImage->green_mask & (1 << server->rfbServerFormat.greenShift) ) )
server->rfbServerFormat.greenShift++;
server->rfbServerFormat.blueShift = 0;
if ( framebufferImage->blue_mask )
while ( ! ( framebufferImage->blue_mask & (1 << server->rfbServerFormat.blueShift) ) )
server->rfbServerFormat.blueShift++;
server->rfbServerFormat.redMax = framebufferImage->red_mask >> server->rfbServerFormat.redShift;
server->rfbServerFormat.greenMax = framebufferImage->green_mask >> server->rfbServerFormat.greenShift;
server->rfbServerFormat.blueMax = framebufferImage->blue_mask >> server->rfbServerFormat.blueShift;
}
server->frameBuffer = fb;
server->autoPort = TRUE;
server->inetdSock = inetdFd;
server->kbdAddEvent = keyboardHook;
server->ptrAddEvent = pointerHook;
server->newClientHook = newClientHook;
server->inetdDisconnectHook = inetdDisconnectHook;
server->passwordCheck = passwordCheck;
server->setXCutText = clipboardHook;
server->desktopName = desktopName.latin1();
if (!myCursor)
myCursor = rfbMakeXCursor(19, 19, (char*) cur, (char*) mask);
server->cursor = myCursor;
passwordChanged();
scanner = new XUpdateScanner(QX11Info::display(),
QApplication::desktop()->winId(),
(unsigned char*)fb, w, h,
server->rfbServerFormat.bitsPerPixel,
server->paddedWidthInBytes,
!configuration->disableXShm());
#ifdef __GNUC__
#warning "FIXME (linking problem)"
#endif
#if 0
rfbInitServer(server);
#endif
state = RFB_WAITING;
if (xtestGrab) {
disabler.disable = false;
XTestGrabControl(QX11Info::display(), true);
}
rfbRunEventLoop(server, -1, TRUE);
initIdleTimer.start(IDLE_PAUSE);
}
void RFBController::stopServer(bool xtestUngrab)
{
rfbScreenCleanup(server);
state = RFB_STOPPED;
delete scanner;
XDestroyImage(framebufferImage);
if (xtestUngrab) {
disabler.disable = true;
QTimer::singleShot(0, &disabler, SLOT(exec()));
}
}
void RFBController::connectionAccepted(bool aRC)
{
if (state != RFB_CONNECTING)
return;
allowDesktopControl = aRC;
emit desktopControlSettingChanged(aRC);
initIdleTimer.stop();
idleTimer.start(IDLE_PAUSE);
server->rfbClientHead->clientGoneHook = clientGoneHook;
state = RFB_CONNECTED;
if (!server->rfbAuthPasswdData)
emit sessionEstablished(remoteIp);
}
void RFBController::acceptConnection(bool aRemoteControl)
{
KNotification::event("UserAcceptsConnection",
i18n("User accepts connection from %1",
remoteIp));
if (state != RFB_CONNECTING)
return;
connectionAccepted(aRemoteControl);
rfbStartOnHoldClient(server->rfbClientHead);
}
void RFBController::refuseConnection()
{
KNotification::event("UserRefusesConnection",
i18n("User refuses connection from %1",
remoteIp));
if (state != RFB_CONNECTING)
return;
rfbRefuseOnHoldClient(server->rfbClientHead);
state = RFB_WAITING;
}
// checks async events, returns true if client disconnected
bool RFBController::checkAsyncEvents()
{
bool closed = false;
bool backgroundActionRequired = false;
asyncMutex.lock();
VNCEvent *e;
for (e = asyncQueue.first(); e; e = asyncQueue.next())
e->exec();
asyncQueue.clear();
if (closePending) {
connectionClosed();
closed = true;
closePending = false;
}
if (disableBackgroundPending != disableBackgroundState)
backgroundActionRequired = true;
asyncMutex.unlock();
if (backgroundActionRequired && (!closed) && !configuration->disableBackground())
disableBackground(disableBackgroundPending);
return closed;
}
void RFBController::disableBackground(bool state) {
if (disableBackgroundState == state)
return;
disableBackgroundState = state;
#if 0
DCOPRef ref("kdesktop", "KBackgroundIface");
ref.setDCOPClient(KApplication::dcopClient());
ref.send("setBackgroundEnabled(bool)", bool(!state));
#endif
}
void RFBController::connectionClosed()
{
KNotification::event("ConnectionClosed",
i18n("Closed connection: %1.",
remoteIp));
idleTimer.stop();
initIdleTimer.stop();
disableBackground(false);
state = RFB_WAITING;
if (forcedClose)
emit quitApp();
else
emit sessionFinished();
}
void RFBController::closeConnection()
{
forcedClose = true;
if (state == RFB_CONNECTED) {
disableBackground(false);
if (!checkAsyncEvents()) {
asyncMutex.lock();
if (!closePending)
rfbCloseClient(server->rfbClientHead);
asyncMutex.unlock();
}
}
else if (state == RFB_CONNECTING)
refuseConnection();
}
void RFBController::enableDesktopControl(bool b) {
if (b != allowDesktopControl)
emit desktopControlSettingChanged(b);
allowDesktopControl = b;
}
void RFBController::idleSlot()
{
if (state != RFB_CONNECTED)
return;
if (checkAsyncEvents() || forcedClose)
return;
rfbUndrawCursor(server);
Q3PtrList<Hint> v;
v.setAutoDelete(true);
QPoint p = QCursor::pos();
scanner->searchUpdates(v, p.y());
Hint *h;
for (h = v.first(); h != 0; h = v.next())
rfbMarkRectAsModified(server, h->left(),
h->top(),
h->right(),
h->bottom());
asyncMutex.lock();
if (!closePending)
defaultPtrAddEvent(0, p.x(),p.y(), server->rfbClientHead);
asyncMutex.unlock();
checkAsyncEvents(); // check 2nd time (see 3rd line)
}
void RFBController::dialogAccepted()
{
dialog.hide();
acceptConnection(dialog.allowRemoteControl());
}
void RFBController::dialogRefused()
{
refuseConnection();
dialog.hide();
emit sessionRefused();
}
bool checkPassword(const QString &p,
unsigned char *ochallenge,
const char *response,
int len) {
if ((len == 0) && (p.length() == 0))
return true;
char passwd[MAXPWLEN];
unsigned char challenge[CHALLENGESIZE];
memcpy(challenge, ochallenge, CHALLENGESIZE);
bzero(passwd, MAXPWLEN);
if (!p.isNull())
strncpy(passwd, p.latin1(),
(MAXPWLEN <= p.length()) ? MAXPWLEN : p.length());
vncEncryptBytes(challenge, passwd);
return memcmp(challenge, response, len) == 0;
}
bool RFBController::handleCheckPassword(rfbClientPtr cl,
const char *response,
int len)
{
bool authd = false;
if (configuration->allowUninvitedConnections())
authd = checkPassword(configuration->password(),
cl->authChallenge, response, len);
if (!authd) {
QList<Invitation>::iterator it =
configuration->invitations().begin();
while (it != configuration->invitations().end()) {
if (checkPassword((*it).password(),
cl->authChallenge, response, len) &&
(*it).isValid()) {
authd = true;
configuration->removeInvitation(it);
break;
}
it++;
}
}
if (!authd) {
if (configuration->invitations().size() > 0) {
sendKNotifyEvent("InvalidPasswordInvitations",
i18n("Failed login attempt from %1: wrong password",
remoteIp));
}
else
sendKNotifyEvent("InvalidPassword",
i18n("Failed login attempt from %1: wrong password",
remoteIp));
return FALSE;
}
asyncMutex.lock();
asyncQueue.append(new SessionEstablishedEvent(this));
asyncMutex.unlock();
return TRUE;
}
enum rfbNewClientAction RFBController::handleNewClient(rfbClientPtr cl)
{
int socket = cl->sock;
cl->negotiationFinishedHook = negotiationFinishedHook;
QString host, port;
#ifdef __GNUC__
#warning "FIXME (port KSocketAddress)"
#endif
#if 0
KSocketAddress *ksa = KExtendedSocket::peerAddress(socket);
if (ksa) {
hostent *he = 0;
KInetSocketAddress *kisa = (KInetSocketAddress*) ksa;
in_addr ia4 = kisa->hostV4();
he = gethostbyaddr((const char*)&ia4,
sizeof(ia4),
AF_INET);
if (he && he->h_name)
host = QString(he->h_name);
else
host = ksa->nodeName();
delete ksa;
}
#endif
if (state != RFB_WAITING) {
sendKNotifyEvent("TooManyConnections",
i18n("Connection refused from %1, already connected.",
host));
return RFB_CLIENT_REFUSE;
}
remoteIp = host;
state = RFB_CONNECTING;
if ((!configuration->askOnConnect()) &&
(configuration->invitations().size() == 0)) {
sendKNotifyEvent("NewConnectionAutoAccepted",
i18n("Accepted uninvited connection from %1",
remoteIp));
connectionAccepted(configuration->allowDesktopControl());
return RFB_CLIENT_ACCEPT;
}
sendKNotifyEvent("NewConnectionOnHold",
i18n("Received connection from %1, on hold (waiting for confirmation)",
remoteIp));
dialog.setRemoteHost(remoteIp);
dialog.setAllowRemoteControl( true );
dialog.setFixedSize(dialog.sizeHint());
dialog.show();
return RFB_CLIENT_ON_HOLD;
}
void RFBController::handleClientGone()
{
asyncMutex.lock();
closePending = true;
asyncMutex.unlock();
}
void RFBController::handleNegotiationFinished(rfbClientPtr cl)
{
asyncMutex.lock();
disableBackgroundPending = cl->disableBackground;
asyncMutex.unlock();
}
void RFBController::handleKeyEvent(bool down, KeySym keySym) {
if (!allowDesktopControl)
return;
asyncMutex.lock();
asyncQueue.append(new KeyboardEvent(down, keySym));
asyncMutex.unlock();
}
void RFBController::handlePointerEvent(int button_mask, int x, int y) {
if (!allowDesktopControl)
return;
asyncMutex.lock();
asyncQueue.append(new PointerEvent(button_mask, x, y));
asyncMutex.unlock();
}
void RFBController::clipboardToServer(const QString &ctext) {
if (!allowDesktopControl)
return;
asyncMutex.lock();
asyncQueue.append(new ClipboardEvent(this, ctext));
asyncMutex.unlock();
}
void RFBController::clipboardChanged() {
if (state != RFB_CONNECTED)
return;
if (clipboard->ownsClipboard())
return;
QString text = clipboard->text(QClipboard::Clipboard);
// avoid ping-pong between client&server
if ((lastClipboardDirection == LAST_SYNC_TO_SERVER) &&
(lastClipboardText == text))
return;
if ((text.length() > MAX_SELECTION_LENGTH) || text.isNull())
return;
lastClipboardDirection = LAST_SYNC_TO_CLIENT;
lastClipboardText = text;
Q3CString ctext = text.utf8();
rfbSendServerCutText(server, ctext.data(), ctext.length());
}
void RFBController::selectionChanged() {
if (state != RFB_CONNECTED)
return;
if (clipboard->ownsSelection())
return;
QString text = clipboard->text(QClipboard::Selection);
// avoid ping-pong between client&server
if ((lastClipboardDirection == LAST_SYNC_TO_SERVER) &&
(lastClipboardText == text))
return;
if ((text.length() > MAX_SELECTION_LENGTH) || text.isNull())
return;
lastClipboardDirection = LAST_SYNC_TO_CLIENT;
lastClipboardText = text;
Q3CString ctext = text.utf8();
rfbSendServerCutText(server, ctext.data(), ctext.length());
}
void RFBController::passwordChanged() {
bool authRequired = (!configuration->allowUninvitedConnections()) ||
(configuration->password().length() != 0) ||
(configuration->invitations().count() > 0);
server->rfbAuthPasswdData = (void*) (authRequired ? 1 : 0);
}
void RFBController::sendKNotifyEvent(const QString &n, const QString &d)
{
asyncMutex.lock();
asyncQueue.append(new KNotifyEvent(n, d));
asyncMutex.unlock();
}
void RFBController::sendSessionEstablished()
{
if (configuration->disableBackground())
disableBackground(true);
emit sessionEstablished(remoteIp);
}
#ifdef __osf__
extern "C" Bool XShmQueryExtension(Display*);
#endif
bool RFBController::checkX11Capabilities() {
int bp1, bp2, majorv, minorv;
Bool r = XTestQueryExtension(QX11Info::display(), &bp1, &bp2,
&majorv, &minorv);
if ((!r) || (((majorv*1000)+minorv) < 2002)) {
KMessageBox::error(0,
i18n("Your X11 Server does not support the required XTest extension version 2.2. Sharing your desktop is not possible."),
i18n("Desktop Sharing Error"));
return false;
}
return true;
}
XTestDisabler::XTestDisabler() :
disable(false) {
}
void XTestDisabler::exec() {
if (disable)
XTestDiscard(QX11Info::display());
}
#include "rfbcontroller.moc"

View File

@@ -1,222 +0,0 @@
/***************************************************************************
rfbcontroller.h
-------------------
begin : Sun Dec 9 2001
copyright : (C) 2001 by Tim Jansen
email : tim@tjansen.de
***************************************************************************/
/***************************************************************************
* Contains portions & concept from rfb's x0rfbserver.cc
* Copyright (C) 2000 heXoNet Support GmbH, D-66424 Homburg.
***************************************************************************/
/***************************************************************************
* *
* 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. *
* *
***************************************************************************/
#ifndef RFBCONTROLLER_H
#define RFBCONTROLLER_H
#include "configuration.h"
#include "connectiondialog.h"
#include "xupdatescanner.h"
#include <qobject.h>
#include <qtimer.h>
#include <qmutex.h>
#include <QCloseEvent>
#include <Q3PtrList>
#define HAVE_PTHREADS
#include "rfb.h"
#include <X11/Xlib.h>
class QCloseEvent;
class QClipboard;
class RFBController;
typedef enum {
RFB_STOPPED,
RFB_WAITING,
RFB_CONNECTING,
RFB_CONNECTED
} RFBState;
class VNCEvent {
public:
virtual void exec() = 0;
virtual ~VNCEvent();
};
class KeyboardEvent : public VNCEvent {
bool down;
KeySym keySym;
static Display *dpy;
static signed char modifiers[0x100];
static KeyCode keycodes[0x100], leftShiftCode, rightShiftCode, altGrCode;
static const int LEFTSHIFT;
static const int RIGHTSHIFT;
static const int ALTGR;
static char ModifierState;
static void tweakModifiers(signed char mod, bool down);
public:
static void initKeycodes();
KeyboardEvent(bool d, KeySym k);
virtual void exec();
};
class PointerEvent : public VNCEvent {
int button_mask, x, y;
static bool initialized;
static Display *dpy;
static int buttonMask;
public:
PointerEvent(int b, int _x, int _y);
virtual void exec();
};
class ClipboardEvent : public VNCEvent {
RFBController *controller;
QString text;
public:
ClipboardEvent(RFBController *c, const QString &text);
virtual void exec();
};
class KNotifyEvent : public VNCEvent {
QString name;
QString desc;
public:
KNotifyEvent(const QString &n, const QString &d);
virtual ~KNotifyEvent();
virtual void exec();
};
class SessionEstablishedEvent : public VNCEvent {
RFBController *controller;
public:
SessionEstablishedEvent(RFBController *c);
virtual void exec();
};
/**
* Manages sockets, drives the RGBConnection and triggers the connection
* dialog.
* The controller has three states: 'waiting for connection',
* 'waiting for confirmation' and 'connected'. In the first state socket and
* connection are null, in the second socket is set and in the last both are
* set.
* @author Tim Jansen
*/
class RFBController : public QObject {
Q_OBJECT
friend class SessionEstablishedEvent;
friend class ClipboardEvent;
public:
RFBController(Configuration *c);
virtual ~RFBController();
RFBState state;
void acceptConnection(bool allowRemoteConnection);
void connectionAccepted(bool allowRemoteConnection);
void refuseConnection();
void connectionClosed();
bool handleCheckPassword(rfbClientPtr, const char *, int);
void handleKeyEvent(bool down, KeySym keySym);
void handlePointerEvent(int button_mask, int x, int y);
enum rfbNewClientAction handleNewClient(rfbClientPtr cl);
void clipboardToServer(const QString &text);
void handleClientGone();
void handleNegotiationFinished(rfbClientPtr cl);
int getPort();
void startServer(int inetdFd = -1, bool xtestGrab = true);
static bool checkX11Capabilities();
public slots:
void passwordChanged();
void closeConnection();
void enableDesktopControl(bool c);
signals:
void sessionEstablished(QString host);
void sessionFinished();
void sessionRefused();
void quitApp();
void desktopControlSettingChanged(bool);
private:
void stopServer(bool xtestUngrab = true);
void sendKNotifyEvent(const QString &name, const QString &desc);
void sendSessionEstablished();
void disableBackground(bool state);
QString remoteIp;
volatile bool allowDesktopControl;
QTimer initIdleTimer;
QTimer idleTimer;
enum {
LAST_SYNC_TO_SERVER,
LAST_SYNC_TO_CLIENT
} lastClipboardDirection;
QString lastClipboardText;
QClipboard *clipboard;
Configuration *configuration;
XUpdateScanner *scanner;
ConnectionDialog dialog;
QString desktopName;
rfbScreenInfoPtr server;
XImage *framebufferImage;
QMutex asyncMutex;
Q3PtrList<VNCEvent> asyncQueue;
bool disableBackgroundPending; // background, as desired by libvncserver
bool disableBackgroundState; // real background state
bool closePending; // set when libvncserver detected close
bool forcedClose; // set when user closed connection
private slots:
bool checkAsyncEvents();
void idleSlot();
void dialogAccepted();
void dialogRefused();
void selectionChanged();
void clipboardChanged();
};
/*
* Class to call XTestDiscard at idle time (because otherwise
* it will not work with QT)
*/
class XTestDisabler : public QObject {
Q_OBJECT
public:
XTestDisabler();
bool disable;
Display *dpy;
public slots:
void exec();
};
#endif

View File

@@ -1,483 +0,0 @@
/*
* Copyright (C) 2000 heXoNet Support GmbH, D-66424 Homburg.
* All Rights Reserved.
*
* This 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.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*/
/*
* December 15th 2001: removed coments, mouse pointer options and some
* other stuff
* January 10th 2002: improved hint creation (join adjacent hints)
* February 20th: use only partial tiles
* January 21st 2003: remember last modified scanlines, and scan them and
* in every cycle, reduce scanlines to every 35th
* January 21st 2003: scan lines around the cursor in every cycle
*
* Tim Jansen <tim@tjansen.de>
*/
#include <kdebug.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdlib.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/XShm.h>
#include <string.h>
#include <assert.h>
#include "xupdatescanner.h"
//Added by qt3to4:
#include <Q3PtrList>
/* ../../krfb/libvncserver/rfb.h */
#ifdef Bool
#undef Bool
#endif
#define Bool int
#define SCANLINES 35
unsigned int scanlines[SCANLINES] = { 0, 16, 8, 24,
33, 4, 20, 12, 28,
10, 26, 18, 34, 2,
22, 6, 30, 14,
1, 17, 32, 9, 25,
7, 23, 15, 31,
19, 3, 27, 11,
29, 13, 5, 21 };
#define MAX_ADJ_TOLERANCE 8
#define MAX_RECENT_HITS 12
unsigned int recentHitScanlines[MAX_RECENT_HITS];
#define CURSOR_SCANLINES 5
int cursorScanlines[CURSOR_SCANLINES] = {
-10, -4, 0, 4, 10
};
XUpdateScanner::XUpdateScanner(Display *_dpy,
Window _window,
unsigned char *_fb,
int _width,
int _height,
int _bitsPerPixel,
int _bytesPerLine,
bool useXShm) :
dpy(_dpy),
window(_window),
fb(_fb),
width(_width),
height(_height),
bitsPerPixel(_bitsPerPixel),
bytesPerLine(_bytesPerLine),
tileWidth(32),
tileHeight(32),
count (0),
scanline(NULL),
tile(NULL)
{
useShm = useXShm && XShmQueryExtension(dpy);
if (useShm) {
int major, minor;
Bool pixmaps;
if ((!XShmQueryVersion(dpy, &major, &minor, &pixmaps)) || !pixmaps)
useShm = false;
}
if (useShm) {
tile = XShmCreateImage(dpy,
DefaultVisual( dpy, 0 ),
bitsPerPixel,
ZPixmap,
NULL,
&shminfo_tile,
tileWidth,
tileHeight);
shminfo_tile.shmid = shmget(IPC_PRIVATE,
tile->bytes_per_line * tile->height,
IPC_CREAT | 0777);
shminfo_tile.shmaddr = tile->data = (char *)
shmat(shminfo_tile.shmid, 0, 0);
shminfo_tile.readOnly = False;
XShmAttach(dpy, &shminfo_tile);
}
else {
int tlen = tileWidth*(bitsPerPixel/8);
void *data = malloc(tlen*tileHeight);
tile = XCreateImage(dpy,
DefaultVisual(dpy, 0),
bitsPerPixel,
ZPixmap,
0,
(char*)data,
tileWidth,
tileHeight,
8,
tlen);
}
tilesX = (width + tileWidth - 1) / tileWidth;
tilesY = (height + tileHeight - 1) / tileHeight;
tileMap = new bool[tilesX * tilesY];
tileRegionMap = new struct TileChangeRegion[tilesX * tilesY];
unsigned int i;
for (i = 0; i < tilesX * tilesY; i++)
tileMap[i] = false;
if (useShm) {
scanline = XShmCreateImage(dpy,
DefaultVisual(dpy, 0),
bitsPerPixel,
ZPixmap,
NULL,
&shminfo_scanline,
width,
1);
shminfo_scanline.shmid = shmget(IPC_PRIVATE,
scanline->bytes_per_line,
IPC_CREAT | 0777);
shminfo_scanline.shmaddr = scanline->data = (char *)
shmat( shminfo_scanline.shmid, 0, 0 );
shminfo_scanline.readOnly = False;
XShmAttach(dpy, &shminfo_scanline);
}
else {
int slen = width*(bitsPerPixel/8);
void *data = malloc(slen);
scanline = XCreateImage(dpy,
DefaultVisual(dpy, 0),
bitsPerPixel,
ZPixmap,
0,
(char*)data,
width,
1,
8,
slen);
}
for (int i = 0; i < MAX_RECENT_HITS; i++)
recentHitScanlines[i] = i;
}
XUpdateScanner::~XUpdateScanner()
{
if (useShm) {
XShmDetach(dpy, &shminfo_scanline);
XDestroyImage(scanline);
shmdt(shminfo_scanline.shmaddr);
shmctl(shminfo_scanline.shmid, IPC_RMID, 0);
XShmDetach(dpy, &shminfo_tile);
XDestroyImage(tile);
shmdt(shminfo_tile.shmaddr);
shmctl(shminfo_tile.shmid, IPC_RMID, 0);
}
else {
free(tile->data);
free(scanline->data);
XDestroyImage(scanline);
XDestroyImage(tile);
}
delete tileMap;
delete tileRegionMap;
}
// returns true if last line changed. this is used to re-scan the tile under
// this one because it is likely to be modified but missed by the probe
bool XUpdateScanner::copyTile(int x, int y, int tx, int ty)
{
unsigned int maxWidth = width - x;
unsigned int maxHeight = height - y;
if (maxWidth > tileWidth)
maxWidth = tileWidth;
if (maxHeight > tileHeight)
maxHeight = tileHeight;
if (useShm) {
if ((maxWidth == tileWidth) && (maxHeight == tileHeight)) {
XShmGetImage(dpy, window, tile, x, y, AllPlanes);
} else {
XGetSubImage(dpy, window, x, y, maxWidth, maxHeight,
AllPlanes, ZPixmap, tile, 0, 0);
}
}
else
XGetSubImage(dpy, window, x, y, maxWidth, maxHeight,
AllPlanes, ZPixmap, tile, 0, 0);
unsigned int line;
int pixelsize = bitsPerPixel >> 3;
unsigned char *src = (unsigned char*) tile->data;
unsigned char *dest = fb + y * bytesPerLine + x * pixelsize;
unsigned char *ssrc = src;
unsigned char *sdest = dest;
int firstLine = maxHeight;
for (line = 0; line < maxHeight; line++) {
if (memcmp(sdest, ssrc, maxWidth * pixelsize)) {
firstLine = line;
break;
}
ssrc += tile->bytes_per_line;
sdest += bytesPerLine;
}
if (firstLine == maxHeight) {
tileMap[tx + ty * tilesX] = false;
return false;
}
unsigned char *msrc = src + (tile->bytes_per_line * maxHeight);
unsigned char *mdest = dest + (bytesPerLine * maxHeight);
int lastLine = firstLine;
for (line = maxHeight-1; line > firstLine; line--) {
msrc -= tile->bytes_per_line;
mdest -= bytesPerLine;
if (memcmp(mdest, msrc, maxWidth * pixelsize)) {
lastLine = line;
break;
}
}
for (line = firstLine; line <= lastLine; line++) {
memcpy(sdest, ssrc, maxWidth * pixelsize );
ssrc += tile->bytes_per_line;
sdest += bytesPerLine;
}
struct TileChangeRegion *r = &tileRegionMap[tx + (ty * tilesX)];
r->firstLine = firstLine;
r->lastLine = lastLine;
return lastLine == (maxHeight-1);
}
void XUpdateScanner::copyAllTiles()
{
for (unsigned int y = 0; y < tilesY; y++) {
for (unsigned int x = 0; x < tilesX; x++) {
if (tileMap[x + y * tilesX])
if (copyTile(x*tileWidth, y*tileHeight, x, y) &&
((y+1) < tilesY))
tileMap[x + (y+1) * tilesX] = true;
}
}
}
void XUpdateScanner::createHintFromTile(int x, int y, int th, Hint &hint)
{
unsigned int w = width - x;
unsigned int h = height - y;
if (w > tileWidth)
w = tileWidth;
if (h > th)
h = th;
hint.x = x;
hint.y = y;
hint.w = w;
hint.h = h;
}
void XUpdateScanner::addTileToHint(int x, int y, int th, Hint &hint)
{
unsigned int w = width - x;
unsigned int h = height - y;
if (w > tileWidth)
w = tileWidth;
if (h > th)
h = th;
if (hint.x > x) {
hint.w += hint.x - x;
hint.x = x;
}
if (hint.y > y) {
hint.h += hint.y - y;
hint.y = y;
}
if ((hint.x+hint.w) < (x+w)) {
hint.w = (x+w) - hint.x;
}
if ((hint.y+hint.h) < (y+h)) {
hint.h = (y+h) - hint.y;
}
}
static void printStatistics(Hint &hint) {
static int snum = 0;
static float ssum = 0.0;
int oX0 = hint.x & 0xffffffe0;
int oY0 = hint.y & 0xffffffe0;
int oX2 = (hint.x+hint.w) & 0x1f;
int oY2 = (hint.y+hint.h) & 0x1f;
int oX3 = (((hint.x+hint.w) | 0x1f) + ((oX2 == 0) ? 0 : 1)) & 0xffffffe0;
int oY3 = (((hint.y+hint.h) | 0x1f) + ((oY2 == 0) ? 0 : 1)) & 0xffffffe0;
float s0 = hint.w*hint.h;
float s1 = (oX3-oX0)*(oY3-oY0);
float p = (100*s0/s1);
ssum += p;
snum++;
float avg = ssum / snum;
kDebug() << "avg size: "<< avg <<"%"<<endl;
}
void XUpdateScanner::flushHint(int x, int y, int &x0,
Hint &hint, Q3PtrList<Hint> &hintList)
{
if (x0 < 0)
return;
x0 = -1;
assert (hint.w > 0);
assert (hint.h > 0);
//printStatistics(hint);
hintList.append(new Hint(hint));
}
void XUpdateScanner::createHints(Q3PtrList<Hint> &hintList)
{
Hint hint;
int x0 = -1;
for (int y = 0; y < tilesY; y++) {
int x;
for (x = 0; x < tilesX; x++) {
int idx = x + y * tilesX;
if (tileMap[idx]) {
int ty = tileRegionMap[idx].firstLine;
int th = tileRegionMap[idx].lastLine - ty +1;
if (x0 < 0) {
createHintFromTile(x * tileWidth,
(y * tileHeight) + ty,
th,
hint);
x0 = x;
} else {
addTileToHint(x * tileWidth,
(y * tileHeight) + ty,
th,
hint);
}
}
else
flushHint(x, y, x0, hint, hintList);
}
flushHint(x, y, x0, hint, hintList);
}
}
void XUpdateScanner::testScanline(int y, bool rememberHits) {
if (y < 0)
return;
if (y >= (int)height)
return;
int x = 0;
bool hit = false;
if (useShm)
XShmGetImage(dpy, window, scanline, 0, y, AllPlanes);
else
XGetSubImage(dpy, window, 0, y, width, 1,
AllPlanes, ZPixmap, scanline, 0, 0);
while (x < width) {
int pixelsize = bitsPerPixel >> 3;
unsigned char *src = (unsigned char*) scanline->data +
x * pixelsize;
unsigned char *dest = fb +
y * bytesPerLine + x * pixelsize;
int w = (x + 32) > width ? (width-x) : 32;
if (memcmp(dest, src, w * pixelsize)) {
hit = true;
tileMap[(x / tileWidth) +
(y / tileHeight) * tilesX] = true;
}
x += 32;
}
if (!rememberHits)
return;
for (int i = 1; i < MAX_RECENT_HITS; i++)
recentHitScanlines[i-1] = recentHitScanlines[i];
recentHitScanlines[MAX_RECENT_HITS-1] = y;
}
void XUpdateScanner::searchUpdates(Q3PtrList<Hint> &hintList, int ptrY)
{
count++;
count %= SCANLINES;
unsigned int i;
unsigned int y;
for (i = 0; i < (tilesX * tilesY); i++) {
tileMap[i] = false;
}
// test last scanlines with hits
for (i = 0; i < MAX_RECENT_HITS; i++)
testScanline(recentHitScanlines[i], true);
// test scanlines around the cursor
for (i = 0; i < CURSOR_SCANLINES; i++)
testScanline(ptrY+cursorScanlines[i], false);
// test last/first line of the tiles around the cursor
// (assumes tileHeight = 32)
testScanline((ptrY&0xffe0)-1, false);
testScanline((ptrY|0x1f)+1, false);
// test every SCANLINESth scanline
y = scanlines[count];
while (y < (int)height) {
testScanline(y, true);
y += SCANLINES;
}
copyAllTiles();
createHints(hintList);
}

View File

@@ -1,112 +0,0 @@
/*
* Copyright (C) 2000 heXoNet Support GmbH, D-66424 Homburg.
* All Rights Reserved.
*
* This 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.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*/
#ifndef _hexonet_rfb_XUpdateScanner_h_
#define _hexonet_rfb_XUpdateScanner_h_
#include <q3ptrlist.h>
#include <X11/Xlib.h>
#include <X11/extensions/XShm.h>
class Hint {
public:
int x, y, w, h;
Hint() :
x(0),
y(0),
w(0),
h(0)
{}
Hint(Hint &h) :
x(h.x),
y(h.y),
w(h.w),
h(h.h)
{
}
int left() {
return x;
}
int right() {
return x+w;
}
int top() {
return y;
}
int bottom() {
return y+h;
}
};
struct TileChangeRegion {
short firstLine, lastLine;
};
class XUpdateScanner
{
public:
XUpdateScanner( Display *_dpy,
Window _window,
unsigned char *_fb,
int _width, int _height,
int _bitsPerPixel, int _bytesPerLine,
bool useXShm);
~XUpdateScanner();
// hitList: returns list of changes
// ptrY: ptrY: position of the cursor
void searchUpdates( Q3PtrList<Hint> &hintList, int ptrY);
private:
void testScanline(int y, bool rememberHits);
bool copyTile(int x, int y, int tx, int ty);
void copyAllTiles();
void flushHint(int x, int y, int &x0, Hint &hint,
Q3PtrList<Hint> &hintList);
void createHints(Q3PtrList<Hint> &hintList);
void addTileToHint(int x, int y, int th, Hint &hint);
void createHintFromTile(int x, int y, int th, Hint &hint);
Display *dpy;
Window window;
unsigned char *fb;
int width, height;
int bitsPerPixel, bytesPerLine;
unsigned int tileWidth, tileHeight;
unsigned int count;
bool useShm;
XImage *scanline;
XShmSegmentInfo shminfo_scanline;
XImage *tile;
XShmSegmentInfo shminfo_tile;
unsigned int tilesX, tilesY;
bool *tileMap;
struct TileChangeRegion *tileRegionMap;
};
#endif // _hexonet_rfb_XUpdateScanner_h_