sync, almost 0.1

svn path=/trunk/kdenetwork/krfb/; revision=127978
This commit is contained in:
Tim Jansen
2001-12-19 20:35:12 +00:00
parent bbcaf86931
commit dbda058e7f
12 changed files with 356 additions and 361 deletions

7
TODO
View File

@@ -1,7 +1,6 @@
Todo:
- fix what's-this help in dialogs
- remove help buttons?
- add command-line args (one-connection, set-password, ask-on-connect)
- idle singleton to destroy XTest resources
- i18n (0.2)
Possible features:

View File

@@ -51,7 +51,7 @@ krfb_LDFLAGS = $(all_libraries) $(KDE_RPATH) -lXtst
#rcdir = $(kde_datadir)/krfb
#rc_DATA = krfbui.rc
messages: rc.cpp
messages:
LIST=`find . -name \*.h -o -name \*.hh -o -name \*.H -o -name \*.hxx -o -name \*.hpp -o -name \*.cpp -o -name \*.cc -o -name \*.cxx -o -name \*.ecpp -o -name \*.C`; \
if test -n "$$LIST"; then \
$(XGETTEXT) $$LIST -o $(podir)/krfb.pot; \

View File

@@ -18,6 +18,7 @@
* USA.
*/
#include <sys/ipc.h>
#include <sys/shm.h>
#include <X11/Xlib.h>
@@ -37,305 +38,165 @@ unsigned int scanlines[32] = { 0, 16, 8, 24,
19, 3, 27, 11,
29, 13, 5, 21 };
XUpdateScanner::XUpdateScanner( Display *_dpy,
Window _window,
Framebuffer *_fb,
unsigned int _tileWidth,
unsigned int _tileHeight,
unsigned int _blockWidth,
unsigned int _blockHeight )
: dpy( _dpy )
, window( _window )
, fb( _fb )
, tileWidth( 32 )
, tileHeight( 32 )
, blockWidth( _blockWidth )
, blockHeight( _blockHeight )
, count ( 0 )
, scanline( NULL )
, tile( NULL )
XUpdateScanner::XUpdateScanner(Display *_dpy,
Window _window,
Framebuffer *_fb,
unsigned int _tileWidth,
unsigned int _tileHeight,
unsigned int _blockWidth,
unsigned int _blockHeight) :
dpy(_dpy),
window(_window),
fb(_fb),
tileWidth(32),
tileHeight(32),
blockWidth(_blockWidth),
blockHeight(_blockHeight),
count (0),
scanline(NULL),
tile(NULL)
{
// tile = XGetImage( dpy, window, 0, 0, tileWidth, tileHeight, AllPlanes, ZPixmap );
tile = XShmCreateImage( dpy,
DefaultVisual( dpy, 0 ),
fb->pixelFormat.bits_per_pixel,
ZPixmap,
NULL,
&shminfo_tile,
tileWidth,
tileHeight );
tile = XShmCreateImage(dpy,
DefaultVisual( dpy, 0 ),
fb->pixelFormat.bits_per_pixel,
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;
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 );
XShmAttach(dpy, &shminfo_tile);
tilesX = (fb->width + tileWidth - 1) / tileWidth;
tilesY = (fb->height + tileHeight - 1) / tileHeight;
tileMap = (char *) malloc( tilesX * tilesY );
tilesX = (fb->width + tileWidth - 1) / tileWidth;
tilesY = (fb->height + tileHeight - 1) / tileHeight;
tileMap = (char*) malloc(tilesX * tilesY);
unsigned int i;
for ( i = 0; i < tilesX * tilesY; i++ ) tileMap[i] = 0;
unsigned int i;
for (i = 0; i < tilesX * tilesY; i++)
tileMap[i] = 0;
scanline = XShmCreateImage( dpy,
DefaultVisual( dpy, 0 ),
fb->pixelFormat.bits_per_pixel,
ZPixmap,
NULL,
&shminfo_scanline,
fb->width,
1 );
scanline = XShmCreateImage(dpy,
DefaultVisual(dpy, 0),
fb->pixelFormat.bits_per_pixel,
ZPixmap,
NULL,
&shminfo_scanline,
fb->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 );
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);
};
XUpdateScanner::~XUpdateScanner()
{
XShmDetach( dpy, &shminfo_scanline );
XDestroyImage( scanline );
shmdt( shminfo_scanline.shmaddr );
shmctl( shminfo_scanline.shmid, IPC_RMID, 0 );
free( tileMap );
XShmDetach( dpy, &shminfo_tile );
XDestroyImage( tile );
shmdt( shminfo_tile.shmaddr );
shmctl( shminfo_tile.shmid, IPC_RMID, 0 );
XShmDetach(dpy, &shminfo_scanline);
XDestroyImage(scanline);
shmdt(shminfo_scanline.shmaddr);
shmctl(shminfo_scanline.shmid, IPC_RMID, 0);
free(tileMap);
XShmDetach(dpy, &shminfo_tile);
XDestroyImage(tile);
shmdt(shminfo_tile.shmaddr);
shmctl(shminfo_tile.shmid, IPC_RMID, 0);
}
void XUpdateScanner::checkTile( int x, int y, list< Hint > &hintList )
void XUpdateScanner::checkTile(int x, int y, list<Hint> &hintList)
{
unsigned int maxWidth = fb->width - x;
unsigned int maxHeight = fb->height - y;
if ( maxWidth > tileWidth ) maxWidth = tileWidth;
if ( maxHeight > tileHeight ) maxHeight = tileHeight;
unsigned int maxWidth = fb->width - x;
unsigned int maxHeight = fb->height - y;
if (maxWidth > tileWidth)
maxWidth = tileWidth;
if (maxHeight > tileHeight)
maxHeight = tileHeight;
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 );
}
unsigned int line;
bool changed = false;
unsigned char *src = (unsigned char*) tile->data;
unsigned char *dest = fb->data + y * fb->bytesPerLine + x * (fb->pixelFormat.bits_per_pixel >> 3);
for ( line = 0; line < maxHeight; line++ ) {
if ( memcmp( dest, src, maxWidth * (fb->pixelFormat.bits_per_pixel >> 3) ) ) {
changed = true;
memcpy( dest, src, maxWidth * (fb->pixelFormat.bits_per_pixel >> 3) );
}
src += tile->bytes_per_line;
dest += fb->bytesPerLine;
}
unsigned int tx = x / tileWidth;
unsigned int ty = y / tileHeight;
if ( changed ) {
Hint hint;
hint.type = hintRefresh;
hint.hint.refresh.x = x;
hint.hint.refresh.y = y;
hint.hint.refresh.width = maxWidth;
hint.hint.refresh.height = maxHeight;
hintList.push_back( hint );
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);
}
unsigned int line;
bool changed = false;
int pixelsize = fb->pixelFormat.bits_per_pixel >> 3;
unsigned char *src = (unsigned char*) tile->data;
unsigned char *dest = fb->data + y * fb->bytesPerLine + x * pixelsize;
for (line = 0; line < maxHeight; line++) {
if ( changed || memcmp(dest, src, maxWidth * pixelsize) ) {
changed = true;
memcpy(dest, src, maxWidth * pixelsize );
}
src += tile->bytes_per_line;
dest += fb->bytesPerLine;
}
/*
tileMap[ tx + ty * tilesX ] += 2;
if ( tx > 0 )
if ( tileMap[ (tx-1) + ty * tilesX ] <= 1 ) tileMap[ (tx-1) + ty * tilesX ] = 2;
if ( ty > 0 )
if ( tileMap[ tx + (ty-1) * tilesX ] <= 1 ) tileMap[ tx + (ty-1) * tilesX ] = 2;
if ( tx < tilesX-1 )
if ( tileMap[ (tx+1) + ty * tilesX ] <= 1 ) tileMap[ (tx+1) + ty * tilesX ] = 2;
if ( ty < tilesY-1 )
if ( tileMap[ tx + (ty+1) * tilesX ] <= 1 ) tileMap[ tx + (ty+1) * tilesX ] = 2;
} else {
if ( tileMap[ tx + ty * tilesX ] >= 2 )
tileMap[ tx + ty * tilesX ] -= 2;
*/
}
if (changed) {
Hint hint;
hint.type = hintRefresh;
hint.hint.refresh.x = x;
hint.hint.refresh.y = y;
hint.hint.refresh.width = maxWidth;
hint.hint.refresh.height = maxHeight;
hintList.push_back(hint);
}
}
#define POINTER_WIDTH 12
#define POINTER_HEIGHT 18
char pointerMap[] =
" "
" .. "
" .+. "
" .++. "
" .+++. "
" .++++. "
" .+++++. "
" .++++++. "
" .+++++++. "
" .++++++++. "
" .+++++.... "
" .++.++. "
" .+. .++. "
" .. .++. "
" .++. "
" .++. "
" .. "
" ";
void XUpdateScanner::searchUpdates( list< Hint > &hintList,
bool showMousePointer)
void XUpdateScanner::searchUpdates(list<Hint> &hintList,
bool showMousePointer)
{
/*
count %= (blockWidth * blockHeight);
if ( count % 4 == 0 ) {
unsigned int i;
for ( i = 0; i < tilesX * tilesY; i++ ) {
if ( tileMap[i] > 0 ) tileMap[i]--;
if ( tileMap[i] <= 0 )
tileMap[i] += (count == (i % (blockWidth * blockHeight)))? 1 : 0;
if ( tileMap[i] > 16 )
tileMap[i] = 16;
if ( tileMap[i] < -8 )
tileMap[i] = -8;
}
}
*/
count %= 32;
unsigned int i;
unsigned int x, y;
count %= 32;
unsigned int i;
unsigned int x, y;
for ( i = 0; i < tilesX * tilesY; i++ ) {
// if ( tileMap[i] > 0 ) tileMap[i]--;
// if ( tileMap[i] > 8 ) tileMap[i] = 8;
tileMap[i] = 0;
}
for (i = 0; i < (tilesX * tilesY); i++) {
tileMap[i] = 0;
}
y = scanlines[count];
while ( y < fb->height ) {
XShmGetImage( dpy, window, scanline, 0, y, AllPlanes );
x = 0;
while ( x < fb->width ) {
unsigned char *src = (unsigned char*) scanline->data + x * (fb->pixelFormat.bits_per_pixel >> 3);
unsigned char *dest = fb->data + y * fb->bytesPerLine + x * (fb->pixelFormat.bits_per_pixel >> 3);
if ( memcmp( dest, src, 32 * (fb->pixelFormat.bits_per_pixel >> 3) ) ) {
tileMap[ (x / tileWidth) + (y / tileHeight) * tilesX ] = 1;
}
x += 32;
}
y += 32;
}
y = scanlines[count];
while (y < fb->height) {
XShmGetImage(dpy, window, scanline, 0, y, AllPlanes);
x = 0;
while (x < fb->width) {
int pixelsize = fb->pixelFormat.bits_per_pixel >> 3;
unsigned char *src = (unsigned char*) scanline->data +
x * pixelsize;
unsigned char *dest = fb->data +
y * fb->bytesPerLine + x * pixelsize;
if (memcmp(dest, src, 32 * pixelsize)) {
tileMap[(x / tileWidth) +
(y / tileHeight) * tilesX] = 1;
}
x += 32;
}
y += 32;
}
for ( y = 0; y < tilesY; y++ ) {
for ( x = 0; x < tilesX; x++ ) {
if ( tileMap[x + y * tilesX] > 0 )
checkTile( x * tileWidth, y * tileHeight, hintList );
}
}
for (y = 0; y < tilesY; y++) {
for (x = 0; x < tilesX; x++) {
if (tileMap[x + y * tilesX] > 0)
checkTile(x*tileWidth, y*tileHeight,
hintList);
}
}
if ( showMousePointer ) {
Window root_return, child_return;
int root_x, root_y;
int win_x, win_y;
unsigned int mask_return;
XQueryPointer( dpy, window, &root_return, &child_return,
&root_x, &root_y,
&win_x, &win_y,
&mask_return );
// draw Pointer Map
int px, py, mx, my;
mx = fb->width - root_x;
if ( mx > POINTER_WIDTH ) mx = POINTER_WIDTH;
my = fb->height - root_y;
if ( my > POINTER_HEIGHT ) my = POINTER_HEIGHT;
for ( py = 0; py < my; py++ )
for ( px = 0; px < mx; px++ ) {
int ofs = (root_x + px) * (fb->pixelFormat.bits_per_pixel >> 3)
+ (root_y + py) * fb->bytesPerLine;
switch ( pointerMap[ px + py * POINTER_WIDTH ] ) {
case '.':
switch ( fb->pixelFormat.bits_per_pixel ) {
case 8:
fb->data[ofs] = 0;
break;
case 16:
fb->data[ofs] = 0;
fb->data[ofs+1] = 0;
break;
case 24:
fb->data[ofs] = 0;
fb->data[ofs+1] = 0;
fb->data[ofs+2] = 0;
break;
case 32:
fb->data[ofs] = 0;
fb->data[ofs+1] = 0;
fb->data[ofs+2] = 0;
fb->data[ofs+3] = 0;
break;
}
break;
case '+':
switch ( fb->pixelFormat.bits_per_pixel ) {
case 8:
fb->data[ofs] = 255;
break;
case 16:
fb->data[ofs] = 255;
fb->data[ofs+1] = 255;
break;
case 24:
fb->data[ofs] = 255;
fb->data[ofs+1] = 255;
fb->data[ofs+2] = 255;
break;
case 32:
fb->data[ofs] = 255;
fb->data[ofs+1] = 255;
fb->data[ofs+2] = 255;
fb->data[ofs+3] = 255;
break;
}
break;
default: break;
}
}
/*
Hint hint;
hint.type = hintRefresh;
hint.hint.refresh.x = root_x;
hint.hint.refresh.y = root_y;
hint.hint.refresh.width = mx;
hint.hint.refresh.height = my;
hintList.push_back( hint );
*/
}
count++;
count++;
}
} // namespace rfb

View File

@@ -24,12 +24,13 @@
#include <qlineedit.h>
#include <qcheckbox.h>
Configuration::Configuration()
Configuration::Configuration() :
preconfiguredFlag(false),
oneConnectionFlag(false)
{
loadFromKConfig();
saveToDialog();
portValidator = new QIntValidator(0, 65535,
confDlg.displayNumberInput);
confDlg.displayNumberInput->setValidator(portValidator);
@@ -42,16 +43,32 @@ Configuration::Configuration()
SLOT(applyPressed()));
}
Configuration::Configuration(bool oneConnection, bool askOnConnect,
bool allowDesktopControl, QString password,
int port) :
preconfiguredFlag(true),
oneConnectionFlag(oneConnection),
askOnConnectFlag(askOnConnect),
allowDesktopControlFlag(allowDesktopControl),
passwordString(password)
{
if ((port >= 5900) && (port < 6000))
portNumber = port-5900;
else
portNumber = port;
}
Configuration::~Configuration() {
}
void Configuration::loadFromKConfig() {
if (preconfigured())
return;
KConfig *config = KGlobal::config();
askOnConnectFlag = config->readBoolEntry("askOnConnect", true);
allowDesktopControlFlag = config->readBoolEntry("allowDesktopControl",
false);
showMousePointerFlag = config->readBoolEntry("showMousePointer",
true);
passwordString = config->readEntry("password", "");
portNumber = config->readNumEntry("port", 0);
}
@@ -59,7 +76,6 @@ void Configuration::loadFromKConfig() {
void Configuration::loadFromDialog() {
askOnConnectFlag = confDlg.askOnConnectCB->isChecked();
allowDesktopControlFlag = confDlg.allowDesktopControlCB->isChecked();
showMousePointerFlag = confDlg.showMousePointerCB->isChecked();
passwordString = confDlg.passwordInput->text();
int p = confDlg.displayNumberInput->text().toInt();
if (p != portNumber) {
@@ -69,10 +85,11 @@ void Configuration::loadFromDialog() {
}
void Configuration::saveToKConfig() {
if (preconfigured())
return;
KConfig *config = KGlobal::config();
config->writeEntry("askOnConnect", askOnConnectFlag);
config->writeEntry("allowDesktopControl", allowDesktopControlFlag);
config->writeEntry("showMousePointer", showMousePointerFlag);
config->writeEntry("password", passwordString);
config->writeEntry("port", portNumber);
}
@@ -80,11 +97,18 @@ void Configuration::saveToKConfig() {
void Configuration::saveToDialog() {
confDlg.askOnConnectCB->setChecked(askOnConnectFlag);
confDlg.allowDesktopControlCB->setChecked(allowDesktopControlFlag);
confDlg.showMousePointerCB->setChecked(showMousePointerFlag);
confDlg.passwordInput->setText(passwordString);
confDlg.displayNumberInput->setText(QString().setNum(portNumber));
}
bool Configuration::preconfigured() const {
return preconfiguredFlag;
}
bool Configuration::oneConnection() const {
return oneConnectionFlag;
}
bool Configuration::askOnConnect() const {
return askOnConnectFlag;
}
@@ -93,10 +117,6 @@ bool Configuration::allowDesktopControl() const {
return allowDesktopControlFlag;
}
bool Configuration::showMousePointer() const {
return showMousePointerFlag;
}
QString Configuration::password() const {
return passwordString;
}

View File

@@ -33,11 +33,14 @@ class Configuration : public QObject {
Q_OBJECT
public:
Configuration();
Configuration(bool oneConnection, bool askOnConnect,
bool allowDesktopControl, QString password, int port);
~Configuration();
bool preconfigured() const;
bool oneConnection() const;
bool askOnConnect() const;
bool allowDesktopControl() const;
bool showMousePointer() const;
QString password() const;
int port() const;
@@ -57,9 +60,10 @@ private:
ConfigurationDialog confDlg;
QIntValidator *portValidator;
bool preconfiguredFlag;
bool askOnConnectFlag;
bool allowDesktopControlFlag;
bool showMousePointerFlag;
bool oneConnectionFlag;
QString passwordString;
int portNumber;

View File

@@ -12,7 +12,7 @@
<x>0</x>
<y>0</y>
<width>318</width>
<height>284</height>
<height>257</height>
</rect>
</property>
<property stdset="1">
@@ -98,21 +98,6 @@
<string>If you turn this option on the remote user can enter keystrokes and use your mouse pointer. This gives him full control over your computer, so be careful. When the option is disabled the remote user can only watch your screen.</string>
</property>
</widget>
<widget>
<class>QCheckBox</class>
<property stdset="1">
<name>name</name>
<cstring>showMousePointerCB</cstring>
</property>
<property stdset="1">
<name>text</name>
<string>&amp;show mouse pointer on remote client</string>
</property>
<property>
<name>whatsThis</name>
<string>If you enable this option the remote client can see the mouse pointer of this display additionally to his own. Especially if you have a slow network connection (modem, ISDN) this will make the remote display appear more sloppy. On the other hand the cursor will let the remote user orienting on the screen because the cursor moves slower on a remote connection.</string>
</property>
</widget>
</vbox>
</widget>
<widget>
@@ -182,7 +167,8 @@
</property>
<property>
<name>whatsThis</name>
<string>Enter the display number/port here. Unless you have more than one server running on the machine just enter 0. Regular RFB/VNC port numbers are between 0 and 99. If you enter a higher number it will be used as TCP port. Note that ports below 1024 require root privileges.</string>
<string>Enter the display number/port here. Unless you have more than one server running on the machine just enter 0.
Regular RFB/VNC port numbers are between 0 and 99. If you enter a higher number it will be used as TCP port. Note that ports below 1024 require root privileges.</string>
</property>
</widget>
</vbox>

View File

@@ -1,5 +1,5 @@
/***************************************************************************
main.cpp - description
main.cpp
-------------------
begin : Sat Dec 8 03:23:02 CET 2001
copyright : (C) 2001 by Tim Jansen
@@ -21,53 +21,131 @@
#include <kpixmap.h>
#include <kaction.h>
#include <kdebug.h>
#include <kapplication.h>
#include <ksystemtray.h>
#include <kcmdlineargs.h>
#include <kaboutdata.h>
#include <kaboutapplication.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <qobject.h>
#include <qwindowdefs.h>
#define VERSION "0.1"
static const char *description = I18N_NOOP("Krfb");
static const char *description = I18N_NOOP("RFB (VNC) Server to share "
"KDE sessions");
#define ARG_PORT "port"
#define ARG_ONE_SESSION "one-session"
#define ARG_PASSWORD "password"
#define ARG_DONT_CONFIRM_CONNECT "dont-confirm-connect"
#define ARG_REMOTE_CONTROL "remote-control"
static KCmdLineOptions options[] =
{
{ "p ", 0, 0},
{ ARG_PORT " ", I18N_NOOP("Set the display number the server is listening on."), "0"},
{ "o", 0, 0},
{ ARG_ONE_SESSION, I18N_NOOP("Terminate when the first session is finished."), 0},
{ "w ", 0, 0},
{ ARG_PASSWORD " ", I18N_NOOP("Set the password."), 0},
{ "d", 0, 0},
{ ARG_DONT_CONFIRM_CONNECT, I18N_NOOP("Allow connections without asking the user."), 0},
{ "c", 0, 0},
{ ARG_REMOTE_CONTROL, I18N_NOOP("Allow remote side to control this computer."), 0},
{ 0, 0, 0 }
// INSERT YOUR COMMANDLINE OPTIONS HERE
};
static int checkX11Capabilities() {
int bp1, bp2, majorv, minorv;
Bool r = XTestQueryExtension(qt_xdisplay(), &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. KRfb can not run on your system."),
i18n("KRfb Error"));
return 1;
}
r = XShmQueryExtension(qt_xdisplay());
if (!r) {
KMessageBox::error(0,
i18n("Your X11 Server does not support the required XShm extension. You are probably not running KRfb on a local server which is required."),
i18n("KRfb Error"));
return 1;
}
return 0;
}
int main(int argc, char *argv[])
{
KAboutData aboutData( "krfb", I18N_NOOP("Krfb"),
int r;
KAboutData aboutData( "krfb", I18N_NOOP("KRfb"),
VERSION, description, KAboutData::License_GPL,
"(c) 2001, Tim Jansen", 0, 0, "tim@tjansen.de");
aboutData.addAuthor("Tim Jansen",0, "tim@tjansen.de");
KCmdLineArgs::init( argc, argv, &aboutData );
KCmdLineArgs::addCmdLineOptions( options );
"(c) 2000, heXoNet Support GmbH, D-66424 Homburg\n"
"(c) 2001, Tim Jansen", 0, "http://www.tjansen.de/krfb",
"ml@tjansen.de");
aboutData.addAuthor("Jens Wagner (heXoNet Support GmbH)",
"RFB library, original x0rfbserver",
"");
aboutData.addAuthor("Tim Jansen", "KDE Port", "tim@tjansen.de");
KCmdLineArgs::init(argc, argv, &aboutData);
KCmdLineArgs::addCmdLineOptions(options);
KApplication app;
TrayIcon trayicon;
Configuration config;
RFBController controller(&config);
if ((r = checkX11Capabilities()) != 0)
return r;
QObject::connect(&trayicon, SIGNAL(showConfigure()),
&config, SLOT(showDialog()));
Configuration *config;
KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
if (args->isSet(ARG_PORT) ||
args->isSet(ARG_ONE_SESSION) ||
args->isSet(ARG_PASSWORD) ||
args->isSet(ARG_REMOTE_CONTROL) ||
args->isSet(ARG_DONT_CONFIRM_CONNECT)) {
bool oneConnection = args->isSet(ARG_ONE_SESSION);
bool askOnConnect = !args->isSet(ARG_DONT_CONFIRM_CONNECT);
bool allowDesktopControl = args->isSet(ARG_REMOTE_CONTROL);
QString password = args->getOption(ARG_PASSWORD);
int port = args->getOption(ARG_PORT).toInt();
config = new Configuration(oneConnection, askOnConnect,
allowDesktopControl, password, port);
}
else
config = new Configuration();
args->clear();
TrayIcon trayicon(new KAboutApplication(&aboutData), config);
RFBController controller(config);
if (controller.state() == RFB_ERROR)
return 1;
QObject::connect(&app, SIGNAL(lastWindowClosed()),
&app, SLOT(quit()));
QObject::connect(&controller, SIGNAL(sessionEstablished()),
&trayicon, SLOT(openConnection()));
QObject::connect(&controller, SIGNAL(sessionFinished()),
&trayicon, SLOT(closeConnection()));
QObject::connect(&trayicon, SIGNAL(showConfigure()),
config, SLOT(showDialog()));
QObject::connect(&trayicon, SIGNAL(connectionClosed()),
&controller, SLOT(closeSession()));
QObject::connect(&config, SIGNAL(portChanged()),
QObject::connect(config, SIGNAL(portChanged()),
&controller, SLOT(rebind()));
QObject::connect(&controller, SIGNAL(sessionEstablished()),
&trayicon, SLOT(openConnection()));
if (config->oneConnection()) {
QObject::connect(&controller, SIGNAL(sessionRefused()),
&controller, SLOT(quit()));
QObject::connect(&controller, SIGNAL(sessionFinished()),
&trayicon, SLOT(quit()));
} else {
QObject::connect(&controller, SIGNAL(sessionFinished()),
&trayicon, SLOT(closeConnection()));
}
return app.exec();
}

View File

@@ -62,10 +62,9 @@ RFBConnection::~RFBConnection() {
DeleteBlocks();
destroyFramebuffer();
XTestDiscard( dpy );
// XTestDiscard(dpy); // (makes problems with Qt??)
delete bufferedConnection;
close(fd);
}
void RFBConnection::handleKeyEvent(KeyEvent &keyEvent) {

View File

@@ -27,6 +27,8 @@
#include <fcntl.h>
#include <kdebug.h>
#include <kmessagebox.h>
#include <klocale.h>
#include <qwindowdefs.h>
#include <qtimer.h>
#include <qcheckbox.h>
@@ -48,7 +50,8 @@ RFBController::RFBController(Configuration *c) :
}
RFBController::~RFBController() {
delete serversocket;
if (serversocket)
delete serversocket;
if (socket)
delete socket;
if (connection)
@@ -58,8 +61,24 @@ RFBController::~RFBController() {
void RFBController::startServer() {
serversocket = new KServerSocket(configuration->port(), false);
connect(serversocket, SIGNAL(accepted(KSocket*)), SLOT(accepted(KSocket*)));
serversocket->bindAndListen();
// TODO: error message if bindAndListen fails (port in use)
if (!serversocket->bindAndListen()) {
delete serversocket;
serversocket = 0;
KMessageBox::error(0,
i18n("KRfb Server cannot run, port %1 is already in use. ")
.arg(configuration->port()),
i18n("KRfb Error"));
}
}
RFBState RFBController::state() {
if (!serversocket)
return RFB_ERROR;
if (!socket)
return RFB_WAITING;
if (!connection)
return RFB_CONNECTING;
return RFB_CONNECTED;
}
void RFBController::rebind() {
@@ -107,35 +126,27 @@ void RFBController::acceptConnection(bool allowDesktopControl) {
connection = new RFBConnection(qt_xdisplay(), s->socket(),
configuration->password(),
allowDesktopControl,
configuration->showMousePointer());
false);
emit sessionEstablished();
}
void RFBController::checkWriteBuffer() {
BufferedConnection *bc = connection->bufferedConnection;
socket->enableWrite((bc->senderBuffer.end - bc->senderBuffer.pos) > 0);
}
void RFBController::idleSlot() {
kdDebug() << "Idle 1" << endl;
idleUpdateScheduled = false;
if (connection) {
kdDebug() << "Idle 2" << endl;
connection->scanUpdates();
connection->sendIncrementalFramebufferUpdate();
checkWriteBuffer();
}
}
void RFBController::prepareIdleUpdate() {
kdDebug() << "test schedule, isScheduled? " << idleUpdateScheduled<< endl;
void RFBController::checkWriteBuffer() {
BufferedConnection *bc = connection->bufferedConnection;
if (((bc->senderBuffer.end - bc->senderBuffer.pos) == 0) &&
!idleUpdateScheduled) {
bool bufferEmpty = (bc->senderBuffer.end - bc->senderBuffer.pos) == 0;
socket->enableWrite(!bufferEmpty);
if (bufferEmpty && !idleUpdateScheduled && connection) {
QTimer::singleShot(0, this, SLOT(idleSlot()));
idleUpdateScheduled = true;
kdDebug() << "Scheduled!" << endl;
}
}
@@ -149,7 +160,10 @@ void RFBController::socketReadable() {
if (count >= 0)
bc->receiverBuffer.end += count;
else {
// TODO: what to do if write failed
closeSession();
KMessageBox::error(0,
i18n("An error occurred while reading from the remote client. The connection will be terminated."),
i18n("KRfb Error"));
}
while (connection->currentState && bc->hasReceiverBufferData()) {
connection->update();
@@ -164,21 +178,20 @@ void RFBController::socketReadable() {
void RFBController::socketWritable() {
ASSERT(socket);
kdDebug() << "write slot" << endl;
int fd = socket->socket();
BufferedConnection *bc = connection->bufferedConnection;
ASSERT((bc->senderBuffer.end - bc->senderBuffer.pos) > 0);
// TODO: what to do if fd < 0?
int count = write(fd,
bc->senderBuffer.data + bc->senderBuffer.pos,
bc->senderBuffer.end - bc->senderBuffer.pos);
if (count >= 0) {
bc->senderBuffer.pos += count;
} else {
// TODO: what to do if write failed
KMessageBox::error(0,
i18n("An error occurred while writing to the remote client. The connection will be terminated."),
i18n("KRfb Error"));
}
kdDebug() << "written " << count << " left " << (bc->senderBuffer.end - bc->senderBuffer.pos) << endl;
prepareIdleUpdate();
checkWriteBuffer();
}
@@ -207,6 +220,7 @@ void RFBController::dialogRefused() {
closeSocket();
dialog.hide();
emit sessionRefused();
}
void RFBController::closeSocket() {

View File

@@ -32,6 +32,13 @@
using namespace rfb;
typedef enum {
RFB_ERROR,
RFB_WAITING,
RFB_CONNECTING,
RFB_CONNECTED
} RFBState;
/**
* Manages sockets, drives the RGBConnection and triggers the connection
* dialog.
@@ -47,6 +54,8 @@ public:
RFBController(Configuration *c);
~RFBController();
RFBState state();
public slots:
void rebind();
void closeSession();
@@ -54,11 +63,11 @@ public slots:
signals:
void sessionEstablished();
void sessionFinished();
void sessionRefused();
private:
void startServer();
void checkWriteBuffer();
void prepareIdleUpdate();
void acceptConnection(bool ask);
void closeSocket();

View File

@@ -16,23 +16,35 @@
***************************************************************************/
#include "trayicon.h"
#include <kdebug.h>
#include <klocale.h>
#include <kdialog.h>
#include <kglobal.h>
#include <kiconloader.h>
#include <kpopupmenu.h>
TrayIcon::TrayIcon() : KSystemTray() {
TrayIcon::TrayIcon(KDialog *d, Configuration *c) :
KSystemTray(),
aboutDialog(d)
{
KIconLoader *loader = KGlobal::iconLoader();
trayIconOpen = loader->loadIcon("eyes-open24", KIcon::User);
trayIconClosed = loader->loadIcon("eyes-closed24", KIcon::User);
setPixmap(trayIconClosed);
configureAction = new KAction(i18n("&Configure KRfb"));
configureAction->plug(contextMenu());
if (!c->preconfigured())
configureAction->plug(contextMenu());
closeConnectionAction = new KAction(i18n("Close connection"));
closeConnectionAction->plug(contextMenu());
closeConnectionAction->setEnabled(false);
contextMenu()->insertSeparator();
aboutAction = new KAction(i18n("&About KRfb"));
aboutAction->plug(contextMenu());
connect(configureAction, SIGNAL(activated()), SIGNAL(showConfigure()));
connect(aboutAction, SIGNAL(activated()), SLOT(showAbout()));
connect(closeConnectionAction, SIGNAL(activated()),
SIGNAL(connectionClosed()));
show();
@@ -50,3 +62,7 @@ void TrayIcon::closeConnection(){
setPixmap(trayIconClosed);
closeConnectionAction->setEnabled(false);
}
void TrayIcon::showAbout() {
aboutDialog->show();
}

View File

@@ -18,11 +18,15 @@
#ifndef TRAYICON_H
#define TRAYICON_H
#include "configuration.h"
#include <qwidget.h>
#include <kpixmap.h>
#include <kaction.h>
#include <ksystemtray.h>
class KDialog;
/**
*@author Tim Jansen
*/
@@ -30,22 +34,27 @@
class TrayIcon : public KSystemTray {
Q_OBJECT
public:
TrayIcon();
TrayIcon(KDialog*, Configuration*);
~TrayIcon();
public slots:
void closeConnection();
void openConnection();
private:
KPixmap trayIconOpen;
KPixmap trayIconClosed;
KAction* closeConnectionAction;
KAction* configureAction;
signals:
void connectionClosed();
void showConfigure();
private:
KPixmap trayIconOpen;
KPixmap trayIconClosed;
KDialog* aboutDialog;
KAction* closeConnectionAction;
KAction* configureAction;
KAction* aboutAction;
private slots:
void showAbout();
};
#endif