mirror of
https://github.com/KDE/krfb
synced 2026-07-01 07:31:16 -07:00
almost working
svn path=/trunk/kdenetwork/krfb/; revision=135195
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
SUBDIRS = lib krfb po doc include
|
SUBDIRS = libvncserver krfb po doc
|
||||||
|
|
||||||
EXTRA_DIST = admin AUTHORS COPYING ChangeLog INSTALL README TODO NOTES \
|
EXTRA_DIST = admin AUTHORS COPYING ChangeLog INSTALL README TODO NOTES \
|
||||||
README_KDE3 krfb.lsm
|
README_KDE3 krfb.lsm
|
||||||
|
|||||||
@@ -1,8 +1 @@
|
|||||||
For KDE 3.0, you need to do the following:
|
3.0 support has been removed for this release, but will re-appear soon.
|
||||||
|
|
||||||
* the .ui files must be recompiled, you can enforce this by touching them:
|
|
||||||
touch krfb/*.ui
|
|
||||||
|
|
||||||
* main.cpp and trayicon.cpp include the file kapp.h. It has been renamed to
|
|
||||||
kapplication.h, so you must change the sources accordingly.
|
|
||||||
|
|
||||||
26
ROADMAP
Normal file
26
ROADMAP
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
Version 0.5 (2002/01/02): First release
|
||||||
|
- first release
|
||||||
|
- port x0rfbserver wiith simplified KDE/Qt interface
|
||||||
|
|
||||||
|
|
||||||
|
Version 0.6 (2002/02/??): Improve RFB backend
|
||||||
|
- improve RFB backend
|
||||||
|
- replace x0rfbserver's encoders with those from TightVNCs WinVNC
|
||||||
|
<- port ZLib and Tight encodings from TightVNCs WinVNC
|
||||||
|
<- clip framebuffer updates to requested region
|
||||||
|
<- rewrite Connection to use linked buffers
|
||||||
|
<- knotify
|
||||||
|
<- UI for multiple users (if libvncserver is chosen)
|
||||||
|
|
||||||
|
Version 0.7 (2002/??/??): Better integration with KDE, more end-user friendly
|
||||||
|
- i18n
|
||||||
|
- kded module or some other way to have a small module listening on the Rfb
|
||||||
|
port (like inetd) that then starts KRfb
|
||||||
|
- kcontrol module to configure the kded thing
|
||||||
|
- on startup a dialog appears that allows the user to invite somebody
|
||||||
|
else using email (and later other mechanisms). Dialog can be turned
|
||||||
|
off, of course
|
||||||
|
|
||||||
|
Version 0.8 (2002/??/??):
|
||||||
|
- docs
|
||||||
|
|
||||||
@@ -4,9 +4,15 @@ AM_INIT_AUTOMAKE(krfb,0.6)
|
|||||||
|
|
||||||
AC_CHECK_HEADER(X11/extensions/XTest.h,
|
AC_CHECK_HEADER(X11/extensions/XTest.h,
|
||||||
[],
|
[],
|
||||||
AC_MSG_ERROR([XTest extension header not found]))
|
AC_MSG_ERROR([XTest extension header not found / no xlib headers]))
|
||||||
|
|
||||||
AC_CHECK_HEADER(zlib.h,
|
AC_CHECK_HEADER(zlib.h,
|
||||||
[],
|
[],
|
||||||
AC_MSG_ERROR([ZLib header not found]))
|
AC_MSG_ERROR([ZLib header not found]))
|
||||||
|
|
||||||
|
AC_CHECK_HEADER(jpeglib.h,
|
||||||
|
[],
|
||||||
|
AC_MSG_ERROR([libjpeg header not found]))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
METASOURCES = AUTO
|
METASOURCES = AUTO
|
||||||
|
|
||||||
bin_PROGRAMS = krfb
|
bin_PROGRAMS = krfb
|
||||||
krfb_SOURCES = rfbcontroller.cc configuration.cc trayicon.cpp XUpdateScanner.cc rfbconnection.cc main.cpp configurationdialog.ui newconnectiondialog.ui
|
krfb_SOURCES = rfbcontroller.cc configuration.cc trayicon.cpp XUpdateScanner.cc main.cpp configurationdialog.ui newconnectiondialog.ui
|
||||||
krfb_LDADD = ../lib/librfbserver.a -lz $(LIB_QT) $(LIB_KDECORE) $(LIB_KDEUI) $(LIBSOCKET)
|
krfb_LDADD = ../libvncserver/libvncserver.a -lz -lpthread -ljpeg -lXtst $(LIB_QT) $(LIB_KDECORE) $(LIB_KDEUI) $(LIBSOCKET)
|
||||||
|
|
||||||
EXTRA_DIST = $(krfb_SOURCES) krfb.desktop lo32-app-krfb.png lo16-app-krfb.png rfbcontroller.h rfbconnection.h eyes-closed24.png eyes-open24.png XUpdateScanner.h trayicon.h configuration.h
|
EXTRA_DIST = $(krfb_SOURCES) krfb.desktop lo32-app-krfb.png lo16-app-krfb.png rfbcontroller.h eyes-closed24.png eyes-open24.png XUpdateScanner.h trayicon.h configuration.h
|
||||||
|
|
||||||
install-data-local:
|
install-data-local:
|
||||||
$(mkinstalldirs) $(kde_appsdir)/Applications/
|
$(mkinstalldirs) $(kde_appsdir)/Applications/
|
||||||
@@ -35,10 +35,12 @@ KDE_ICON = krfb
|
|||||||
# kde_wallpaperdir Where general wallpapers should go to.
|
# kde_wallpaperdir Where general wallpapers should go to.
|
||||||
|
|
||||||
# set the include path for X, qt and KDE
|
# set the include path for X, qt and KDE
|
||||||
INCLUDES= $(all_includes) -I../include
|
INCLUDES= $(all_includes) -I../libvncserver
|
||||||
|
|
||||||
# the library search path.
|
# the library search path.
|
||||||
krfb_LDFLAGS = $(all_libraries) $(KDE_RPATH) -lXtst
|
krfb_LDFLAGS = $(all_libraries) $(KDE_RPATH)
|
||||||
|
|
||||||
|
CXXFLAGS = @CXXFLAGS@ -DQT_THREAD_SUPPORT
|
||||||
|
|
||||||
# Uncomment the following two lines if you add a ui.rc file for your application to make use of
|
# Uncomment the following two lines if you add a ui.rc file for your application to make use of
|
||||||
# KDE´s XML GUI builing
|
# KDE´s XML GUI builing
|
||||||
|
|||||||
@@ -31,8 +31,6 @@
|
|||||||
|
|
||||||
#include "XUpdateScanner.h"
|
#include "XUpdateScanner.h"
|
||||||
|
|
||||||
namespace rfb {
|
|
||||||
|
|
||||||
unsigned int scanlines[32] = { 0, 16, 8, 24,
|
unsigned int scanlines[32] = { 0, 16, 8, 24,
|
||||||
4, 20, 12, 28,
|
4, 20, 12, 28,
|
||||||
10, 26, 18, 2,
|
10, 26, 18, 2,
|
||||||
@@ -44,25 +42,29 @@ unsigned int scanlines[32] = { 0, 16, 8, 24,
|
|||||||
|
|
||||||
XUpdateScanner::XUpdateScanner(Display *_dpy,
|
XUpdateScanner::XUpdateScanner(Display *_dpy,
|
||||||
Window _window,
|
Window _window,
|
||||||
Framebuffer *_fb,
|
unsigned char *_fb,
|
||||||
|
int _width,
|
||||||
|
int _height,
|
||||||
|
int _bitsPerPixel,
|
||||||
|
int _bytesPerLine,
|
||||||
unsigned int _tileWidth,
|
unsigned int _tileWidth,
|
||||||
unsigned int _tileHeight,
|
unsigned int _tileHeight) :
|
||||||
unsigned int _blockWidth,
|
|
||||||
unsigned int _blockHeight) :
|
|
||||||
dpy(_dpy),
|
dpy(_dpy),
|
||||||
window(_window),
|
window(_window),
|
||||||
fb(_fb),
|
fb(_fb),
|
||||||
|
width(_width),
|
||||||
|
height(_height),
|
||||||
|
bitsPerPixel(_bitsPerPixel),
|
||||||
|
bytesPerLine(_bytesPerLine),
|
||||||
tileWidth(_tileWidth),
|
tileWidth(_tileWidth),
|
||||||
tileHeight(_tileHeight),
|
tileHeight(_tileHeight),
|
||||||
blockWidth(_blockWidth),
|
|
||||||
blockHeight(_blockHeight),
|
|
||||||
count (0),
|
count (0),
|
||||||
scanline(NULL),
|
scanline(NULL),
|
||||||
tile(NULL)
|
tile(NULL)
|
||||||
{
|
{
|
||||||
tile = XShmCreateImage(dpy,
|
tile = XShmCreateImage(dpy,
|
||||||
DefaultVisual( dpy, 0 ),
|
DefaultVisual( dpy, 0 ),
|
||||||
fb->pixelFormat.bits_per_pixel,
|
bitsPerPixel,
|
||||||
ZPixmap,
|
ZPixmap,
|
||||||
NULL,
|
NULL,
|
||||||
&shminfo_tile,
|
&shminfo_tile,
|
||||||
@@ -78,8 +80,8 @@ XUpdateScanner::XUpdateScanner(Display *_dpy,
|
|||||||
|
|
||||||
XShmAttach(dpy, &shminfo_tile);
|
XShmAttach(dpy, &shminfo_tile);
|
||||||
|
|
||||||
tilesX = (fb->width + tileWidth - 1) / tileWidth;
|
tilesX = (width + tileWidth - 1) / tileWidth;
|
||||||
tilesY = (fb->height + tileHeight - 1) / tileHeight;
|
tilesY = (height + tileHeight - 1) / tileHeight;
|
||||||
tileMap = new bool[tilesX * tilesY];
|
tileMap = new bool[tilesX * tilesY];
|
||||||
|
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
@@ -88,11 +90,11 @@ XUpdateScanner::XUpdateScanner(Display *_dpy,
|
|||||||
|
|
||||||
scanline = XShmCreateImage(dpy,
|
scanline = XShmCreateImage(dpy,
|
||||||
DefaultVisual(dpy, 0),
|
DefaultVisual(dpy, 0),
|
||||||
fb->pixelFormat.bits_per_pixel,
|
bitsPerPixel,
|
||||||
ZPixmap,
|
ZPixmap,
|
||||||
NULL,
|
NULL,
|
||||||
&shminfo_scanline,
|
&shminfo_scanline,
|
||||||
fb->width,
|
width,
|
||||||
1);
|
1);
|
||||||
|
|
||||||
shminfo_scanline.shmid = shmget(IPC_PRIVATE,
|
shminfo_scanline.shmid = shmget(IPC_PRIVATE,
|
||||||
@@ -122,8 +124,8 @@ XUpdateScanner::~XUpdateScanner()
|
|||||||
|
|
||||||
void XUpdateScanner::copyTile(int x, int y)
|
void XUpdateScanner::copyTile(int x, int y)
|
||||||
{
|
{
|
||||||
unsigned int maxWidth = fb->width - x;
|
unsigned int maxWidth = width - x;
|
||||||
unsigned int maxHeight = fb->height - y;
|
unsigned int maxHeight = height - y;
|
||||||
if (maxWidth > tileWidth)
|
if (maxWidth > tileWidth)
|
||||||
maxWidth = tileWidth;
|
maxWidth = tileWidth;
|
||||||
if (maxHeight > tileHeight)
|
if (maxHeight > tileHeight)
|
||||||
@@ -136,13 +138,13 @@ void XUpdateScanner::copyTile(int x, int y)
|
|||||||
AllPlanes, ZPixmap, tile, 0, 0);
|
AllPlanes, ZPixmap, tile, 0, 0);
|
||||||
}
|
}
|
||||||
unsigned int line;
|
unsigned int line;
|
||||||
int pixelsize = fb->pixelFormat.bits_per_pixel >> 3;
|
int pixelsize = bitsPerPixel >> 3;
|
||||||
unsigned char *src = (unsigned char*) tile->data;
|
unsigned char *src = (unsigned char*) tile->data;
|
||||||
unsigned char *dest = fb->data + y * fb->bytesPerLine + x * pixelsize;
|
unsigned char *dest = fb + y * bytesPerLine + x * pixelsize;
|
||||||
for (line = 0; line < maxHeight; line++) {
|
for (line = 0; line < maxHeight; line++) {
|
||||||
memcpy(dest, src, maxWidth * pixelsize );
|
memcpy(dest, src, maxWidth * pixelsize );
|
||||||
src += tile->bytes_per_line;
|
src += tile->bytes_per_line;
|
||||||
dest += fb->bytesPerLine;
|
dest += bytesPerLine;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,60 +161,51 @@ void XUpdateScanner::copyAllTiles()
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void XUpdateScanner::initHint(Hint &hint)
|
|
||||||
{
|
|
||||||
hint.type = hintRefresh;
|
|
||||||
hint.hint.refresh.x = 0;
|
|
||||||
hint.hint.refresh.y = 0;
|
|
||||||
hint.hint.refresh.width = 0;
|
|
||||||
hint.hint.refresh.height = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void XUpdateScanner::createHintFromTile(int x, int y, Hint &hint)
|
void XUpdateScanner::createHintFromTile(int x, int y, Hint &hint)
|
||||||
{
|
{
|
||||||
unsigned int w = fb->width - x;
|
unsigned int w = width - x;
|
||||||
unsigned int h = fb->height - y;
|
unsigned int h = height - y;
|
||||||
if (w > tileWidth)
|
if (w > tileWidth)
|
||||||
w = tileWidth;
|
w = tileWidth;
|
||||||
if (h > tileHeight)
|
if (h > tileHeight)
|
||||||
h = tileHeight;
|
h = tileHeight;
|
||||||
|
|
||||||
hint.hint.refresh.x = x;
|
hint.x = x;
|
||||||
hint.hint.refresh.y = y;
|
hint.y = y;
|
||||||
hint.hint.refresh.width = w;
|
hint.w = w;
|
||||||
hint.hint.refresh.height = h;
|
hint.h = h;
|
||||||
}
|
}
|
||||||
|
|
||||||
void XUpdateScanner::addTileToHint(int x, int y, Hint &hint)
|
void XUpdateScanner::addTileToHint(int x, int y, Hint &hint)
|
||||||
{
|
{
|
||||||
unsigned int w = fb->width - x;
|
unsigned int w = width - x;
|
||||||
unsigned int h = fb->height - y;
|
unsigned int h = height - y;
|
||||||
if (w > tileWidth)
|
if (w > tileWidth)
|
||||||
w = tileWidth;
|
w = tileWidth;
|
||||||
if (h > tileHeight)
|
if (h > tileHeight)
|
||||||
h = tileHeight;
|
h = tileHeight;
|
||||||
|
|
||||||
if (hint.hint.refresh.x > x) {
|
if (hint.x > x) {
|
||||||
hint.hint.refresh.width += hint.hint.refresh.x - x;
|
hint.w += hint.x - x;
|
||||||
hint.hint.refresh.x = x;
|
hint.x = x;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hint.hint.refresh.y > y) {
|
if (hint.y > y) {
|
||||||
hint.hint.refresh.height += hint.hint.refresh.y - y;
|
hint.h += hint.y - y;
|
||||||
hint.hint.refresh.y = y;
|
hint.y = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((hint.hint.refresh.x+hint.hint.refresh.width) < (x+w)) {
|
if ((hint.x+hint.w) < (x+w)) {
|
||||||
hint.hint.refresh.width = (x+w) - hint.hint.refresh.x;
|
hint.w = (x+w) - hint.x;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((hint.hint.refresh.y+hint.hint.refresh.height) < (y+h)) {
|
if ((hint.y+hint.h) < (y+h)) {
|
||||||
hint.hint.refresh.height = (y+h) - hint.hint.refresh.y;
|
hint.h = (y+h) - hint.y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void XUpdateScanner::flushHint(int x, int y, int &x0,
|
void XUpdateScanner::flushHint(int x, int y, int &x0,
|
||||||
Hint &hint, list<Hint> &hintList)
|
Hint &hint, QList<Hint> &hintList)
|
||||||
{
|
{
|
||||||
if (x0 < 0)
|
if (x0 < 0)
|
||||||
return;
|
return;
|
||||||
@@ -234,20 +227,18 @@ void XUpdateScanner::flushHint(int x, int y, int &x0,
|
|||||||
h++;
|
h++;
|
||||||
}
|
}
|
||||||
|
|
||||||
hint.hint.refresh.height = h * tileHeight;
|
hint.h = h * tileHeight;
|
||||||
if ((hint.hint.refresh.y + hint.hint.refresh.height) > fb->height)
|
if ((hint.y + hint.h) > height)
|
||||||
hint.hint.refresh.height = fb->height - hint.hint.refresh.y;
|
h = height - hint.y;
|
||||||
|
|
||||||
x0 = -1;
|
x0 = -1;
|
||||||
|
|
||||||
hintList.push_back(hint);
|
hintList.append(new Hint(hint));
|
||||||
initHint(hint);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void XUpdateScanner::createHints(list<Hint> &hintList)
|
void XUpdateScanner::createHints(QList<Hint> &hintList)
|
||||||
{
|
{
|
||||||
Hint hint;
|
Hint hint;
|
||||||
initHint(hint);
|
|
||||||
int x0 = -1;
|
int x0 = -1;
|
||||||
|
|
||||||
for (int y = 0; y < tilesY; y++) {
|
for (int y = 0; y < tilesY; y++) {
|
||||||
@@ -272,7 +263,7 @@ void XUpdateScanner::createHints(list<Hint> &hintList)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void XUpdateScanner::searchUpdates(list<Hint> &hintList)
|
void XUpdateScanner::searchUpdates(QList<Hint> &hintList)
|
||||||
{
|
{
|
||||||
count++;
|
count++;
|
||||||
count %= 32;
|
count %= 32;
|
||||||
@@ -285,16 +276,16 @@ void XUpdateScanner::searchUpdates(list<Hint> &hintList)
|
|||||||
}
|
}
|
||||||
|
|
||||||
y = scanlines[count];
|
y = scanlines[count];
|
||||||
while (y < fb->height) {
|
while (y < height) {
|
||||||
XShmGetImage(dpy, window, scanline, 0, y, AllPlanes);
|
XShmGetImage(dpy, window, scanline, 0, y, AllPlanes);
|
||||||
x = 0;
|
x = 0;
|
||||||
while (x < fb->width) {
|
while (x < width) {
|
||||||
int pixelsize = fb->pixelFormat.bits_per_pixel >> 3;
|
int pixelsize = bitsPerPixel >> 3;
|
||||||
unsigned char *src = (unsigned char*) scanline->data +
|
unsigned char *src = (unsigned char*) scanline->data +
|
||||||
x * pixelsize;
|
x * pixelsize;
|
||||||
unsigned char *dest = fb->data +
|
unsigned char *dest = fb +
|
||||||
y * fb->bytesPerLine + x * pixelsize;
|
y * bytesPerLine + x * pixelsize;
|
||||||
int w = (x + 32) > fb->width ? (fb->width-x) : 32;
|
int w = (x + 32) > width ? (width-x) : 32;
|
||||||
if (memcmp(dest, src, w * pixelsize))
|
if (memcmp(dest, src, w * pixelsize))
|
||||||
tileMap[(x / tileWidth) +
|
tileMap[(x / tileWidth) +
|
||||||
(y / tileHeight) * tilesX] = true;
|
(y / tileHeight) * tilesX] = true;
|
||||||
@@ -308,6 +299,5 @@ void XUpdateScanner::searchUpdates(list<Hint> &hintList)
|
|||||||
createHints(hintList);
|
createHints(hintList);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace rfb
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -21,41 +21,69 @@
|
|||||||
#ifndef _hexonet_rfb_XUpdateScanner_h_
|
#ifndef _hexonet_rfb_XUpdateScanner_h_
|
||||||
#define _hexonet_rfb_XUpdateScanner_h_
|
#define _hexonet_rfb_XUpdateScanner_h_
|
||||||
|
|
||||||
|
#include <qlist.h>
|
||||||
#include "../include/rfbServer.h"
|
|
||||||
|
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
#include <X11/extensions/XShm.h>
|
#include <X11/extensions/XShm.h>
|
||||||
|
|
||||||
|
|
||||||
namespace rfb {
|
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;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class XUpdateScanner
|
class XUpdateScanner
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
XUpdateScanner( Display *_dpy,
|
XUpdateScanner( Display *_dpy,
|
||||||
Window _window,
|
Window _window,
|
||||||
Framebuffer *_fb,
|
unsigned char *_fb,
|
||||||
|
int _width, int _height,
|
||||||
|
int _bitsPerPixel, int _bytesPerLine,
|
||||||
unsigned int _tileWidth = 32,
|
unsigned int _tileWidth = 32,
|
||||||
unsigned int _tileHeight = 32,
|
unsigned int _tileHeight = 32);
|
||||||
unsigned int _blockWidth = 9,
|
|
||||||
unsigned int _blockHeight = 9);
|
|
||||||
|
|
||||||
~XUpdateScanner();
|
~XUpdateScanner();
|
||||||
|
|
||||||
void copyTile( int x, int y);
|
void copyTile( int x, int y);
|
||||||
void copyAllTiles();
|
void copyAllTiles();
|
||||||
void searchUpdates( list< Hint > &hintList);
|
void searchUpdates( QList<Hint> &hintList);
|
||||||
void initHint(Hint &hint);
|
void flushHint(int x, int y, int &x0, Hint &hint, QList<Hint> &hintList);
|
||||||
void flushHint(int x, int y, int &x0, Hint &hint, list<Hint> &hintList);
|
void createHints(QList<Hint> &hintList);
|
||||||
void createHints(list<Hint> &hintList);
|
|
||||||
void addTileToHint(int x, int y, Hint &hint);
|
void addTileToHint(int x, int y, Hint &hint);
|
||||||
void createHintFromTile(int x, int y, Hint &hint);
|
void createHintFromTile(int x, int y, Hint &hint);
|
||||||
|
|
||||||
Display *dpy;
|
Display *dpy;
|
||||||
Window window;
|
Window window;
|
||||||
Framebuffer *fb;
|
unsigned char *fb;
|
||||||
unsigned int tileWidth, tileHeight, blockWidth, blockHeight;
|
int width, height;
|
||||||
|
int bitsPerPixel, bytesPerLine;
|
||||||
|
unsigned int tileWidth, tileHeight;
|
||||||
unsigned int count;
|
unsigned int count;
|
||||||
|
|
||||||
XImage *scanline;
|
XImage *scanline;
|
||||||
@@ -69,6 +97,4 @@ class XUpdateScanner
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
} // namespace rfb
|
|
||||||
|
|
||||||
#endif // _hexonet_rfb_XUpdateScanner_h_
|
#endif // _hexonet_rfb_XUpdateScanner_h_
|
||||||
|
|||||||
@@ -34,6 +34,8 @@
|
|||||||
|
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
|
#include <X11/extensions/XTest.h>
|
||||||
|
|
||||||
#define VERSION "0.6"
|
#define VERSION "0.6"
|
||||||
|
|
||||||
static const char *description = I18N_NOOP("VNC-compatible server to share "
|
static const char *description = I18N_NOOP("VNC-compatible server to share "
|
||||||
@@ -137,9 +139,6 @@ int main(int argc, char *argv[])
|
|||||||
TrayIcon trayicon(new KAboutApplication(&aboutData), config);
|
TrayIcon trayicon(new KAboutApplication(&aboutData), config);
|
||||||
RFBController controller(config);
|
RFBController controller(config);
|
||||||
|
|
||||||
if (controller.state() == RFB_ERROR)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
QObject::connect(&app, SIGNAL(lastWindowClosed()),
|
QObject::connect(&app, SIGNAL(lastWindowClosed()),
|
||||||
&controller, SLOT(closeSession()));
|
&controller, SLOT(closeSession()));
|
||||||
|
|
||||||
|
|||||||
@@ -1,183 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
rfbconnection.cpp
|
|
||||||
-------------------
|
|
||||||
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. *
|
|
||||||
* *
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
#include "rfbconnection.h"
|
|
||||||
|
|
||||||
#include <kdebug.h>
|
|
||||||
#include <qapplication.h>
|
|
||||||
#include <qtimer.h>
|
|
||||||
#include <X11/Xutil.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
static XTestDisabler disabler;
|
|
||||||
|
|
||||||
RFBConnection::RFBConnection(Display *_dpy,
|
|
||||||
int _fd,
|
|
||||||
const QString &cpassword,
|
|
||||||
bool _allowInput) :
|
|
||||||
Server(),
|
|
||||||
fd(_fd),
|
|
||||||
buttonMask(0),
|
|
||||||
allowInput(_allowInput),
|
|
||||||
dpy(_dpy)
|
|
||||||
{
|
|
||||||
memcpy(password, "\0\0\0\0\0\0\0\0", 8);
|
|
||||||
if (!cpassword.isNull())
|
|
||||||
strncpy(password, cpassword.latin1(),
|
|
||||||
(8 <= cpassword.length()) ? 8 : cpassword.length());
|
|
||||||
|
|
||||||
connection = new BufferedConnection(fd, 32768, 16384);
|
|
||||||
|
|
||||||
XTestGrabControl(dpy, true);
|
|
||||||
disabler.disable = false;
|
|
||||||
|
|
||||||
createFramebuffer();
|
|
||||||
|
|
||||||
sendFirstHandshake(connection);
|
|
||||||
}
|
|
||||||
|
|
||||||
RFBConnection::~RFBConnection() {
|
|
||||||
destroyFramebuffer();
|
|
||||||
delete connection;
|
|
||||||
|
|
||||||
disabler.disable = true;
|
|
||||||
disabler.dpy = dpy;
|
|
||||||
QTimer::singleShot(0, &disabler, SLOT(exec()));
|
|
||||||
}
|
|
||||||
|
|
||||||
void RFBConnection::handleKeyEvent(KeyEvent &keyEvent) {
|
|
||||||
if (!allowInput)
|
|
||||||
return;
|
|
||||||
KeyCode kc = XKeysymToKeycode(dpy, keyEvent.key);
|
|
||||||
if (kc != NoSymbol)
|
|
||||||
XTestFakeKeyEvent(dpy,
|
|
||||||
XKeysymToKeycode( dpy, keyEvent.key ),
|
|
||||||
keyEvent.down_flag,
|
|
||||||
CurrentTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RFBConnection::handlePointerEvent(PointerEvent &pointerEvent) {
|
|
||||||
if (!allowInput)
|
|
||||||
return;
|
|
||||||
XTestFakeMotionEvent(dpy,
|
|
||||||
0,
|
|
||||||
pointerEvent.x_position,
|
|
||||||
pointerEvent.y_position,
|
|
||||||
CurrentTime);
|
|
||||||
int i = 1;
|
|
||||||
while (i <= 5) {
|
|
||||||
if ( (buttonMask & (1 << (i-1))) != (pointerEvent.button_mask & (1 << (i-1))) )
|
|
||||||
XTestFakeButtonEvent( dpy, i,
|
|
||||||
(pointerEvent.button_mask & (1 << (i-1)))? True : False,
|
|
||||||
CurrentTime );
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
buttonMask = pointerEvent.button_mask;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RFBConnection::createFramebuffer()
|
|
||||||
{
|
|
||||||
framebufferImage = XGetImage(dpy,
|
|
||||||
QApplication::desktop()->winId(),
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
QApplication::desktop()->width(),
|
|
||||||
QApplication::desktop()->height(),
|
|
||||||
AllPlanes,
|
|
||||||
ZPixmap);
|
|
||||||
framebuffer = new Framebuffer();
|
|
||||||
framebuffer->width = framebufferImage->width;
|
|
||||||
framebuffer->height = framebufferImage->height;
|
|
||||||
framebuffer->bytesPerLine = framebufferImage->bytes_per_line;
|
|
||||||
framebuffer->data = (unsigned char*) framebufferImage->data;
|
|
||||||
|
|
||||||
framebuffer->pixelFormat.bits_per_pixel =
|
|
||||||
framebufferImage->bits_per_pixel;
|
|
||||||
framebuffer->pixelFormat.depth = framebufferImage->depth;
|
|
||||||
framebuffer->pixelFormat.big_endian_flag =
|
|
||||||
(framebufferImage->bitmap_bit_order == MSBFirst);
|
|
||||||
framebuffer->pixelFormat.true_colour_flag = true;
|
|
||||||
|
|
||||||
if (framebuffer->pixelFormat.bits_per_pixel == 8) {
|
|
||||||
framebuffer->pixelFormat.red_shift = 0;
|
|
||||||
framebuffer->pixelFormat.green_shift = 2;
|
|
||||||
framebuffer->pixelFormat.blue_shift = 5;
|
|
||||||
framebuffer->pixelFormat.red_max = 3;
|
|
||||||
framebuffer->pixelFormat.green_max = 7;
|
|
||||||
framebuffer->pixelFormat.blue_max = 3;
|
|
||||||
} else {
|
|
||||||
framebuffer->pixelFormat.red_shift = 0;
|
|
||||||
if ( framebufferImage->red_mask )
|
|
||||||
while (!(framebufferImage->red_mask & (1 << framebuffer->pixelFormat.red_shift)))
|
|
||||||
framebuffer->pixelFormat.red_shift++;
|
|
||||||
framebuffer->pixelFormat.green_shift = 0;
|
|
||||||
if (framebufferImage->green_mask)
|
|
||||||
while (!(framebufferImage->green_mask & (1 << framebuffer->pixelFormat.green_shift)))
|
|
||||||
framebuffer->pixelFormat.green_shift++;
|
|
||||||
framebuffer->pixelFormat.blue_shift = 0;
|
|
||||||
if (framebufferImage->blue_mask)
|
|
||||||
while (!(framebufferImage->blue_mask & (1 << framebuffer->pixelFormat.blue_shift)))
|
|
||||||
framebuffer->pixelFormat.blue_shift++;
|
|
||||||
framebuffer->pixelFormat.red_max = framebufferImage->red_mask >> framebuffer->pixelFormat.red_shift;
|
|
||||||
framebuffer->pixelFormat.green_max = framebufferImage->green_mask >> framebuffer->pixelFormat.green_shift;
|
|
||||||
framebuffer->pixelFormat.blue_max = framebufferImage->blue_mask >> framebuffer->pixelFormat.blue_shift;
|
|
||||||
}
|
|
||||||
scanner = new XUpdateScanner( dpy, QApplication::desktop()->winId(), framebuffer );
|
|
||||||
}
|
|
||||||
|
|
||||||
void RFBConnection::destroyFramebuffer()
|
|
||||||
{
|
|
||||||
delete scanner;
|
|
||||||
delete framebuffer;
|
|
||||||
XDestroyImage(framebufferImage);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RFBConnection::scanUpdates()
|
|
||||||
{
|
|
||||||
list<Hint> hintList;
|
|
||||||
|
|
||||||
scanner->searchUpdates(hintList);
|
|
||||||
list<Hint>::iterator i;
|
|
||||||
for (i = hintList.begin(); i != hintList.end(); i++)
|
|
||||||
handleHint(*i);
|
|
||||||
};
|
|
||||||
|
|
||||||
void RFBConnection::getServerInitialisation( ServerInitialisation &_serverInit )
|
|
||||||
{
|
|
||||||
Server::getServerInitialisation( _serverInit );
|
|
||||||
_serverInit.name_length = strlen( getenv("HOSTNAME") );
|
|
||||||
_serverInit.name_string = (CARD8 *) malloc( _serverInit.name_length + 1 );
|
|
||||||
strcpy( (char*) _serverInit.name_string, getenv( "HOSTNAME" ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
XTestDisabler::XTestDisabler() :
|
|
||||||
disable(false) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void XTestDisabler::exec() {
|
|
||||||
if (disable)
|
|
||||||
XTestDiscard(dpy);
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "rfbconnection.moc"
|
|
||||||
@@ -1,90 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
rfbconnection.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 RFBCONNECTION_H
|
|
||||||
#define RFBCONNECTION_H
|
|
||||||
|
|
||||||
// QT must be first because of conflicts with X11
|
|
||||||
#include <qobject.h>
|
|
||||||
#include <qstring.h>
|
|
||||||
|
|
||||||
#include "XUpdateScanner.h"
|
|
||||||
|
|
||||||
#include "../include/rfbServer.h"
|
|
||||||
|
|
||||||
#include <X11/Xlib.h>
|
|
||||||
#include <X11/extensions/XTest.h>
|
|
||||||
|
|
||||||
|
|
||||||
using namespace rfb;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is a port from x0rfbserver's BaseServer to KDE. It is called
|
|
||||||
* RFBConnection because the original Server, despite its name, handles only
|
|
||||||
* a single connection after it has been established. This class and its
|
|
||||||
* connections are created and destroyed by RFBController. RFBController is the real
|
|
||||||
* serverk, but I did not want to call it Server and create more confusion.
|
|
||||||
* Unlike the original this one allows only one client, making stuff a little bit
|
|
||||||
* simpler.
|
|
||||||
* @author Tim Jansen
|
|
||||||
*/
|
|
||||||
class RFBConnection : public QObject, public Server {
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
RFBConnection(Display *dpy, int fd,
|
|
||||||
const QString &cpassword,
|
|
||||||
bool allowInput);
|
|
||||||
virtual ~RFBConnection();
|
|
||||||
virtual void handleKeyEvent(KeyEvent &keyEvent);
|
|
||||||
virtual void handlePointerEvent(PointerEvent &pointerEvent);
|
|
||||||
virtual void getServerInitialisation( ServerInitialisation &_serverInitialisation );
|
|
||||||
void scanUpdates();
|
|
||||||
|
|
||||||
private:
|
|
||||||
void createFramebuffer();
|
|
||||||
void destroyFramebuffer();
|
|
||||||
|
|
||||||
int fd;
|
|
||||||
int buttonMask;
|
|
||||||
bool allowInput;
|
|
||||||
|
|
||||||
XUpdateScanner *scanner;
|
|
||||||
|
|
||||||
Display *dpy;
|
|
||||||
XImage *framebufferImage;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Class to calls 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
|
|
||||||
@@ -6,11 +6,6 @@
|
|||||||
email : tim@tjansen.de
|
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 *
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
@@ -26,6 +21,7 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
#include <kapp.h>
|
||||||
#include <kdebug.h>
|
#include <kdebug.h>
|
||||||
#include <kmessagebox.h>
|
#include <kmessagebox.h>
|
||||||
#include <klocale.h>
|
#include <klocale.h>
|
||||||
@@ -37,21 +33,78 @@
|
|||||||
#include <qglobal.h>
|
#include <qglobal.h>
|
||||||
#include <qlabel.h>
|
#include <qlabel.h>
|
||||||
|
|
||||||
|
#include <X11/Xutil.h>
|
||||||
|
#include <X11/extensions/XTest.h>
|
||||||
|
|
||||||
#ifndef ASSERT
|
#ifndef ASSERT
|
||||||
#define ASSERT(x) Q_ASSERT(x)
|
#define ASSERT(x) Q_ASSERT(x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define IDLE_PAUSE (1000/50)
|
||||||
|
|
||||||
|
static XTestDisabler disabler;
|
||||||
|
|
||||||
|
// 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 void keyboardHook(Bool down, KeySym keySym, rfbClientPtr cl)
|
||||||
|
{
|
||||||
|
AppLocker a;
|
||||||
|
self->handleKeyEvent(down?true:false, keySym);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pointerHook(int bm, int x, int y, rfbClientPtr cl)
|
||||||
|
{
|
||||||
|
AppLocker a;
|
||||||
|
self->handlePointerEvent(bm, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum rfbNewClientAction newClientHook(struct _rfbClientRec *cl)
|
||||||
|
{
|
||||||
|
AppLocker a;
|
||||||
|
return self->handleNewClient(cl);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Bool passwordCheck(rfbClientPtr cl,
|
||||||
|
char* encryptedPassword,
|
||||||
|
int len)
|
||||||
|
{
|
||||||
|
AppLocker a;
|
||||||
|
self->handleCheckPassword(encryptedPassword, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void clientGoneHook(rfbClientPtr cl)
|
||||||
|
{
|
||||||
|
AppLocker a;
|
||||||
|
self->handleClientGone();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void ConnectionDialog::closeEvent(QCloseEvent *)
|
void ConnectionDialog::closeEvent(QCloseEvent *)
|
||||||
{
|
{
|
||||||
emit closed();
|
emit closed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
RFBController::RFBController(Configuration *c) :
|
RFBController::RFBController(Configuration *c) :
|
||||||
configuration(c),
|
allowRemoteControl(false),
|
||||||
socket(0),
|
connectionNum(0),
|
||||||
connection(0),
|
configuration(c)
|
||||||
idleUpdateScheduled(false)
|
|
||||||
{
|
{
|
||||||
|
self = this;
|
||||||
connect(dialog.acceptConnectionButton, SIGNAL(clicked()),
|
connect(dialog.acceptConnectionButton, SIGNAL(clicked()),
|
||||||
SLOT(dialogAccepted()));
|
SLOT(dialogAccepted()));
|
||||||
connect(dialog.refuseConnectionButton, SIGNAL(clicked()),
|
connect(dialog.refuseConnectionButton, SIGNAL(clicked()),
|
||||||
@@ -61,178 +114,302 @@ RFBController::RFBController(Configuration *c) :
|
|||||||
startServer();
|
startServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
RFBController::~RFBController() {
|
RFBController::~RFBController()
|
||||||
if (serversocket)
|
{
|
||||||
delete serversocket;
|
stopServer();
|
||||||
if (socket)
|
|
||||||
delete socket;
|
|
||||||
if (connection)
|
|
||||||
delete connection;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RFBController::startServer() {
|
|
||||||
serversocket = new KServerSocket(configuration->port(), false);
|
|
||||||
connect(serversocket, SIGNAL(accepted(KSocket*)), SLOT(accepted(KSocket*)));
|
void RFBController::startServer(bool xtestGrab)
|
||||||
if (!serversocket->bindAndListen()) {
|
{
|
||||||
delete serversocket;
|
framebufferImage = XGetImage(qt_xdisplay(),
|
||||||
serversocket = 0;
|
QApplication::desktop()->winId(),
|
||||||
KMessageBox::error(0,
|
0,
|
||||||
i18n("KRfb Server cannot run, port %1 is already in use. ")
|
0,
|
||||||
.arg(configuration->port()),
|
QApplication::desktop()->width(),
|
||||||
i18n("KRfb Error"));
|
QApplication::desktop()->height(),
|
||||||
|
AllPlanes,
|
||||||
|
ZPixmap);
|
||||||
|
|
||||||
|
int w = framebufferImage->width;
|
||||||
|
int h = framebufferImage->height;
|
||||||
|
int bpp = framebufferImage->depth;
|
||||||
|
char *fb = framebufferImage->data;
|
||||||
|
|
||||||
|
server = rfbGetScreen(0, 0, w, h,
|
||||||
|
(bpp==4) ? 8 : 5,
|
||||||
|
0, bpp);
|
||||||
|
server->frameBuffer = fb;
|
||||||
|
server->rfbPort = configuration->port();
|
||||||
|
//server->udpPort = configuration->port();
|
||||||
|
|
||||||
|
server->kbdAddEvent = keyboardHook;
|
||||||
|
server->ptrAddEvent = pointerHook;
|
||||||
|
server->newClientHook = newClientHook;
|
||||||
|
server->passwordCheck = passwordCheck;
|
||||||
|
|
||||||
|
scanner = new XUpdateScanner(qt_xdisplay(),
|
||||||
|
QApplication::desktop()->winId(),
|
||||||
|
(unsigned char*)fb,
|
||||||
|
w, h, bpp, (bpp/8)*w);
|
||||||
|
|
||||||
|
rfbInitServer(server);
|
||||||
|
state = RFB_WAITING;
|
||||||
|
|
||||||
|
if (xtestGrab) {
|
||||||
|
disabler.disable = false;
|
||||||
|
XTestGrabControl(qt_xdisplay(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rfbRunEventLoop(server, -1, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
RFBState RFBController::state() {
|
void RFBController::stopServer(bool xtestUngrab) {
|
||||||
if (!serversocket)
|
rfbScreenCleanup(server);
|
||||||
return RFB_ERROR;
|
state = RFB_STOPPED;
|
||||||
if (!socket)
|
delete scanner;
|
||||||
return RFB_WAITING;
|
|
||||||
if (!connection)
|
XDestroyImage(framebufferImage);
|
||||||
return RFB_CONNECTING;
|
|
||||||
return RFB_CONNECTED;
|
if (xtestUngrab) {
|
||||||
|
disabler.disable = true;
|
||||||
|
QTimer::singleShot(0, &disabler, SLOT(exec()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RFBController::rebind() {
|
void RFBController::rebind() {
|
||||||
delete serversocket;
|
stopServer(false);
|
||||||
startServer();
|
startServer(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* called when KServerSocket accepted a connection.
|
void RFBController::acceptConnection(bool aRC) {
|
||||||
Refuses the connection if there is already a connection.
|
if (state != RFB_CONNECTING)
|
||||||
*/
|
|
||||||
void RFBController::accepted(KSocket *s) {
|
|
||||||
int sockFd = s->socket();
|
|
||||||
if (sockFd < 0)
|
|
||||||
kdError() << "Got negative socket (error)" << endl;
|
|
||||||
|
|
||||||
if (socket) {
|
|
||||||
kdWarning() << "refuse 2nd connection" << endl;
|
|
||||||
// TODO: send connection failed with reason
|
|
||||||
delete s;
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
int one = 1;
|
allowRemoteControl = aRC;
|
||||||
setsockopt(sockFd, IPPROTO_TCP, TCP_NODELAY,
|
connectionNum++;
|
||||||
(char *)&one, sizeof(one));
|
idleTimer.start(IDLE_PAUSE);
|
||||||
fcntl(sockFd, F_SETFL, O_NONBLOCK);
|
|
||||||
socket = s;
|
|
||||||
|
|
||||||
if (configuration->askOnConnect()) {
|
client->clientGoneHook = clientGoneHook;
|
||||||
QString host, port;
|
rfbStartOnHoldClient(client);
|
||||||
KExtendedSocket::resolve(KExtendedSocket::peerAddress(sockFd),
|
|
||||||
host, port);
|
|
||||||
dialog.ipLabel->setText(host);
|
|
||||||
dialog.allowRemoteControlCB->setChecked(
|
|
||||||
configuration->allowDesktopControl());
|
|
||||||
dialog.setFixedSize(dialog.sizeHint());
|
|
||||||
dialog.show();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
acceptConnection(configuration->allowDesktopControl());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RFBController::acceptConnection(bool allowDesktopControl) {
|
|
||||||
KSocket *s = socket;
|
|
||||||
connect(s, SIGNAL(readEvent(KSocket*)), SLOT(socketReadable()));
|
|
||||||
connect(s, SIGNAL(writeEvent(KSocket*)), SLOT(socketWritable()));
|
|
||||||
connect(s, SIGNAL(closeEvent(KSocket*)), SLOT(closeSession()));
|
|
||||||
s->enableRead(true);
|
|
||||||
s->enableWrite(true);
|
|
||||||
connection = new RFBConnection(qt_xdisplay(), s->socket(),
|
|
||||||
configuration->password(),
|
|
||||||
allowDesktopControl);
|
|
||||||
|
|
||||||
|
state = RFB_CONNECTED;
|
||||||
emit sessionEstablished();
|
emit sessionEstablished();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RFBController::idleSlot() {
|
void RFBController::refuseConnection() {
|
||||||
idleUpdateScheduled = false;
|
if (state != RFB_CONNECTING)
|
||||||
if (connection) {
|
return;
|
||||||
connection->scanUpdates();
|
rfbRefuseOnHoldClient(client);
|
||||||
connection->sendIncrementalFramebufferUpdate();
|
state = RFB_WAITING;
|
||||||
connection->connection->write();
|
|
||||||
checkWriteBuffer();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RFBController::checkWriteBuffer() {
|
void RFBController::connectionClosed()
|
||||||
BufferedConnection *bc = connection->connection;
|
{
|
||||||
bool bufferEmpty = !bc->hasSenderBufferData();
|
idleTimer.stop();
|
||||||
socket->enableWrite(!bufferEmpty);
|
connectionNum--;
|
||||||
if (bufferEmpty && !idleUpdateScheduled && connection) {
|
state = RFB_WAITING;
|
||||||
QTimer::singleShot(0, this, SLOT(idleSlot()));
|
client = 0;
|
||||||
idleUpdateScheduled = true;
|
emit sessionFinished();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RFBController::socketReadable() {
|
void RFBController::closeConnection()
|
||||||
if ((!socket) || (!connection))
|
{
|
||||||
return;
|
rfbCloseClient(client);
|
||||||
|
|
||||||
BufferedConnection *bc = connection->connection;
|
|
||||||
int count = bc->read();
|
|
||||||
if (count < 0) {
|
|
||||||
closeSession();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
while (connection->currentState && bc->hasReceiverBufferData()) {
|
|
||||||
connection->update();
|
|
||||||
checkWriteBuffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!connection->currentState) {
|
|
||||||
closeSession();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RFBController::socketWritable() {
|
void RFBController::idleSlot()
|
||||||
if ((!socket) || (!connection))
|
{
|
||||||
return;
|
rfbUndrawCursor(server);
|
||||||
|
|
||||||
BufferedConnection *bc = connection->connection;
|
QList<Hint> v;
|
||||||
int count = bc->write();
|
v.setAutoDelete(true);
|
||||||
if (count >= 0)
|
scanner->searchUpdates(v);
|
||||||
checkWriteBuffer();
|
|
||||||
else
|
Hint *h;
|
||||||
closeSession();
|
|
||||||
|
for (h = v.first(); h != 0; h = v.next())
|
||||||
|
rfbMarkRectAsModified(server, h->left(),
|
||||||
|
h->top(),
|
||||||
|
h->right(),
|
||||||
|
h->bottom());
|
||||||
|
|
||||||
|
QPoint p = QCursor::pos();
|
||||||
|
defaultPtrAddEvent(0, p.x(),p.y(), client);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RFBController::closeSession() {
|
void RFBController::dialogAccepted()
|
||||||
if (!socket)
|
{
|
||||||
return;
|
|
||||||
if (connection) {
|
|
||||||
delete connection;
|
|
||||||
connection = 0;
|
|
||||||
emit sessionFinished();
|
|
||||||
}
|
|
||||||
closeSocket();
|
|
||||||
}
|
|
||||||
|
|
||||||
void RFBController::dialogAccepted() {
|
|
||||||
if (!socket)
|
|
||||||
return;
|
|
||||||
ASSERT(!connection);
|
|
||||||
|
|
||||||
dialog.hide();
|
dialog.hide();
|
||||||
acceptConnection(dialog.allowRemoteControlCB->isChecked());
|
acceptConnection(dialog.allowRemoteControlCB->isChecked());
|
||||||
}
|
}
|
||||||
|
|
||||||
void RFBController::dialogRefused() {
|
void RFBController::dialogRefused()
|
||||||
if (!socket)
|
{
|
||||||
return;
|
refuseConnection();
|
||||||
ASSERT(!connection);
|
|
||||||
|
|
||||||
closeSocket();
|
|
||||||
dialog.hide();
|
dialog.hide();
|
||||||
emit sessionRefused();
|
emit sessionRefused();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RFBController::closeSocket() {
|
bool RFBController::handleCheckPassword(const char *p, int len)
|
||||||
delete socket;
|
{
|
||||||
socket = 0;
|
return TRUE;
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
enum rfbNewClientAction RFBController::handleNewClient(rfbClientPtr cl)
|
||||||
|
{
|
||||||
|
int socket = cl->sock;
|
||||||
|
|
||||||
|
if ((connectionNum > 0) ||
|
||||||
|
(state != RFB_WAITING))
|
||||||
|
return RFB_CLIENT_REFUSE;
|
||||||
|
|
||||||
|
client = cl;
|
||||||
|
|
||||||
|
state = RFB_CONNECTING;
|
||||||
|
|
||||||
|
if (!configuration->askOnConnect()) {
|
||||||
|
acceptConnection(configuration->allowDesktopControl());
|
||||||
|
return RFB_CLIENT_ACCEPT;
|
||||||
|
}
|
||||||
|
|
||||||
|
dialog.allowRemoteControlCB->setChecked(configuration->allowDesktopControl());
|
||||||
|
// TODO: get & set client host name
|
||||||
|
|
||||||
|
dialog.show();
|
||||||
|
|
||||||
|
return RFB_CLIENT_ON_HOLD;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RFBController::handleClientGone()
|
||||||
|
{
|
||||||
|
connectionClosed();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define LEFTSHIFT 1
|
||||||
|
#define RIGHTSHIFT 2
|
||||||
|
#define ALTGR 4
|
||||||
|
char ModifierState = 0;
|
||||||
|
|
||||||
|
/* this function adjusts the modifiers according to mod (as from modifiers) and ModifierState */
|
||||||
|
|
||||||
|
void RFBController::tweakModifiers(char mod, bool down)
|
||||||
|
{
|
||||||
|
Display *dpy = qt_xdisplay();
|
||||||
|
|
||||||
|
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 RFBController::initKeycodes()
|
||||||
|
{
|
||||||
|
Display *dpy = qt_xdisplay();
|
||||||
|
KeySym key,*keymap;
|
||||||
|
int i,j,minkey,maxkey,syms_per_keycode;
|
||||||
|
|
||||||
|
memset(modifiers,-1,sizeof(modifiers));
|
||||||
|
|
||||||
|
XDisplayKeycodes(dpy,&minkey,&maxkey);
|
||||||
|
keymap=XGetKeyboardMapping(dpy,minkey,(maxkey - minkey + 1),&syms_per_keycode);
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RFBController::handleKeyEvent(bool down, KeySym keySym) {
|
||||||
|
if (!allowRemoteControl)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Display *dpy = qt_xdisplay();
|
||||||
|
|
||||||
|
#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);
|
||||||
|
//tweakModifiers(modifiers[keySym],down);
|
||||||
|
//k = XKeysymToKeycode( dpy,keySym );
|
||||||
|
k = keycodes[keySym];
|
||||||
|
if(k!=NoSymbol)
|
||||||
|
XTestFakeKeyEvent(dpy,k,down,CurrentTime);
|
||||||
|
|
||||||
|
/*XTestFakeKeyEvent(dpy,keycodes[keySym],down,CurrentTime);*/
|
||||||
|
if (down)
|
||||||
|
tweakModifiers(modifiers[keySym],False);
|
||||||
|
} else {
|
||||||
|
KeyCode k = XKeysymToKeycode( dpy,keySym );
|
||||||
|
if(k!=NoSymbol)
|
||||||
|
XTestFakeKeyEvent(dpy,k,down,CurrentTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RFBController::handlePointerEvent(int button_mask, int x, int y) {
|
||||||
|
if (!allowRemoteControl)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Display *dpy = qt_xdisplay();
|
||||||
|
XTestFakeMotionEvent(dpy, 0, 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
XTestDisabler::XTestDisabler() :
|
||||||
|
disable(false) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void XTestDisabler::exec() {
|
||||||
|
if (disable)
|
||||||
|
XTestDiscard(qt_xdisplay());
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "rfbcontroller.moc"
|
#include "rfbcontroller.moc"
|
||||||
|
|||||||
@@ -25,17 +25,21 @@
|
|||||||
|
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
#include "newconnectiondialog.h"
|
#include "newconnectiondialog.h"
|
||||||
|
#include "XUpdateScanner.h"
|
||||||
#include <ksock.h>
|
#include <ksock.h>
|
||||||
#include <qobject.h>
|
#include <qobject.h>
|
||||||
|
#include <qtimer.h>
|
||||||
// rfbconnection must be last because of X11 headers
|
// rfbconnection must be last because of X11 headers
|
||||||
#include "rfbconnection.h"
|
#include "rfb.h"
|
||||||
|
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class QCloseEvent;
|
class QCloseEvent;
|
||||||
|
|
||||||
using namespace rfb;
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
RFB_ERROR,
|
RFB_STOPPED,
|
||||||
RFB_WAITING,
|
RFB_WAITING,
|
||||||
RFB_CONNECTING,
|
RFB_CONNECTING,
|
||||||
RFB_CONNECTED
|
RFB_CONNECTED
|
||||||
@@ -65,11 +69,20 @@ public:
|
|||||||
RFBController(Configuration *c);
|
RFBController(Configuration *c);
|
||||||
virtual ~RFBController();
|
virtual ~RFBController();
|
||||||
|
|
||||||
RFBState state();
|
RFBState state;
|
||||||
|
|
||||||
|
void acceptConnection(bool allowRemoteConnection);
|
||||||
|
void refuseConnection();
|
||||||
|
void connectionClosed();
|
||||||
|
bool handleCheckPassword(const char *p, int len);
|
||||||
|
void handleKeyEvent(bool down, KeySym keySym);
|
||||||
|
void handlePointerEvent(int button_mask, int x, int y);
|
||||||
|
enum rfbNewClientAction handleNewClient(rfbClientPtr cl);
|
||||||
|
void handleClientGone();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void rebind();
|
void rebind();
|
||||||
void closeSession();
|
void closeConnection();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void sessionEstablished();
|
void sessionEstablished();
|
||||||
@@ -77,25 +90,45 @@ signals:
|
|||||||
void sessionRefused();
|
void sessionRefused();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void startServer();
|
void startServer(bool xtestGrab = true);
|
||||||
void checkWriteBuffer();
|
void stopServer(bool xtestUngrab = true);
|
||||||
void acceptConnection(bool ask);
|
void tweakModifiers(char mod, bool down);
|
||||||
void closeSocket();
|
void initKeycodes();
|
||||||
|
|
||||||
|
bool allowRemoteControl;
|
||||||
|
int connectionNum;
|
||||||
|
|
||||||
|
QTimer idleTimer;
|
||||||
Configuration *configuration;
|
Configuration *configuration;
|
||||||
KServerSocket *serversocket;
|
XUpdateScanner *scanner;
|
||||||
KSocket *socket;
|
|
||||||
RFBConnection *connection;
|
|
||||||
ConnectionDialog dialog;
|
ConnectionDialog dialog;
|
||||||
bool idleUpdateScheduled;
|
|
||||||
|
rfbScreenInfoPtr server;
|
||||||
|
rfbClientPtr client;
|
||||||
|
|
||||||
|
XImage *framebufferImage;
|
||||||
|
int buttonMask;
|
||||||
|
char modifiers[0x100];
|
||||||
|
KeyCode keycodes[0x100], leftShiftCode, rightShiftCode, altGrCode;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void idleSlot();
|
void idleSlot();
|
||||||
void accepted(KSocket*);
|
|
||||||
void socketReadable();
|
|
||||||
void socketWritable();
|
|
||||||
void dialogAccepted();
|
void dialogAccepted();
|
||||||
void dialogRefused();
|
void dialogRefused();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user