mirror of
https://invent.kde.org/network/krfb
synced 2024-07-05 09:28:35 +00:00
Sorry, committed my vnc client a little bit too early (and possibly at the wrong location)
svn path=/trunk/kdenetwork/krfb/; revision=156481
This commit is contained in:
parent
d0df828c56
commit
6463941a18
|
@ -1,4 +1,4 @@
|
|||
SUBDIRS = client kinetd libvncserver krfb kcm_krfb
|
||||
SUBDIRS = kinetd libvncserver krfb kcm_krfb
|
||||
|
||||
EXTRA_DIST = AUTHORS COPYING ChangeLog INSTALL README TODO NOTES \
|
||||
ROADMAP DCOP-INTERFACE krfb.lsm
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
KDE_CXXFLAGS = $(USE_THREADS)
|
||||
|
||||
METASOURCES = AUTO
|
||||
|
||||
bin_PROGRAMS = krdc
|
||||
krdc_SOURCES = main.cpp krdc.cpp kvncview.cpp threads.cpp \
|
||||
colour.c cursor.c d3des.c desktop.c rfbproto.c sockets.c vncauth.c \
|
||||
newconnectiondialog.ui passworddialog.ui
|
||||
|
||||
EXTRA_DIST = krdc.h kvncview.cpp vncviewer.h
|
||||
|
||||
krdc_LDADD = $(LIB_KDEUI) -ljpeg
|
||||
krdc_LDFLAGS = $(all_libraries) $(KDE_RPATH)
|
||||
|
||||
lnkdir = $(kde_appsdir)/Internet
|
||||
lnk_DATA = krdc.desktop
|
||||
|
||||
KDE_ICON = AUTO
|
||||
|
||||
INCLUDES= $(all_includes)
|
||||
|
||||
messages: rc.cpp
|
||||
$(XGETTEXT) rc.cpp *.cpp *.cc -o $(podir)/krdc.pot
|
34
client/TODO
34
client/TODO
|
@ -1,34 +0,0 @@
|
|||
+ working viewing prototype
|
||||
+ move logic ->kvncview widget
|
||||
+ basic command line arguments
|
||||
+ expose/redraw events
|
||||
+ make event queues for sending events on demand
|
||||
+ gentle wayto exit krdc worker thread
|
||||
+ get performance comparable to xvncviewer
|
||||
+ make scrollable
|
||||
+ feedback from thread to widget
|
||||
+ mouse input
|
||||
+ keyboard input
|
||||
+ create main window
|
||||
+ add login gui
|
||||
+ replace console password input
|
||||
- advanced command line arguments
|
||||
- better event-based error & disconnection handling
|
||||
- fullscreen
|
||||
- add fullscreen control panel (auto-hide+minimize+disable full)
|
||||
- display connection status on canvas
|
||||
|
||||
-> release
|
||||
|
||||
- mouse wheel
|
||||
- use pixmap only, dont paint directly on screen
|
||||
-> write desktop.c function for 8,16,32 to fill rect
|
||||
-> use CONCAT2E to replace func calls to xlib with desktop.c func
|
||||
-> find out when to copy rect
|
||||
- optional scaling if other desktop is too big
|
||||
- add function to vncviewer code to de-allocate resources
|
||||
- dont quit after failed connect attempt but allow re-try
|
||||
|
||||
- login with user's name+password?
|
||||
- SSL/TLS?
|
||||
|
415
client/colour.c
415
client/colour.c
|
@ -1,415 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 1999 AT&T Laboratories Cambridge. 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* colour.c - functions to deal with colour - i.e. RFB pixel formats, X visuals
|
||||
* and colormaps. Thanks to Grant McDorman for some of the ideas used here.
|
||||
*/
|
||||
|
||||
#include "vncviewer.h"
|
||||
#include <limits.h>
|
||||
|
||||
|
||||
#define INVALID_PIXEL 0xffffffff
|
||||
#define MAX_CMAP_SIZE 256
|
||||
#define BGR233_SIZE 256
|
||||
unsigned long BGR233ToPixel[BGR233_SIZE];
|
||||
|
||||
Colormap cmap;
|
||||
Visual *vis;
|
||||
unsigned int visdepth, visbpp;
|
||||
Bool allocColorFailed = False;
|
||||
|
||||
static int nBGR233ColoursAllocated;
|
||||
|
||||
static int GetBPPForDepth(int depth);
|
||||
static void SetupBGR233Map(void);
|
||||
static void AllocateExactBGR233Colours(void);
|
||||
static Bool AllocateBGR233Colour(int r, int g, int b);
|
||||
|
||||
|
||||
/*
|
||||
* SetVisualAndCmap() deals with the wonderful world of X "visuals" (which are
|
||||
* equivalent to the RFB protocol's "pixel format"). Having decided on the
|
||||
* best visual, it also creates a colormap if necessary, sets the appropriate
|
||||
* resources on the toplevel widget, and sets up the myFormat structure to
|
||||
* describe the pixel format in terms that the RFB server will be able to
|
||||
* understand.
|
||||
*
|
||||
* The algorithm for deciding which visual to use is as follows:
|
||||
*
|
||||
* If forceOwnCmap is true then we try to use a PseudoColor visual - we first
|
||||
* see if there's one of the same depth as the RFB server, followed by an 8-bit
|
||||
* deep one.
|
||||
*
|
||||
* If forceTrueColour is true then we try to use a TrueColor visual - if
|
||||
* requestedDepth is set then it must be of that depth, otherwise any depth
|
||||
* will be used.
|
||||
*
|
||||
* Otherwise, we use the X server's default visual and colormap. If this is
|
||||
* TrueColor then we just ask the RFB server for this format. If the default
|
||||
* isn't TrueColor, or if useBGR233 is true, then we ask the RFB server for
|
||||
* BGR233 pixel format and use a lookup table to translate to the nearest
|
||||
* colours provided by the X server.
|
||||
*/
|
||||
|
||||
void
|
||||
SetVisualAndCmap()
|
||||
{
|
||||
/* just use default visual and colormap */
|
||||
|
||||
vis = DefaultVisual(dpy,DefaultScreen(dpy));
|
||||
visdepth = DefaultDepth(dpy,DefaultScreen(dpy));
|
||||
visbpp = GetBPPForDepth(visdepth);
|
||||
cmap = DefaultColormap(dpy,DefaultScreen(dpy));
|
||||
|
||||
if (!appData.useBGR233 && (vis->class == TrueColor)) {
|
||||
|
||||
myFormat.bitsPerPixel = visbpp;
|
||||
myFormat.depth = visdepth;
|
||||
myFormat.trueColour = 1;
|
||||
myFormat.bigEndian = (ImageByteOrder(dpy) == MSBFirst);
|
||||
myFormat.redShift = ffs(vis->red_mask) - 1;
|
||||
myFormat.greenShift = ffs(vis->green_mask) - 1;
|
||||
myFormat.blueShift = ffs(vis->blue_mask) - 1;
|
||||
myFormat.redMax = vis->red_mask >> myFormat.redShift;
|
||||
myFormat.greenMax = vis->green_mask >> myFormat.greenShift;
|
||||
myFormat.blueMax = vis->blue_mask >> myFormat.blueShift;
|
||||
|
||||
fprintf(stderr,
|
||||
"Using default colormap which is TrueColor. Pixel format:\n");
|
||||
PrintPixelFormat(&myFormat);
|
||||
return;
|
||||
}
|
||||
|
||||
appData.useBGR233 = True;
|
||||
|
||||
myFormat.bitsPerPixel = 8;
|
||||
myFormat.depth = 8;
|
||||
myFormat.trueColour = 1;
|
||||
myFormat.bigEndian = 0;
|
||||
myFormat.redMax = 7;
|
||||
myFormat.greenMax = 7;
|
||||
myFormat.blueMax = 3;
|
||||
myFormat.redShift = 0;
|
||||
myFormat.greenShift = 3;
|
||||
myFormat.blueShift = 6;
|
||||
|
||||
fprintf(stderr,
|
||||
"Using default colormap and translating from BGR233. Pixel format:\n");
|
||||
PrintPixelFormat(&myFormat);
|
||||
|
||||
SetupBGR233Map();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* GetBPPForDepth looks through the "pixmap formats" to find the bits-per-pixel
|
||||
* for the given depth.
|
||||
*/
|
||||
|
||||
static int
|
||||
GetBPPForDepth(int depth)
|
||||
{
|
||||
XPixmapFormatValues *format;
|
||||
int nformats;
|
||||
int i;
|
||||
int bpp;
|
||||
|
||||
format = XListPixmapFormats(dpy, &nformats);
|
||||
|
||||
for (i = 0; i < nformats; i++) {
|
||||
if (format[i].depth == depth)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == nformats) {
|
||||
fprintf(stderr,"no pixmap format for depth %d???\n", depth);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
bpp = format[i].bits_per_pixel;
|
||||
|
||||
XFree(format);
|
||||
|
||||
if (bpp != 1 && bpp != 8 && bpp != 16 && bpp != 32) {
|
||||
fprintf(stderr,"Can't cope with %d bits-per-pixel. Sorry.\n", bpp);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return bpp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* SetupBGR233Map() sets up the BGR233ToPixel array.
|
||||
*
|
||||
* It calls AllocateExactBGR233Colours to allocate some exact BGR233 colours
|
||||
* (limited by space in the colormap and/or by the value of the nColours
|
||||
* resource). If the number allocated is less than BGR233_SIZE then it fills
|
||||
* the rest in using the "nearest" colours available. How this is done depends
|
||||
* on the value of the useSharedColours resource. If it's false, we use only
|
||||
* colours from the exact BGR233 colours we've just allocated. If it's true,
|
||||
* then we also use other clients' "shared" colours available in the colormap.
|
||||
*/
|
||||
|
||||
static void
|
||||
SetupBGR233Map(void)
|
||||
{
|
||||
int r, g, b;
|
||||
long i;
|
||||
unsigned long nearestPixel = 0;
|
||||
int cmapSize;
|
||||
XColor cmapEntry[MAX_CMAP_SIZE];
|
||||
Bool exactBGR233[MAX_CMAP_SIZE];
|
||||
Bool shared[MAX_CMAP_SIZE];
|
||||
Bool usedAsNearest[MAX_CMAP_SIZE];
|
||||
int nSharedUsed = 0;
|
||||
|
||||
if (visdepth > 8) {
|
||||
appData.nColours = 256; /* ignore nColours setting for > 8-bit deep */
|
||||
}
|
||||
|
||||
for (i = 0; i < BGR233_SIZE; i++) {
|
||||
BGR233ToPixel[i] = INVALID_PIXEL;
|
||||
}
|
||||
|
||||
AllocateExactBGR233Colours();
|
||||
|
||||
fprintf(stderr,"Got %d exact BGR233 colours out of %d\n",
|
||||
nBGR233ColoursAllocated, appData.nColours);
|
||||
|
||||
if (nBGR233ColoursAllocated < BGR233_SIZE) {
|
||||
|
||||
if (visdepth > 8) { /* shouldn't get here */
|
||||
fprintf(stderr,"Error: couldn't allocate BGR233 colours even though "
|
||||
"depth is %d\n", visdepth);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
cmapSize = (1 << visdepth);
|
||||
|
||||
for (i = 0; i < cmapSize; i++) {
|
||||
cmapEntry[i].pixel = i;
|
||||
exactBGR233[i] = False;
|
||||
shared[i] = False;
|
||||
usedAsNearest[i] = False;
|
||||
}
|
||||
|
||||
XQueryColors(dpy, cmap, cmapEntry, cmapSize);
|
||||
|
||||
/* mark all our exact BGR233 pixels */
|
||||
|
||||
for (i = 0; i < BGR233_SIZE; i++) {
|
||||
if (BGR233ToPixel[i] != INVALID_PIXEL)
|
||||
exactBGR233[BGR233ToPixel[i]] = True;
|
||||
}
|
||||
|
||||
if (appData.useSharedColours) {
|
||||
|
||||
/* Try to find existing shared colours. This is harder than it sounds
|
||||
because XQueryColors doesn't tell us whether colours are shared,
|
||||
private or unallocated. What we do is go through the colormap and for
|
||||
each pixel try to allocate exactly its RGB values. If this returns a
|
||||
different pixel then it's definitely either a private or unallocated
|
||||
pixel, so no use to us. If it returns us the same pixel again, then
|
||||
it's likely that it's a shared colour - however, it is possible that
|
||||
it was actually an unallocated pixel, which we've now allocated. We
|
||||
minimise this possibility by going through the pixels in reverse order
|
||||
- this helps becuse the X server allocates new pixels from the lowest
|
||||
number up, so it should only be a problem for the lowest unallocated
|
||||
pixel. Got that? */
|
||||
|
||||
for (i = cmapSize-1; i >= 0; i--) {
|
||||
if (!exactBGR233[i] &&
|
||||
XAllocColor(dpy, cmap, &cmapEntry[i])) {
|
||||
|
||||
if (cmapEntry[i].pixel == (unsigned long) i) {
|
||||
|
||||
shared[i] = True; /* probably shared */
|
||||
|
||||
} else {
|
||||
|
||||
/* "i" is either unallocated or private. We have now unnecessarily
|
||||
allocated cmapEntry[i].pixel. Free it. */
|
||||
|
||||
XFreeColors(dpy, cmap, &cmapEntry[i].pixel, 1, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Now fill in the nearest colours */
|
||||
|
||||
for (r = 0; r < 8; r++) {
|
||||
for (g = 0; g < 8; g++) {
|
||||
for (b = 0; b < 4; b++) {
|
||||
if (BGR233ToPixel[(b<<6) | (g<<3) | r] == INVALID_PIXEL) {
|
||||
|
||||
unsigned long minDistance = ULONG_MAX;
|
||||
|
||||
for (i = 0; i < cmapSize; i++) {
|
||||
if (exactBGR233[i] || shared[i]) {
|
||||
unsigned long distance
|
||||
= (abs(cmapEntry[i].red - r * 65535 / 7)
|
||||
+ abs(cmapEntry[i].green - g * 65535 / 7)
|
||||
+ abs(cmapEntry[i].blue - b * 65535 / 3));
|
||||
|
||||
if (distance < minDistance) {
|
||||
minDistance = distance;
|
||||
nearestPixel = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BGR233ToPixel[(b<<6) | (g<<3) | r] = nearestPixel;
|
||||
if (shared[nearestPixel] && !usedAsNearest[nearestPixel])
|
||||
nSharedUsed++;
|
||||
usedAsNearest[nearestPixel] = True;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Tidy up shared colours which we allocated but aren't going to use */
|
||||
|
||||
for (i = 0; i < cmapSize; i++) {
|
||||
if (shared[i] && !usedAsNearest[i]) {
|
||||
XFreeColors(dpy, cmap, &i, 1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr,"Using %d existing shared colours\n", nSharedUsed);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* AllocateExactBGR233Colours() attempts to allocate each of the colours in the
|
||||
* BGR233 colour cube, stopping when an allocation fails. The order it does
|
||||
* this in is such that we should get a fairly well spread subset of the cube,
|
||||
* however many allocations are made. There's probably a neater algorithm for
|
||||
* doing this, but it's not obvious to me anyway. The way this algorithm works
|
||||
* is:
|
||||
*
|
||||
* At each stage, we introduce a new value for one of the primaries, and
|
||||
* allocate all the colours with the new value of that primary and all previous
|
||||
* values of the other two primaries. We start with r=0 as the "new" value
|
||||
* for r, and g=0, b=0 as the "previous" values of g and b. So we get:
|
||||
*
|
||||
* New primary value Previous values of other primaries Colours allocated
|
||||
* ----------------- ---------------------------------- -----------------
|
||||
* r=0 g=0 b=0 r0 g0 b0
|
||||
* g=7 r=0 b=0 r0 g7 b0
|
||||
* b=3 r=0 g=0,7 r0 g0 b3
|
||||
* r0 g7 b3
|
||||
* r=7 g=0,7 b=0,3 r7 g0 b0
|
||||
* r7 g0 b3
|
||||
* r7 g7 b0
|
||||
* r7 g7 b3
|
||||
* g=3 r=0,7 b=0,3 r0 g3 b0
|
||||
* r0 g3 b3
|
||||
* r7 g3 b0
|
||||
* r7 g3 b3
|
||||
* ....etc.
|
||||
* */
|
||||
|
||||
static void
|
||||
AllocateExactBGR233Colours(void)
|
||||
{
|
||||
int rv[] = {0,7,3,5,1,6,2,4};
|
||||
int gv[] = {0,7,3,5,1,6,2,4};
|
||||
int bv[] = {0,3,1,2};
|
||||
int rn = 0;
|
||||
int gn = 1;
|
||||
int bn = 1;
|
||||
int ri, gi, bi;
|
||||
|
||||
nBGR233ColoursAllocated = 0;
|
||||
|
||||
while (1) {
|
||||
if (rn == 8)
|
||||
break;
|
||||
|
||||
ri = rn;
|
||||
for (gi = 0; gi < gn; gi++) {
|
||||
for (bi = 0; bi < bn; bi++) {
|
||||
if (!AllocateBGR233Colour(rv[ri], gv[gi], bv[bi]))
|
||||
return;
|
||||
}
|
||||
}
|
||||
rn++;
|
||||
|
||||
if (gn == 8)
|
||||
break;
|
||||
|
||||
gi = gn;
|
||||
for (ri = 0; ri < rn; ri++) {
|
||||
for (bi = 0; bi < bn; bi++) {
|
||||
if (!AllocateBGR233Colour(rv[ri], gv[gi], bv[bi]))
|
||||
return;
|
||||
}
|
||||
}
|
||||
gn++;
|
||||
|
||||
if (bn < 4) {
|
||||
|
||||
bi = bn;
|
||||
for (ri = 0; ri < rn; ri++) {
|
||||
for (gi = 0; gi < gn; gi++) {
|
||||
if (!AllocateBGR233Colour(rv[ri], gv[gi], bv[bi]))
|
||||
return;
|
||||
}
|
||||
}
|
||||
bn++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* AllocateBGR233Colour() attempts to allocate the given BGR233 colour as a
|
||||
* shared colormap entry, storing its pixel value in the BGR233ToPixel array.
|
||||
* r is from 0 to 7, g from 0 to 7 and b from 0 to 3. It fails either when the
|
||||
* allocation fails or when we would exceed the number of colours specified in
|
||||
* the nColours resource.
|
||||
*/
|
||||
|
||||
static Bool
|
||||
AllocateBGR233Colour(int r, int g, int b)
|
||||
{
|
||||
XColor c;
|
||||
|
||||
if (nBGR233ColoursAllocated >= appData.nColours)
|
||||
return False;
|
||||
|
||||
c.red = r * 65535 / 7;
|
||||
c.green = g * 65535 / 7;
|
||||
c.blue = b * 65535 / 3;
|
||||
|
||||
if (!XAllocColor(dpy, cmap, &c))
|
||||
return False;
|
||||
|
||||
BGR233ToPixel[(b<<6) | (g<<3) | r] = c.pixel;
|
||||
|
||||
nBGR233ColoursAllocated++;
|
||||
|
||||
return True;
|
||||
}
|
|
@ -1,83 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 1999 AT&T Laboratories Cambridge. 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* corre.c - handle CoRRE encoding.
|
||||
*
|
||||
* This file shouldn't be compiled directly. It is included multiple times by
|
||||
* rfbproto.c, each time with a different definition of the macro BPP. For
|
||||
* each value of BPP, this file defines a function which handles a CoRRE
|
||||
* encoded rectangle with BPP bits per pixel.
|
||||
*/
|
||||
|
||||
#define HandleCoRREBPP CONCAT2E(HandleCoRRE,BPP)
|
||||
#define CARDBPP CONCAT2E(CARD,BPP)
|
||||
|
||||
static Bool
|
||||
HandleCoRREBPP (int rx, int ry, int rw, int rh)
|
||||
{
|
||||
rfbRREHeader hdr;
|
||||
XGCValues gcv;
|
||||
int i;
|
||||
CARDBPP pix;
|
||||
CARD8 *ptr;
|
||||
int x, y, w, h;
|
||||
|
||||
if (!ReadFromRFBServer((char *)&hdr, sz_rfbRREHeader))
|
||||
return False;
|
||||
|
||||
hdr.nSubrects = Swap32IfLE(hdr.nSubrects);
|
||||
|
||||
if (!ReadFromRFBServer((char *)&pix, sizeof(pix)))
|
||||
return False;
|
||||
|
||||
#if (BPP == 8)
|
||||
gcv.foreground = (appData.useBGR233 ? BGR233ToPixel[pix] : pix);
|
||||
#else
|
||||
gcv.foreground = pix;
|
||||
#endif
|
||||
|
||||
XChangeGC(dpy, gc, GCForeground, &gcv);
|
||||
XFillRectangle(dpy, desktopWin, gc, rx, ry, rw, rh);
|
||||
|
||||
if (!ReadFromRFBServer(buffer, hdr.nSubrects * (4 + (BPP / 8))))
|
||||
return False;
|
||||
|
||||
ptr = (CARD8 *)buffer;
|
||||
|
||||
for (i = 0; i < hdr.nSubrects; i++) {
|
||||
pix = *(CARDBPP *)ptr;
|
||||
ptr += BPP/8;
|
||||
x = *ptr++;
|
||||
y = *ptr++;
|
||||
w = *ptr++;
|
||||
h = *ptr++;
|
||||
|
||||
#if (BPP == 8)
|
||||
gcv.foreground = (appData.useBGR233 ? BGR233ToPixel[pix] : pix);
|
||||
#else
|
||||
gcv.foreground = pix;
|
||||
#endif
|
||||
|
||||
XChangeGC(dpy, gc, GCForeground, &gcv);
|
||||
XFillRectangle(dpy, desktopWin, gc, rx + x, ry + y, w, h);
|
||||
}
|
||||
|
||||
return True;
|
||||
}
|
431
client/cursor.c
431
client/cursor.c
|
@ -1,431 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2001 Const Kaplinsky. 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* cursor.c - code to support cursor shape updates (XCursor, RichCursor).
|
||||
*/
|
||||
|
||||
#include <vncviewer.h>
|
||||
|
||||
|
||||
#define OPER_SAVE 0
|
||||
#define OPER_RESTORE 1
|
||||
|
||||
|
||||
/* Copied from Xvnc/lib/font/util/utilbitmap.c */
|
||||
static unsigned char _reverse_byte[0x100] = {
|
||||
0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
|
||||
0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
|
||||
0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
|
||||
0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
|
||||
0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
|
||||
0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
|
||||
0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
|
||||
0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
|
||||
0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
|
||||
0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
|
||||
0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
|
||||
0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
|
||||
0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
|
||||
0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
|
||||
0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
|
||||
0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
|
||||
0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
|
||||
0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
|
||||
0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
|
||||
0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
|
||||
0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
|
||||
0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
|
||||
0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
|
||||
0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
|
||||
0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
|
||||
0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
|
||||
0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
|
||||
0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
|
||||
0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
|
||||
0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
|
||||
0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
|
||||
0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
|
||||
};
|
||||
|
||||
/* Data kept for HandleXCursor() function. */
|
||||
static Bool prevXCursorSet = False;
|
||||
static Cursor prevXCursor;
|
||||
|
||||
/* Data kept for RichCursor encoding support. */
|
||||
static Bool prevRichCursorSet = False;
|
||||
static Pixmap rcSavedArea;
|
||||
static CARD8 *rcSource, *rcMask;
|
||||
static int rcHotX, rcHotY, rcWidth, rcHeight;
|
||||
static int rcCursorX = 0, rcCursorY = 0;
|
||||
static int rcLockX, rcLockY, rcLockWidth, rcLockHeight;
|
||||
static Bool rcCursorHidden, rcLockSet;
|
||||
|
||||
static Bool SoftCursorInLockedArea(void);
|
||||
static void SoftCursorCopyArea(int oper);
|
||||
static void SoftCursorDraw(void);
|
||||
static void FreeCursors(Bool setDotCursor);
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
* HandleXCursor(). XCursor encoding support code is concentrated in
|
||||
* this function. XCursor shape updates are translated directly into X
|
||||
* cursors and saved in the prevXCursor variable.
|
||||
********************************************************************/
|
||||
|
||||
Bool HandleXCursor(int xhot, int yhot, int width, int height)
|
||||
{
|
||||
rfbXCursorColors colors;
|
||||
size_t bytesPerRow, bytesData;
|
||||
char *buf = NULL;
|
||||
XColor bg, fg;
|
||||
Drawable dr;
|
||||
unsigned int wret = 0, hret = 0;
|
||||
Pixmap source, mask;
|
||||
Cursor cursor;
|
||||
int i;
|
||||
|
||||
bytesPerRow = (width + 7) / 8;
|
||||
bytesData = bytesPerRow * height;
|
||||
dr = DefaultRootWindow(dpy);
|
||||
|
||||
if (width * height) {
|
||||
if (!ReadFromRFBServer((char *)&colors, sz_rfbXCursorColors))
|
||||
return False;
|
||||
|
||||
buf = malloc(bytesData * 2);
|
||||
if (buf == NULL)
|
||||
return False;
|
||||
|
||||
if (!ReadFromRFBServer(buf, bytesData * 2)) {
|
||||
free(buf);
|
||||
return False;
|
||||
}
|
||||
|
||||
lockQt();
|
||||
XQueryBestCursor(dpy, dr, width, height, &wret, &hret);
|
||||
unlockQt();
|
||||
}
|
||||
|
||||
if (width * height == 0 || wret < width || hret < height) {
|
||||
/* Free resources, restore dot cursor. */
|
||||
if (buf != NULL)
|
||||
free(buf);
|
||||
FreeCursors(True);
|
||||
return True;
|
||||
}
|
||||
|
||||
bg.red = (unsigned short)colors.backRed << 8 | colors.backRed;
|
||||
bg.green = (unsigned short)colors.backGreen << 8 | colors.backGreen;
|
||||
bg.blue = (unsigned short)colors.backBlue << 8 | colors.backBlue;
|
||||
fg.red = (unsigned short)colors.foreRed << 8 | colors.foreRed;
|
||||
fg.green = (unsigned short)colors.foreGreen << 8 | colors.foreGreen;
|
||||
fg.blue = (unsigned short)colors.foreBlue << 8 | colors.foreBlue;
|
||||
|
||||
for (i = 0; i < bytesData * 2; i++)
|
||||
buf[i] = (char)_reverse_byte[(int)buf[i] & 0xFF];
|
||||
|
||||
lockQt();
|
||||
source = XCreateBitmapFromData(dpy, dr, buf, width, height);
|
||||
mask = XCreateBitmapFromData(dpy, dr, &buf[bytesData], width, height);
|
||||
cursor = XCreatePixmapCursor(dpy, source, mask, &fg, &bg, xhot, yhot);
|
||||
XFreePixmap(dpy, source);
|
||||
XFreePixmap(dpy, mask);
|
||||
free(buf);
|
||||
|
||||
XDefineCursor(dpy, desktopWin, cursor);
|
||||
FreeCursors(False);
|
||||
prevXCursor = cursor;
|
||||
prevXCursorSet = True;
|
||||
unlockQt();
|
||||
return True;
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
* HandleRichCursor(). RichCursor shape updates support. This
|
||||
* variation of cursor shape updates cannot be supported directly via
|
||||
* Xlib cursors so we have to emulate cursor operating on the frame
|
||||
* buffer (that is why we call it "software cursor").
|
||||
********************************************************************/
|
||||
|
||||
Bool HandleRichCursor(int xhot, int yhot, int width, int height)
|
||||
{
|
||||
size_t bytesPerRow, bytesMaskData;
|
||||
Drawable dr;
|
||||
char *buf;
|
||||
CARD8 *ptr;
|
||||
int x, y, b;
|
||||
|
||||
bytesPerRow = (width + 7) / 8;
|
||||
bytesMaskData = bytesPerRow * height;
|
||||
dr = DefaultRootWindow(dpy);
|
||||
|
||||
FreeCursors(True);
|
||||
|
||||
if (width * height == 0)
|
||||
return True;
|
||||
|
||||
/* Read cursor pixel data. */
|
||||
|
||||
rcSource = malloc(width * height * (myFormat.bitsPerPixel / 8));
|
||||
if (rcSource == NULL)
|
||||
return False;
|
||||
|
||||
if (!ReadFromRFBServer((char *)rcSource,
|
||||
width * height * (myFormat.bitsPerPixel / 8))) {
|
||||
free(rcSource);
|
||||
return False;
|
||||
}
|
||||
|
||||
/* Read and decode mask data. */
|
||||
|
||||
buf = malloc(bytesMaskData);
|
||||
if (buf == NULL) {
|
||||
free(rcSource);
|
||||
return False;
|
||||
}
|
||||
|
||||
if (!ReadFromRFBServer(buf, bytesMaskData)) {
|
||||
free(rcSource);
|
||||
free(buf);
|
||||
return False;
|
||||
}
|
||||
|
||||
rcMask = malloc(width * height);
|
||||
if (rcMask == NULL) {
|
||||
free(rcSource);
|
||||
free(buf);
|
||||
return False;
|
||||
}
|
||||
|
||||
ptr = rcMask;
|
||||
for (y = 0; y < height; y++) {
|
||||
for (x = 0; x < width / 8; x++) {
|
||||
for (b = 7; b >= 0; b--) {
|
||||
*ptr++ = buf[y * bytesPerRow + x] >> b & 1;
|
||||
}
|
||||
}
|
||||
for (b = 7; b > 7 - width % 8; b--) {
|
||||
*ptr++ = buf[y * bytesPerRow + x] >> b & 1;
|
||||
}
|
||||
}
|
||||
|
||||
free(buf);
|
||||
|
||||
/* Set remaining data associated with cursor. */
|
||||
|
||||
dr = DefaultRootWindow(dpy);
|
||||
lockQt();
|
||||
rcSavedArea = XCreatePixmap(dpy, dr, width, height, visdepth);
|
||||
unlockQt();
|
||||
rcHotX = xhot;
|
||||
rcHotY = yhot;
|
||||
rcWidth = width;
|
||||
rcHeight = height;
|
||||
|
||||
SoftCursorCopyArea(OPER_SAVE);
|
||||
SoftCursorDraw();
|
||||
rcCursorHidden = False;
|
||||
rcLockSet = False;
|
||||
|
||||
prevRichCursorSet = True;
|
||||
return True;
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
* SoftCursorLockArea(). This function should be used to prevent
|
||||
* collisions between simultaneous framebuffer update operations and
|
||||
* cursor drawing operations caused by movements of pointing device.
|
||||
* The parameters denote a rectangle where mouse cursor should not be
|
||||
* drawn. Every next call to this function expands locked area so
|
||||
* previous locks remain active.
|
||||
********************************************************************/
|
||||
|
||||
void SoftCursorLockArea(int x, int y, int w, int h)
|
||||
{
|
||||
int newX, newY;
|
||||
|
||||
if (!prevRichCursorSet)
|
||||
return;
|
||||
|
||||
if (!rcLockSet) {
|
||||
rcLockX = x;
|
||||
rcLockY = y;
|
||||
rcLockWidth = w;
|
||||
rcLockHeight = h;
|
||||
rcLockSet = True;
|
||||
} else {
|
||||
newX = (x < rcLockX) ? x : rcLockX;
|
||||
newY = (y < rcLockY) ? y : rcLockY;
|
||||
rcLockWidth = (x + w > rcLockX + rcLockWidth) ?
|
||||
(x + w - newX) : (rcLockX + rcLockWidth - newX);
|
||||
rcLockHeight = (y + h > rcLockY + rcLockHeight) ?
|
||||
(y + h - newY) : (rcLockY + rcLockHeight - newY);
|
||||
rcLockX = newX;
|
||||
rcLockY = newY;
|
||||
}
|
||||
|
||||
if (!rcCursorHidden && SoftCursorInLockedArea()) {
|
||||
SoftCursorCopyArea(OPER_RESTORE);
|
||||
rcCursorHidden = True;
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* SoftCursorUnlockScreen(). This function discards all locks
|
||||
* performed since previous SoftCursorUnlockScreen() call.
|
||||
********************************************************************/
|
||||
|
||||
void SoftCursorUnlockScreen(void)
|
||||
{
|
||||
if (!prevRichCursorSet)
|
||||
return;
|
||||
|
||||
if (rcCursorHidden) {
|
||||
SoftCursorCopyArea(OPER_SAVE);
|
||||
SoftCursorDraw();
|
||||
rcCursorHidden = False;
|
||||
}
|
||||
rcLockSet = False;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* SoftCursorMove(). Moves soft cursor in particular location. This
|
||||
* function respects locking of screen areas so when the cursor is
|
||||
* moved in the locked area, it becomes invisible until
|
||||
* SoftCursorUnlock() functions is called.
|
||||
********************************************************************/
|
||||
|
||||
void SoftCursorMove(int x, int y)
|
||||
{
|
||||
if (prevRichCursorSet && !rcCursorHidden) {
|
||||
SoftCursorCopyArea(OPER_RESTORE);
|
||||
rcCursorHidden = True;
|
||||
}
|
||||
|
||||
rcCursorX = x;
|
||||
rcCursorY = y;
|
||||
|
||||
if (prevRichCursorSet && !(rcLockSet && SoftCursorInLockedArea())) {
|
||||
SoftCursorCopyArea(OPER_SAVE);
|
||||
SoftCursorDraw();
|
||||
rcCursorHidden = False;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
* Internal (static) low-level functions.
|
||||
********************************************************************/
|
||||
|
||||
static Bool SoftCursorInLockedArea(void)
|
||||
{
|
||||
return (rcLockX < rcCursorX - rcHotX + rcWidth &&
|
||||
rcLockY < rcCursorY - rcHotY + rcHeight &&
|
||||
rcLockX + rcLockWidth > rcCursorX - rcHotX &&
|
||||
rcLockY + rcLockHeight > rcCursorY - rcHotY);
|
||||
}
|
||||
|
||||
static void SoftCursorCopyArea(int oper)
|
||||
{
|
||||
int x, y, w, h;
|
||||
|
||||
x = rcCursorX - rcHotX;
|
||||
y = rcCursorY - rcHotY;
|
||||
if (x >= si.framebufferWidth || y >= si.framebufferHeight)
|
||||
return;
|
||||
|
||||
w = rcWidth;
|
||||
h = rcHeight;
|
||||
if (x < 0) {
|
||||
w += x;
|
||||
x = 0;
|
||||
} else if (x + w > si.framebufferWidth) {
|
||||
w = si.framebufferWidth - x;
|
||||
}
|
||||
if (y < 0) {
|
||||
h += y;
|
||||
y = 0;
|
||||
} else if (y + h > si.framebufferHeight) {
|
||||
h = si.framebufferHeight - y;
|
||||
}
|
||||
|
||||
lockQt();
|
||||
if (oper == OPER_SAVE) {
|
||||
/* Save screen area in memory. */
|
||||
ShmSync();
|
||||
XCopyArea(dpy, desktopWin, rcSavedArea, gc, x, y, w, h, 0, 0);
|
||||
} else {
|
||||
/* Restore screen area. */
|
||||
XCopyArea(dpy, rcSavedArea, desktopWin, gc, 0, 0, w, h, x, y);
|
||||
}
|
||||
unlockQt();
|
||||
}
|
||||
|
||||
static void SoftCursorDraw(void)
|
||||
{
|
||||
int x, y, x0, y0;
|
||||
int offset, bytesPerPixel;
|
||||
char *pos;
|
||||
|
||||
bytesPerPixel = myFormat.bitsPerPixel / 8;
|
||||
|
||||
/* FIXME: Speed optimization is possible. */
|
||||
for (y = 0; y < rcHeight; y++) {
|
||||
y0 = rcCursorY - rcHotY + y;
|
||||
if (y0 >= 0 && y0 < si.framebufferHeight) {
|
||||
for (x = 0; x < rcWidth; x++) {
|
||||
x0 = rcCursorX - rcHotX + x;
|
||||
if (x0 >= 0 && x0 < si.framebufferWidth) {
|
||||
offset = y * rcWidth + x;
|
||||
if (rcMask[offset]) {
|
||||
pos = (char *)&rcSource[offset * bytesPerPixel];
|
||||
CopyDataToScreen(pos, x0, y0, 1, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void FreeCursors(Bool setDotCursor)
|
||||
{
|
||||
lockQt();
|
||||
if (setDotCursor)
|
||||
XDefineCursor(dpy, desktopWin, dotCursor);
|
||||
|
||||
if (prevXCursorSet) {
|
||||
XFreeCursor(dpy, prevXCursor);
|
||||
prevXCursorSet = False;
|
||||
}
|
||||
unlockQt();
|
||||
|
||||
if (prevRichCursorSet) {
|
||||
SoftCursorCopyArea(OPER_RESTORE);
|
||||
lockQt();
|
||||
XFreePixmap(dpy, rcSavedArea);
|
||||
free(rcSource);
|
||||
free(rcMask);
|
||||
prevRichCursorSet = False;
|
||||
unlockQt();
|
||||
}
|
||||
}
|
||||
|
440
client/d3des.c
440
client/d3des.c
|
@ -1,440 +0,0 @@
|
|||
/*
|
||||
* This is D3DES (V5.09) by Richard Outerbridge with the double and
|
||||
* triple-length support removed for use in VNC. Also the bytebit[] array
|
||||
* has been reversed so that the most significant bit in each byte of the
|
||||
* key is ignored, not the least significant.
|
||||
*
|
||||
* These changes are:
|
||||
* Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* D3DES (V5.09) -
|
||||
*
|
||||
* A portable, public domain, version of the Data Encryption Standard.
|
||||
*
|
||||
* Written with Symantec's THINK (Lightspeed) C by Richard Outerbridge.
|
||||
* Thanks to: Dan Hoey for his excellent Initial and Inverse permutation
|
||||
* code; Jim Gillogly & Phil Karn for the DES key schedule code; Dennis
|
||||
* Ferguson, Eric Young and Dana How for comparing notes; and Ray Lau,
|
||||
* for humouring me on.
|
||||
*
|
||||
* Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge.
|
||||
* (GEnie : OUTER; CIS : [71755,204]) Graven Imagery, 1992.
|
||||
*/
|
||||
|
||||
#include "d3des.h"
|
||||
|
||||
static void scrunch(unsigned char *, unsigned long *);
|
||||
static void unscrun(unsigned long *, unsigned char *);
|
||||
static void desfunc(unsigned long *, unsigned long *);
|
||||
static void cookey(unsigned long *);
|
||||
|
||||
static unsigned long KnL[32] = { 0L };
|
||||
static unsigned long KnR[32] = { 0L };
|
||||
static unsigned long Kn3[32] = { 0L };
|
||||
static unsigned char Df_Key[24] = {
|
||||
0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,
|
||||
0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10,
|
||||
0x89,0xab,0xcd,0xef,0x01,0x23,0x45,0x67 };
|
||||
|
||||
static unsigned short bytebit[8] = {
|
||||
01, 02, 04, 010, 020, 040, 0100, 0200 };
|
||||
|
||||
static unsigned long bigbyte[24] = {
|
||||
0x800000L, 0x400000L, 0x200000L, 0x100000L,
|
||||
0x80000L, 0x40000L, 0x20000L, 0x10000L,
|
||||
0x8000L, 0x4000L, 0x2000L, 0x1000L,
|
||||
0x800L, 0x400L, 0x200L, 0x100L,
|
||||
0x80L, 0x40L, 0x20L, 0x10L,
|
||||
0x8L, 0x4L, 0x2L, 0x1L };
|
||||
|
||||
/* Use the key schedule specified in the Standard (ANSI X3.92-1981). */
|
||||
|
||||
static unsigned char pc1[56] = {
|
||||
56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17,
|
||||
9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35,
|
||||
62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21,
|
||||
13, 5, 60, 52, 44, 36, 28, 20, 12, 4, 27, 19, 11, 3 };
|
||||
|
||||
static unsigned char totrot[16] = {
|
||||
1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28 };
|
||||
|
||||
static unsigned char pc2[48] = {
|
||||
13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, 9,
|
||||
22, 18, 11, 3, 25, 7, 15, 6, 26, 19, 12, 1,
|
||||
40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47,
|
||||
43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31 };
|
||||
|
||||
void deskey(key, edf) /* Thanks to James Gillogly & Phil Karn! */
|
||||
unsigned char *key;
|
||||
int edf;
|
||||
{
|
||||
register int i, j, l, m, n;
|
||||
unsigned char pc1m[56], pcr[56];
|
||||
unsigned long kn[32];
|
||||
|
||||
for ( j = 0; j < 56; j++ ) {
|
||||
l = pc1[j];
|
||||
m = l & 07;
|
||||
pc1m[j] = (key[l >> 3] & bytebit[m]) ? 1 : 0;
|
||||
}
|
||||
for( i = 0; i < 16; i++ ) {
|
||||
if( edf == DE1 ) m = (15 - i) << 1;
|
||||
else m = i << 1;
|
||||
n = m + 1;
|
||||
kn[m] = kn[n] = 0L;
|
||||
for( j = 0; j < 28; j++ ) {
|
||||
l = j + totrot[i];
|
||||
if( l < 28 ) pcr[j] = pc1m[l];
|
||||
else pcr[j] = pc1m[l - 28];
|
||||
}
|
||||
for( j = 28; j < 56; j++ ) {
|
||||
l = j + totrot[i];
|
||||
if( l < 56 ) pcr[j] = pc1m[l];
|
||||
else pcr[j] = pc1m[l - 28];
|
||||
}
|
||||
for( j = 0; j < 24; j++ ) {
|
||||
if( pcr[pc2[j]] ) kn[m] |= bigbyte[j];
|
||||
if( pcr[pc2[j+24]] ) kn[n] |= bigbyte[j];
|
||||
}
|
||||
}
|
||||
cookey(kn);
|
||||
return;
|
||||
}
|
||||
|
||||
static void cookey(raw1)
|
||||
register unsigned long *raw1;
|
||||
{
|
||||
register unsigned long *cook, *raw0;
|
||||
unsigned long dough[32];
|
||||
register int i;
|
||||
|
||||
cook = dough;
|
||||
for( i = 0; i < 16; i++, raw1++ ) {
|
||||
raw0 = raw1++;
|
||||
*cook = (*raw0 & 0x00fc0000L) << 6;
|
||||
*cook |= (*raw0 & 0x00000fc0L) << 10;
|
||||
*cook |= (*raw1 & 0x00fc0000L) >> 10;
|
||||
*cook++ |= (*raw1 & 0x00000fc0L) >> 6;
|
||||
*cook = (*raw0 & 0x0003f000L) << 12;
|
||||
*cook |= (*raw0 & 0x0000003fL) << 16;
|
||||
*cook |= (*raw1 & 0x0003f000L) >> 4;
|
||||
*cook++ |= (*raw1 & 0x0000003fL);
|
||||
}
|
||||
usekey(dough);
|
||||
return;
|
||||
}
|
||||
|
||||
void cpkey(into)
|
||||
register unsigned long *into;
|
||||
{
|
||||
register unsigned long *from, *endp;
|
||||
|
||||
from = KnL, endp = &KnL[32];
|
||||
while( from < endp ) *into++ = *from++;
|
||||
return;
|
||||
}
|
||||
|
||||
void usekey(from)
|
||||
register unsigned long *from;
|
||||
{
|
||||
register unsigned long *to, *endp;
|
||||
|
||||
to = KnL, endp = &KnL[32];
|
||||
while( to < endp ) *to++ = *from++;
|
||||
return;
|
||||
}
|
||||
|
||||
void des(inblock, outblock)
|
||||
unsigned char *inblock, *outblock;
|
||||
{
|
||||
unsigned long work[2];
|
||||
|
||||
scrunch(inblock, work);
|
||||
desfunc(work, KnL);
|
||||
unscrun(work, outblock);
|
||||
return;
|
||||
}
|
||||
|
||||
static void scrunch(outof, into)
|
||||
register unsigned char *outof;
|
||||
register unsigned long *into;
|
||||
{
|
||||
*into = (*outof++ & 0xffL) << 24;
|
||||
*into |= (*outof++ & 0xffL) << 16;
|
||||
*into |= (*outof++ & 0xffL) << 8;
|
||||
*into++ |= (*outof++ & 0xffL);
|
||||
*into = (*outof++ & 0xffL) << 24;
|
||||
*into |= (*outof++ & 0xffL) << 16;
|
||||
*into |= (*outof++ & 0xffL) << 8;
|
||||
*into |= (*outof & 0xffL);
|
||||
return;
|
||||
}
|
||||
|
||||
static void unscrun(outof, into)
|
||||
register unsigned long *outof;
|
||||
register unsigned char *into;
|
||||
{
|
||||
*into++ = (*outof >> 24) & 0xffL;
|
||||
*into++ = (*outof >> 16) & 0xffL;
|
||||
*into++ = (*outof >> 8) & 0xffL;
|
||||
*into++ = *outof++ & 0xffL;
|
||||
*into++ = (*outof >> 24) & 0xffL;
|
||||
*into++ = (*outof >> 16) & 0xffL;
|
||||
*into++ = (*outof >> 8) & 0xffL;
|
||||
*into = *outof & 0xffL;
|
||||
return;
|
||||
}
|
||||
|
||||
static unsigned long SP1[64] = {
|
||||
0x01010400L, 0x00000000L, 0x00010000L, 0x01010404L,
|
||||
0x01010004L, 0x00010404L, 0x00000004L, 0x00010000L,
|
||||
0x00000400L, 0x01010400L, 0x01010404L, 0x00000400L,
|
||||
0x01000404L, 0x01010004L, 0x01000000L, 0x00000004L,
|
||||
0x00000404L, 0x01000400L, 0x01000400L, 0x00010400L,
|
||||
0x00010400L, 0x01010000L, 0x01010000L, 0x01000404L,
|
||||
0x00010004L, 0x01000004L, 0x01000004L, 0x00010004L,
|
||||
0x00000000L, 0x00000404L, 0x00010404L, 0x01000000L,
|
||||
0x00010000L, 0x01010404L, 0x00000004L, 0x01010000L,
|
||||
0x01010400L, 0x01000000L, 0x01000000L, 0x00000400L,
|
||||
0x01010004L, 0x00010000L, 0x00010400L, 0x01000004L,
|
||||
0x00000400L, 0x00000004L, 0x01000404L, 0x00010404L,
|
||||
0x01010404L, 0x00010004L, 0x01010000L, 0x01000404L,
|
||||
0x01000004L, 0x00000404L, 0x00010404L, 0x01010400L,
|
||||
0x00000404L, 0x01000400L, 0x01000400L, 0x00000000L,
|
||||
0x00010004L, 0x00010400L, 0x00000000L, 0x01010004L };
|
||||
|
||||
static unsigned long SP2[64] = {
|
||||
0x80108020L, 0x80008000L, 0x00008000L, 0x00108020L,
|
||||
0x00100000L, 0x00000020L, 0x80100020L, 0x80008020L,
|
||||
0x80000020L, 0x80108020L, 0x80108000L, 0x80000000L,
|
||||
0x80008000L, 0x00100000L, 0x00000020L, 0x80100020L,
|
||||
0x00108000L, 0x00100020L, 0x80008020L, 0x00000000L,
|
||||
0x80000000L, 0x00008000L, 0x00108020L, 0x80100000L,
|
||||
0x00100020L, 0x80000020L, 0x00000000L, 0x00108000L,
|
||||
0x00008020L, 0x80108000L, 0x80100000L, 0x00008020L,
|
||||
0x00000000L, 0x00108020L, 0x80100020L, 0x00100000L,
|
||||
0x80008020L, 0x80100000L, 0x80108000L, 0x00008000L,
|
||||
0x80100000L, 0x80008000L, 0x00000020L, 0x80108020L,
|
||||
0x00108020L, 0x00000020L, 0x00008000L, 0x80000000L,
|
||||
0x00008020L, 0x80108000L, 0x00100000L, 0x80000020L,
|
||||
0x00100020L, 0x80008020L, 0x80000020L, 0x00100020L,
|
||||
0x00108000L, 0x00000000L, 0x80008000L, 0x00008020L,
|
||||
0x80000000L, 0x80100020L, 0x80108020L, 0x00108000L };
|
||||
|
||||
static unsigned long SP3[64] = {
|
||||
0x00000208L, 0x08020200L, 0x00000000L, 0x08020008L,
|
||||
0x08000200L, 0x00000000L, 0x00020208L, 0x08000200L,
|
||||
0x00020008L, 0x08000008L, 0x08000008L, 0x00020000L,
|
||||
0x08020208L, 0x00020008L, 0x08020000L, 0x00000208L,
|
||||
0x08000000L, 0x00000008L, 0x08020200L, 0x00000200L,
|
||||
0x00020200L, 0x08020000L, 0x08020008L, 0x00020208L,
|
||||
0x08000208L, 0x00020200L, 0x00020000L, 0x08000208L,
|
||||
0x00000008L, 0x08020208L, 0x00000200L, 0x08000000L,
|
||||
0x08020200L, 0x08000000L, 0x00020008L, 0x00000208L,
|
||||
0x00020000L, 0x08020200L, 0x08000200L, 0x00000000L,
|
||||
0x00000200L, 0x00020008L, 0x08020208L, 0x08000200L,
|
||||
0x08000008L, 0x00000200L, 0x00000000L, 0x08020008L,
|
||||
0x08000208L, 0x00020000L, 0x08000000L, 0x08020208L,
|
||||
0x00000008L, 0x00020208L, 0x00020200L, 0x08000008L,
|
||||
0x08020000L, 0x08000208L, 0x00000208L, 0x08020000L,
|
||||
0x00020208L, 0x00000008L, 0x08020008L, 0x00020200L };
|
||||
|
||||
static unsigned long SP4[64] = {
|
||||
0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L,
|
||||
0x00802080L, 0x00800081L, 0x00800001L, 0x00002001L,
|
||||
0x00000000L, 0x00802000L, 0x00802000L, 0x00802081L,
|
||||
0x00000081L, 0x00000000L, 0x00800080L, 0x00800001L,
|
||||
0x00000001L, 0x00002000L, 0x00800000L, 0x00802001L,
|
||||
0x00000080L, 0x00800000L, 0x00002001L, 0x00002080L,
|
||||
0x00800081L, 0x00000001L, 0x00002080L, 0x00800080L,
|
||||
0x00002000L, 0x00802080L, 0x00802081L, 0x00000081L,
|
||||
0x00800080L, 0x00800001L, 0x00802000L, 0x00802081L,
|
||||
0x00000081L, 0x00000000L, 0x00000000L, 0x00802000L,
|
||||
0x00002080L, 0x00800080L, 0x00800081L, 0x00000001L,
|
||||
0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L,
|
||||
0x00802081L, 0x00000081L, 0x00000001L, 0x00002000L,
|
||||
0x00800001L, 0x00002001L, 0x00802080L, 0x00800081L,
|
||||
0x00002001L, 0x00002080L, 0x00800000L, 0x00802001L,
|
||||
0x00000080L, 0x00800000L, 0x00002000L, 0x00802080L };
|
||||
|
||||
static unsigned long SP5[64] = {
|
||||
0x00000100L, 0x02080100L, 0x02080000L, 0x42000100L,
|
||||
0x00080000L, 0x00000100L, 0x40000000L, 0x02080000L,
|
||||
0x40080100L, 0x00080000L, 0x02000100L, 0x40080100L,
|
||||
0x42000100L, 0x42080000L, 0x00080100L, 0x40000000L,
|
||||
0x02000000L, 0x40080000L, 0x40080000L, 0x00000000L,
|
||||
0x40000100L, 0x42080100L, 0x42080100L, 0x02000100L,
|
||||
0x42080000L, 0x40000100L, 0x00000000L, 0x42000000L,
|
||||
0x02080100L, 0x02000000L, 0x42000000L, 0x00080100L,
|
||||
0x00080000L, 0x42000100L, 0x00000100L, 0x02000000L,
|
||||
0x40000000L, 0x02080000L, 0x42000100L, 0x40080100L,
|
||||
0x02000100L, 0x40000000L, 0x42080000L, 0x02080100L,
|
||||
0x40080100L, 0x00000100L, 0x02000000L, 0x42080000L,
|
||||
0x42080100L, 0x00080100L, 0x42000000L, 0x42080100L,
|
||||
0x02080000L, 0x00000000L, 0x40080000L, 0x42000000L,
|
||||
0x00080100L, 0x02000100L, 0x40000100L, 0x00080000L,
|
||||
0x00000000L, 0x40080000L, 0x02080100L, 0x40000100L };
|
||||
|
||||
static unsigned long SP6[64] = {
|
||||
0x20000010L, 0x20400000L, 0x00004000L, 0x20404010L,
|
||||
0x20400000L, 0x00000010L, 0x20404010L, 0x00400000L,
|
||||
0x20004000L, 0x00404010L, 0x00400000L, 0x20000010L,
|
||||
0x00400010L, 0x20004000L, 0x20000000L, 0x00004010L,
|
||||
0x00000000L, 0x00400010L, 0x20004010L, 0x00004000L,
|
||||
0x00404000L, 0x20004010L, 0x00000010L, 0x20400010L,
|
||||
0x20400010L, 0x00000000L, 0x00404010L, 0x20404000L,
|
||||
0x00004010L, 0x00404000L, 0x20404000L, 0x20000000L,
|
||||
0x20004000L, 0x00000010L, 0x20400010L, 0x00404000L,
|
||||
0x20404010L, 0x00400000L, 0x00004010L, 0x20000010L,
|
||||
0x00400000L, 0x20004000L, 0x20000000L, 0x00004010L,
|
||||
0x20000010L, 0x20404010L, 0x00404000L, 0x20400000L,
|
||||
0x00404010L, 0x20404000L, 0x00000000L, 0x20400010L,
|
||||
0x00000010L, 0x00004000L, 0x20400000L, 0x00404010L,
|
||||
0x00004000L, 0x00400010L, 0x20004010L, 0x00000000L,
|
||||
0x20404000L, 0x20000000L, 0x00400010L, 0x20004010L };
|
||||
|
||||
static unsigned long SP7[64] = {
|
||||
0x00200000L, 0x04200002L, 0x04000802L, 0x00000000L,
|
||||
0x00000800L, 0x04000802L, 0x00200802L, 0x04200800L,
|
||||
0x04200802L, 0x00200000L, 0x00000000L, 0x04000002L,
|
||||
0x00000002L, 0x04000000L, 0x04200002L, 0x00000802L,
|
||||
0x04000800L, 0x00200802L, 0x00200002L, 0x04000800L,
|
||||
0x04000002L, 0x04200000L, 0x04200800L, 0x00200002L,
|
||||
0x04200000L, 0x00000800L, 0x00000802L, 0x04200802L,
|
||||
0x00200800L, 0x00000002L, 0x04000000L, 0x00200800L,
|
||||
0x04000000L, 0x00200800L, 0x00200000L, 0x04000802L,
|
||||
0x04000802L, 0x04200002L, 0x04200002L, 0x00000002L,
|
||||
0x00200002L, 0x04000000L, 0x04000800L, 0x00200000L,
|
||||
0x04200800L, 0x00000802L, 0x00200802L, 0x04200800L,
|
||||
0x00000802L, 0x04000002L, 0x04200802L, 0x04200000L,
|
||||
0x00200800L, 0x00000000L, 0x00000002L, 0x04200802L,
|
||||
0x00000000L, 0x00200802L, 0x04200000L, 0x00000800L,
|
||||
0x04000002L, 0x04000800L, 0x00000800L, 0x00200002L };
|
||||
|
||||
static unsigned long SP8[64] = {
|
||||
0x10001040L, 0x00001000L, 0x00040000L, 0x10041040L,
|
||||
0x10000000L, 0x10001040L, 0x00000040L, 0x10000000L,
|
||||
0x00040040L, 0x10040000L, 0x10041040L, 0x00041000L,
|
||||
0x10041000L, 0x00041040L, 0x00001000L, 0x00000040L,
|
||||
0x10040000L, 0x10000040L, 0x10001000L, 0x00001040L,
|
||||
0x00041000L, 0x00040040L, 0x10040040L, 0x10041000L,
|
||||
0x00001040L, 0x00000000L, 0x00000000L, 0x10040040L,
|
||||
0x10000040L, 0x10001000L, 0x00041040L, 0x00040000L,
|
||||
0x00041040L, 0x00040000L, 0x10041000L, 0x00001000L,
|
||||
0x00000040L, 0x10040040L, 0x00001000L, 0x00041040L,
|
||||
0x10001000L, 0x00000040L, 0x10000040L, 0x10040000L,
|
||||
0x10040040L, 0x10000000L, 0x00040000L, 0x10001040L,
|
||||
0x00000000L, 0x10041040L, 0x00040040L, 0x10000040L,
|
||||
0x10040000L, 0x10001000L, 0x10001040L, 0x00000000L,
|
||||
0x10041040L, 0x00041000L, 0x00041000L, 0x00001040L,
|
||||
0x00001040L, 0x00040040L, 0x10000000L, 0x10041000L };
|
||||
|
||||
static void desfunc(block, keys)
|
||||
register unsigned long *block, *keys;
|
||||
{
|
||||
register unsigned long fval, work, right, leftt;
|
||||
register int round;
|
||||
|
||||
leftt = block[0];
|
||||
right = block[1];
|
||||
work = ((leftt >> 4) ^ right) & 0x0f0f0f0fL;
|
||||
right ^= work;
|
||||
leftt ^= (work << 4);
|
||||
work = ((leftt >> 16) ^ right) & 0x0000ffffL;
|
||||
right ^= work;
|
||||
leftt ^= (work << 16);
|
||||
work = ((right >> 2) ^ leftt) & 0x33333333L;
|
||||
leftt ^= work;
|
||||
right ^= (work << 2);
|
||||
work = ((right >> 8) ^ leftt) & 0x00ff00ffL;
|
||||
leftt ^= work;
|
||||
right ^= (work << 8);
|
||||
right = ((right << 1) | ((right >> 31) & 1L)) & 0xffffffffL;
|
||||
work = (leftt ^ right) & 0xaaaaaaaaL;
|
||||
leftt ^= work;
|
||||
right ^= work;
|
||||
leftt = ((leftt << 1) | ((leftt >> 31) & 1L)) & 0xffffffffL;
|
||||
|
||||
for( round = 0; round < 8; round++ ) {
|
||||
work = (right << 28) | (right >> 4);
|
||||
work ^= *keys++;
|
||||
fval = SP7[ work & 0x3fL];
|
||||
fval |= SP5[(work >> 8) & 0x3fL];
|
||||
fval |= SP3[(work >> 16) & 0x3fL];
|
||||
fval |= SP1[(work >> 24) & 0x3fL];
|
||||
work = right ^ *keys++;
|
||||
fval |= SP8[ work & 0x3fL];
|
||||
fval |= SP6[(work >> 8) & 0x3fL];
|
||||
fval |= SP4[(work >> 16) & 0x3fL];
|
||||
fval |= SP2[(work >> 24) & 0x3fL];
|
||||
leftt ^= fval;
|
||||
work = (leftt << 28) | (leftt >> 4);
|
||||
work ^= *keys++;
|
||||
fval = SP7[ work & 0x3fL];
|
||||
fval |= SP5[(work >> 8) & 0x3fL];
|
||||
fval |= SP3[(work >> 16) & 0x3fL];
|
||||
fval |= SP1[(work >> 24) & 0x3fL];
|
||||
work = leftt ^ *keys++;
|
||||
fval |= SP8[ work & 0x3fL];
|
||||
fval |= SP6[(work >> 8) & 0x3fL];
|
||||
fval |= SP4[(work >> 16) & 0x3fL];
|
||||
fval |= SP2[(work >> 24) & 0x3fL];
|
||||
right ^= fval;
|
||||
}
|
||||
|
||||
right = (right << 31) | (right >> 1);
|
||||
work = (leftt ^ right) & 0xaaaaaaaaL;
|
||||
leftt ^= work;
|
||||
right ^= work;
|
||||
leftt = (leftt << 31) | (leftt >> 1);
|
||||
work = ((leftt >> 8) ^ right) & 0x00ff00ffL;
|
||||
right ^= work;
|
||||
leftt ^= (work << 8);
|
||||
work = ((leftt >> 2) ^ right) & 0x33333333L;
|
||||
right ^= work;
|
||||
leftt ^= (work << 2);
|
||||
work = ((right >> 16) ^ leftt) & 0x0000ffffL;
|
||||
leftt ^= work;
|
||||
right ^= (work << 16);
|
||||
work = ((right >> 4) ^ leftt) & 0x0f0f0f0fL;
|
||||
leftt ^= work;
|
||||
right ^= (work << 4);
|
||||
*block++ = right;
|
||||
*block = leftt;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Validation sets:
|
||||
*
|
||||
* Single-length key, single-length plaintext -
|
||||
* Key : 0123 4567 89ab cdef
|
||||
* Plain : 0123 4567 89ab cde7
|
||||
* Cipher : c957 4425 6a5e d31d
|
||||
*
|
||||
* Double-length key, single-length plaintext -
|
||||
* Key : 0123 4567 89ab cdef fedc ba98 7654 3210
|
||||
* Plain : 0123 4567 89ab cde7
|
||||
* Cipher : 7f1d 0a77 826b 8aff
|
||||
*
|
||||
* Double-length key, double-length plaintext -
|
||||
* Key : 0123 4567 89ab cdef fedc ba98 7654 3210
|
||||
* Plain : 0123 4567 89ab cdef 0123 4567 89ab cdff
|
||||
* Cipher : 27a0 8440 406a df60 278f 47cf 42d6 15d7
|
||||
*
|
||||
* Triple-length key, single-length plaintext -
|
||||
* Key : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567
|
||||
* Plain : 0123 4567 89ab cde7
|
||||
* Cipher : de0b 7c06 ae5e 0ed5
|
||||
*
|
||||
* Triple-length key, double-length plaintext -
|
||||
* Key : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567
|
||||
* Plain : 0123 4567 89ab cdef 0123 4567 89ab cdff
|
||||
* Cipher : ad0d 1b30 ac17 cf07 0ed1 1c63 81e4 4de5
|
||||
*
|
||||
* d3des V5.0a rwo 9208.07 18:44 Graven Imagery
|
||||
**********************************************************************/
|
|
@ -1,51 +0,0 @@
|
|||
/*
|
||||
* This is D3DES (V5.09) by Richard Outerbridge with the double and
|
||||
* triple-length support removed for use in VNC.
|
||||
*
|
||||
* These changes are:
|
||||
* Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* d3des.h -
|
||||
*
|
||||
* Headers and defines for d3des.c
|
||||
* Graven Imagery, 1992.
|
||||
*
|
||||
* Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge
|
||||
* (GEnie : OUTER; CIS : [71755,204])
|
||||
*/
|
||||
|
||||
#define EN0 0 /* MODE == encrypt */
|
||||
#define DE1 1 /* MODE == decrypt */
|
||||
|
||||
extern void deskey(unsigned char *, int);
|
||||
/* hexkey[8] MODE
|
||||
* Sets the internal key register according to the hexadecimal
|
||||
* key contained in the 8 bytes of hexkey, according to the DES,
|
||||
* for encryption or decryption according to MODE.
|
||||
*/
|
||||
|
||||
extern void usekey(unsigned long *);
|
||||
/* cookedkey[32]
|
||||
* Loads the internal key register with the data in cookedkey.
|
||||
*/
|
||||
|
||||
extern void cpkey(unsigned long *);
|
||||
/* cookedkey[32]
|
||||
* Copies the contents of the internal key register into the storage
|
||||
* located at &cookedkey[0].
|
||||
*/
|
||||
|
||||
extern void des(unsigned char *, unsigned char *);
|
||||
/* from[8] to[8]
|
||||
* Encrypts/Decrypts (according to the key currently loaded in the
|
||||
* internal key register) one block of eight bytes at address 'from'
|
||||
* into the block at address 'to'. They can be the same.
|
||||
*/
|
||||
|
||||
/* d3des.h V5.09 rwo 9208.04 15:06 Graven Imagery
|
||||
********************************************************************/
|
494
client/desktop.c
494
client/desktop.c
|
@ -1,494 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 1999 AT&T Laboratories Cambridge. 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*
|
||||
* 03-05-2002 tim@tjansen.de: removed stuff for krdc, merged with shm.c
|
||||
* and misc.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* desktop.c - functions to deal with "desktop" window.
|
||||
*/
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
#include <X11/extensions/XShm.h>
|
||||
#include "vncviewer.h"
|
||||
|
||||
static XShmSegmentInfo shminfo;
|
||||
|
||||
static Bool caughtShmError = False;
|
||||
static Bool needShmCleanup = False;
|
||||
|
||||
GC gc;
|
||||
GC srcGC, dstGC; /* used for debugging copyrect */
|
||||
Window desktopWin;
|
||||
Cursor dotCursor;
|
||||
Dimension dpyWidth, dpyHeight;
|
||||
|
||||
static XImage *image = NULL;
|
||||
|
||||
Bool useShm = True;
|
||||
|
||||
static Cursor CreateDotCursor(void);
|
||||
static void CopyBGR233ToScreen(CARD8 *buf, int x, int y, int width,int height);
|
||||
|
||||
|
||||
void
|
||||
DesktopInit(Window win)
|
||||
{
|
||||
XGCValues gcv;
|
||||
XSetWindowAttributes attr;
|
||||
|
||||
/* image = CreateShmImage();*/
|
||||
|
||||
if (!image) {
|
||||
useShm = False;
|
||||
image = XCreateImage(dpy, vis, visdepth, ZPixmap, 0, NULL,
|
||||
si.framebufferWidth, si.framebufferHeight,
|
||||
BitmapPad(dpy), 0);
|
||||
|
||||
image->data = malloc(image->bytes_per_line * image->height);
|
||||
if (!image->data) {
|
||||
fprintf(stderr,"malloc failed\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
desktopWin = win;
|
||||
|
||||
gc = XCreateGC(dpy,desktopWin,0,NULL);
|
||||
|
||||
gcv.function = GXxor;
|
||||
gcv.foreground = 0x0f0f0f0f;
|
||||
srcGC = XCreateGC(dpy,desktopWin,GCFunction|GCForeground,&gcv);
|
||||
gcv.foreground = 0xf0f0f0f0;
|
||||
dstGC = XCreateGC(dpy,desktopWin,GCFunction|GCForeground,&gcv);
|
||||
|
||||
dotCursor = CreateDotCursor();
|
||||
attr.cursor = dotCursor;
|
||||
|
||||
XChangeWindowAttributes(dpy, desktopWin, CWBackingStore|CWCursor, &attr);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* HandleBasicDesktopEvent - deal with expose and leave events.
|
||||
*/
|
||||
/*
|
||||
static void
|
||||
HandleBasicDesktopEvent(Widget w, XtPointer ptr, XEvent *ev, Boolean *cont)
|
||||
{
|
||||
int i;
|
||||
|
||||
switch (ev->type) {
|
||||
|
||||
case Expose:
|
||||
case GraphicsExpose:
|
||||
/// sometimes due to scrollbars being added/removed we get an expose outside
|
||||
// the actual desktop area. Make sure we don't pass it on to the RFB
|
||||
// server.
|
||||
|
||||
if (ev->xexpose.x + ev->xexpose.width > si.framebufferWidth) {
|
||||
ev->xexpose.width = si.framebufferWidth - ev->xexpose.x;
|
||||
if (ev->xexpose.width <= 0) break;
|
||||
}
|
||||
|
||||
if (ev->xexpose.y + ev->xexpose.height > si.framebufferHeight) {
|
||||
ev->xexpose.height = si.framebufferHeight - ev->xexpose.y;
|
||||
if (ev->xexpose.height <= 0) break;
|
||||
}
|
||||
|
||||
SendFramebufferUpdateRequest(ev->xexpose.x, ev->xexpose.y,
|
||||
ev->xexpose.width, ev->xexpose.height, False);
|
||||
break;
|
||||
|
||||
case LeaveNotify:
|
||||
for (i = 0; i < 256; i++) {
|
||||
if (modifierPressed[i]) {
|
||||
SendKeyEvent(XKeycodeToKeysym(dpy, i, 0), False);
|
||||
modifierPressed[i] = False;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
* SendRFBEvent is an action which sends an RFB event. It can be used in two
|
||||
* ways. Without any parameters it simply sends an RFB event corresponding to
|
||||
* the X event which caused it to be called. With parameters, it generates a
|
||||
* "fake" RFB event based on those parameters. The first parameter is the
|
||||
* event type, either "ptr", "keydown", "keyup" or "key" (down&up). For a
|
||||
* "key" event the second parameter is simply a keysym string as understood by
|
||||
* XStringToKeysym(). For a "ptr" event, the following three parameters are
|
||||
* just X, Y and the button mask (0 for all up, 1 for button1 down, 2 for
|
||||
* button2 down, 3 for both, etc).
|
||||
*/
|
||||
/*
|
||||
void
|
||||
SendRFBEvent(XEvent *ev, String *params, Cardinal *num_params)
|
||||
{
|
||||
KeySym ks;
|
||||
char keyname[256];
|
||||
int buttonMask, x, y;
|
||||
|
||||
if (appData.fullScreen && ev->type == MotionNotify) {
|
||||
if (BumpScroll(ev))
|
||||
return;
|
||||
}
|
||||
|
||||
if (appData.viewOnly) return;
|
||||
|
||||
if (*num_params != 0) {
|
||||
if (strncasecmp(params[0],"key",3) == 0) {
|
||||
if (*num_params != 2) {
|
||||
fprintf(stderr,
|
||||
"Invalid params: SendRFBEvent(key|keydown|keyup,<keysym>)\n");
|
||||
return;
|
||||
}
|
||||
ks = XStringToKeysym(params[1]);
|
||||
if (ks == NoSymbol) {
|
||||
fprintf(stderr,"Invalid keysym '%s' passed to SendRFBEvent\n",
|
||||
params[1]);
|
||||
return;
|
||||
}
|
||||
if (strcasecmp(params[0],"keydown") == 0) {
|
||||
SendKeyEvent(ks, 1);
|
||||
} else if (strcasecmp(params[0],"keyup") == 0) {
|
||||
SendKeyEvent(ks, 0);
|
||||
} else if (strcasecmp(params[0],"key") == 0) {
|
||||
SendKeyEvent(ks, 1);
|
||||
SendKeyEvent(ks, 0);
|
||||
} else {
|
||||
fprintf(stderr,"Invalid event '%s' passed to SendRFBEvent\n",
|
||||
params[0]);
|
||||
return;
|
||||
}
|
||||
} else if (strcasecmp(params[0],"ptr") == 0) {
|
||||
if (*num_params == 4) {
|
||||
x = atoi(params[1]);
|
||||
y = atoi(params[2]);
|
||||
buttonMask = atoi(params[3]);
|
||||
SendPointerEvent(x, y, buttonMask);
|
||||
} else if (*num_params == 2) {
|
||||
switch (ev->type) {
|
||||
case ButtonPress:
|
||||
case ButtonRelease:
|
||||
x = ev->xbutton.x;
|
||||
y = ev->xbutton.y;
|
||||
break;
|
||||
case KeyPress:
|
||||
case KeyRelease:
|
||||
x = ev->xkey.x;
|
||||
y = ev->xkey.y;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr,
|
||||
"Invalid event caused SendRFBEvent(ptr,<buttonMask>)\n");
|
||||
return;
|
||||
}
|
||||
buttonMask = atoi(params[1]);
|
||||
SendPointerEvent(x, y, buttonMask);
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
"Invalid params: SendRFBEvent(ptr,<x>,<y>,<buttonMask>)\n"
|
||||
" or SendRFBEvent(ptr,<buttonMask>)\n");
|
||||
return;
|
||||
}
|
||||
|
||||
} else {
|
||||
fprintf(stderr,"Invalid event '%s' passed to SendRFBEvent\n", params[0]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
switch (ev->type) {
|
||||
|
||||
case MotionNotify:
|
||||
while (XCheckTypedWindowEvent(dpy, desktopWin, MotionNotify, ev))
|
||||
; // discard all queued motion notify events
|
||||
|
||||
SendPointerEvent(ev->xmotion.x, ev->xmotion.y,
|
||||
(ev->xmotion.state & 0x1f00) >> 8);
|
||||
return;
|
||||
|
||||
case ButtonPress:
|
||||
SendPointerEvent(ev->xbutton.x, ev->xbutton.y,
|
||||
(((ev->xbutton.state & 0x1f00) >> 8) |
|
||||
(1 << (ev->xbutton.button - 1))));
|
||||
return;
|
||||
|
||||
case ButtonRelease:
|
||||
SendPointerEvent(ev->xbutton.x, ev->xbutton.y,
|
||||
(((ev->xbutton.state & 0x1f00) >> 8) &
|
||||
~(1 << (ev->xbutton.button - 1))));
|
||||
return;
|
||||
|
||||
case KeyPress:
|
||||
case KeyRelease:
|
||||
XLookupString(&ev->xkey, keyname, 256, &ks, NULL);
|
||||
|
||||
if (IsModifierKey(ks)) {
|
||||
ks = XKeycodeToKeysym(dpy, ev->xkey.keycode, 0);
|
||||
modifierPressed[ev->xkey.keycode] = (ev->type == KeyPress);
|
||||
}
|
||||
|
||||
SendKeyEvent(ks, (ev->type == KeyPress));
|
||||
return;
|
||||
|
||||
default:
|
||||
fprintf(stderr,"Invalid event passed to SendRFBEvent\n");
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
* CreateDotCursor.
|
||||
*/
|
||||
|
||||
static Cursor
|
||||
CreateDotCursor()
|
||||
{
|
||||
Cursor cursor;
|
||||
Pixmap src, msk;
|
||||
static char srcBits[] = { 0, 14,14,14, 0 };
|
||||
static char mskBits[] = { 14,31,31,31,14 };
|
||||
XColor fg, bg;
|
||||
|
||||
src = XCreateBitmapFromData(dpy, DefaultRootWindow(dpy), srcBits, 5, 5);
|
||||
msk = XCreateBitmapFromData(dpy, DefaultRootWindow(dpy), mskBits, 5, 5);
|
||||
XAllocNamedColor(dpy, DefaultColormap(dpy,DefaultScreen(dpy)), "black",
|
||||
&fg, &fg);
|
||||
XAllocNamedColor(dpy, DefaultColormap(dpy,DefaultScreen(dpy)), "white",
|
||||
&bg, &bg);
|
||||
cursor = XCreatePixmapCursor(dpy, src, msk, &fg, &bg, 2, 2);
|
||||
XFreePixmap(dpy, src);
|
||||
XFreePixmap(dpy, msk);
|
||||
|
||||
return cursor;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* CopyDataToScreen.
|
||||
*/
|
||||
|
||||
void
|
||||
CopyDataToScreen(char *buf, int x, int y, int width, int height)
|
||||
{
|
||||
if (appData.rawDelay != 0) {
|
||||
lockQt();
|
||||
XFillRectangle(dpy, desktopWin, gc, x, y, width, height);
|
||||
XSync(dpy,False);
|
||||
unlockQt();
|
||||
|
||||
usleep(appData.rawDelay * 1000);
|
||||
}
|
||||
|
||||
if (!appData.useBGR233) {
|
||||
int h;
|
||||
int widthInBytes = width * myFormat.bitsPerPixel / 8;
|
||||
int scrWidthInBytes = si.framebufferWidth * myFormat.bitsPerPixel / 8;
|
||||
|
||||
char *scr = (image->data + y * scrWidthInBytes
|
||||
+ x * myFormat.bitsPerPixel / 8);
|
||||
|
||||
for (h = 0; h < height; h++) {
|
||||
memcpy(scr, buf, widthInBytes);
|
||||
buf += widthInBytes;
|
||||
scr += scrWidthInBytes;
|
||||
}
|
||||
} else {
|
||||
CopyBGR233ToScreen((CARD8 *)buf, x, y, width, height);
|
||||
}
|
||||
|
||||
lockQt();
|
||||
if (useShm)
|
||||
XShmPutImage(dpy, desktopWin, gc, image, x, y, x, y, width, height, False);
|
||||
else
|
||||
XPutImage(dpy, desktopWin, gc, image, x, y, x, y, width, height);
|
||||
unlockQt();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* CopyBGR233ToScreen.
|
||||
*/
|
||||
|
||||
static void
|
||||
CopyBGR233ToScreen(CARD8 *buf, int x, int y, int width, int height)
|
||||
{
|
||||
int p, q;
|
||||
int xoff = 7 - (x & 7);
|
||||
int xcur;
|
||||
int fbwb = si.framebufferWidth / 8;
|
||||
CARD8 *scr1 = ((CARD8 *)image->data) + y * fbwb + x / 8;
|
||||
CARD8 *scrt;
|
||||
CARD8 *scr8 = ((CARD8 *)image->data) + y * si.framebufferWidth + x;
|
||||
CARD16 *scr16 = ((CARD16 *)image->data) + y * si.framebufferWidth + x;
|
||||
CARD32 *scr32 = ((CARD32 *)image->data) + y * si.framebufferWidth + x;
|
||||
|
||||
switch (visbpp) {
|
||||
|
||||
/* thanks to Chris Hooper for single bpp support */
|
||||
|
||||
case 1:
|
||||
for (q = 0; q < height; q++) {
|
||||
xcur = xoff;
|
||||
scrt = scr1;
|
||||
for (p = 0; p < width; p++) {
|
||||
*scrt = ((*scrt & ~(1 << xcur))
|
||||
| (BGR233ToPixel[*(buf++)] << xcur));
|
||||
|
||||
if (xcur-- == 0) {
|
||||
xcur = 7;
|
||||
scrt++;
|
||||
}
|
||||
}
|
||||
scr1 += fbwb;
|
||||
}
|
||||
break;
|
||||
|
||||
case 8:
|
||||
for (q = 0; q < height; q++) {
|
||||
for (p = 0; p < width; p++) {
|
||||
*(scr8++) = BGR233ToPixel[*(buf++)];
|
||||
}
|
||||
scr8 += si.framebufferWidth - width;
|
||||
}
|
||||
break;
|
||||
|
||||
case 16:
|
||||
for (q = 0; q < height; q++) {
|
||||
for (p = 0; p < width; p++) {
|
||||
*(scr16++) = BGR233ToPixel[*(buf++)];
|
||||
}
|
||||
scr16 += si.framebufferWidth - width;
|
||||
}
|
||||
break;
|
||||
|
||||
case 32:
|
||||
for (q = 0; q < height; q++) {
|
||||
for (p = 0; p < width; p++) {
|
||||
*(scr32++) = BGR233ToPixel[*(buf++)];
|
||||
}
|
||||
scr32 += si.framebufferWidth - width;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ShmSync(void) {
|
||||
if (useShm)
|
||||
XSync(dpy, False);
|
||||
}
|
||||
|
||||
/*
|
||||
* ToplevelInitBeforeRealization sets the title, geometry and other resources
|
||||
* on the toplevel window.
|
||||
*/
|
||||
|
||||
void
|
||||
ToplevelInit()
|
||||
{
|
||||
dpyWidth = WidthOfScreen(DefaultScreenOfDisplay(dpy));
|
||||
dpyHeight = HeightOfScreen(DefaultScreenOfDisplay(dpy));
|
||||
}
|
||||
|
||||
/*
|
||||
* Cleanup - perform shm cleanup operations prior to exiting.
|
||||
*/
|
||||
|
||||
void
|
||||
Cleanup()
|
||||
{
|
||||
if (useShm)
|
||||
ShmCleanup();
|
||||
}
|
||||
|
||||
void
|
||||
ShmCleanup()
|
||||
{
|
||||
fprintf(stderr,"ShmCleanup called\n");
|
||||
if (needShmCleanup) {
|
||||
shmdt(shminfo.shmaddr);
|
||||
shmctl(shminfo.shmid, IPC_RMID, 0);
|
||||
needShmCleanup = False;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
ShmCreationXErrorHandler(Display* _dpy, XErrorEvent *_e)
|
||||
{
|
||||
caughtShmError = True;
|
||||
return 0;
|
||||
}
|
||||
|
||||
XImage *
|
||||
CreateShmImage()
|
||||
{
|
||||
XImage *_image;
|
||||
XErrorHandler oldXErrorHandler;
|
||||
|
||||
if (!XShmQueryExtension(dpy))
|
||||
return NULL;
|
||||
|
||||
_image = XShmCreateImage(dpy, vis, visdepth, ZPixmap, NULL, &shminfo,
|
||||
si.framebufferWidth, si.framebufferHeight);
|
||||
if (!_image) return NULL;
|
||||
|
||||
shminfo.shmid = shmget(IPC_PRIVATE,
|
||||
_image->bytes_per_line * _image->height,
|
||||
IPC_CREAT|0777);
|
||||
|
||||
if (shminfo.shmid == -1) {
|
||||
XDestroyImage(_image);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
shminfo.shmaddr = _image->data = shmat(shminfo.shmid, 0, 0);
|
||||
|
||||
if (shminfo.shmaddr == (char *)-1) {
|
||||
XDestroyImage(_image);
|
||||
shmctl(shminfo.shmid, IPC_RMID, 0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
shminfo.readOnly = True;
|
||||
|
||||
oldXErrorHandler = XSetErrorHandler(ShmCreationXErrorHandler);
|
||||
XShmAttach(dpy, &shminfo);
|
||||
XSync(dpy, False);
|
||||
XSetErrorHandler(oldXErrorHandler);
|
||||
|
||||
if (caughtShmError) {
|
||||
XDestroyImage(_image);
|
||||
shmdt(shminfo.shmaddr);
|
||||
shmctl(shminfo.shmid, IPC_RMID, 0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
needShmCleanup = True;
|
||||
|
||||
fprintf(stderr,"Using shared memory PutImage\n");
|
||||
|
||||
return _image;
|
||||
}
|
147
client/hextile.c
147
client/hextile.c
|
@ -1,147 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 1999 AT&T Laboratories Cambridge. 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* hextile.c - handle hextile encoding.
|
||||
*
|
||||
* This file shouldn't be compiled directly. It is included multiple times by
|
||||
* rfbproto.c, each time with a different definition of the macro BPP. For
|
||||
* each value of BPP, this file defines a function which handles a hextile
|
||||
* encoded rectangle with BPP bits per pixel.
|
||||
*/
|
||||
|
||||
#define HandleHextileBPP CONCAT2E(HandleHextile,BPP)
|
||||
#define CARDBPP CONCAT2E(CARD,BPP)
|
||||
#define GET_PIXEL CONCAT2E(GET_PIXEL,BPP)
|
||||
|
||||
static Bool
|
||||
HandleHextileBPP (int rx, int ry, int rw, int rh)
|
||||
{
|
||||
CARDBPP bg, fg;
|
||||
XGCValues gcv;
|
||||
int i;
|
||||
CARD8 *ptr;
|
||||
int x, y, w, h;
|
||||
int sx, sy, sw, sh;
|
||||
CARD8 subencoding;
|
||||
CARD8 nSubrects;
|
||||
|
||||
for (y = ry; y < ry+rh; y += 16) {
|
||||
for (x = rx; x < rx+rw; x += 16) {
|
||||
w = h = 16;
|
||||
if (rx+rw - x < 16)
|
||||
w = rx+rw - x;
|
||||
if (ry+rh - y < 16)
|
||||
h = ry+rh - y;
|
||||
|
||||
if (!ReadFromRFBServer((char *)&subencoding, 1))
|
||||
return False;
|
||||
|
||||
if (subencoding & rfbHextileRaw) {
|
||||
if (!ReadFromRFBServer(buffer, w * h * (BPP / 8)))
|
||||
return False;
|
||||
|
||||
CopyDataToScreen(buffer, x, y, w, h);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (subencoding & rfbHextileBackgroundSpecified)
|
||||
if (!ReadFromRFBServer((char *)&bg, sizeof(bg)))
|
||||
return False;
|
||||
|
||||
#if (BPP == 8)
|
||||
if (appData.useBGR233)
|
||||
gcv.foreground = BGR233ToPixel[bg];
|
||||
else
|
||||
#endif
|
||||
gcv.foreground = bg;
|
||||
|
||||
lockQt();
|
||||
XChangeGC(dpy, gc, GCForeground, &gcv);
|
||||
XFillRectangle(dpy, desktopWin, gc, x, y, w, h);
|
||||
unlockQt();
|
||||
|
||||
if (subencoding & rfbHextileForegroundSpecified)
|
||||
if (!ReadFromRFBServer((char *)&fg, sizeof(fg)))
|
||||
return False;
|
||||
|
||||
if (!(subencoding & rfbHextileAnySubrects)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ReadFromRFBServer((char *)&nSubrects, 1))
|
||||
return False;
|
||||
|
||||
ptr = (CARD8 *)buffer;
|
||||
|
||||
if (subencoding & rfbHextileSubrectsColoured) {
|
||||
if (!ReadFromRFBServer(buffer, nSubrects * (2 + (BPP / 8))))
|
||||
return False;
|
||||
|
||||
lockQt();
|
||||
for (i = 0; i < nSubrects; i++) {
|
||||
GET_PIXEL(fg, ptr);
|
||||
sx = rfbHextileExtractX(*ptr);
|
||||
sy = rfbHextileExtractY(*ptr);
|
||||
ptr++;
|
||||
sw = rfbHextileExtractW(*ptr);
|
||||
sh = rfbHextileExtractH(*ptr);
|
||||
ptr++;
|
||||
#if (BPP == 8)
|
||||
if (appData.useBGR233)
|
||||
gcv.foreground = BGR233ToPixel[fg];
|
||||
else
|
||||
#endif
|
||||
gcv.foreground = fg;
|
||||
|
||||
XChangeGC(dpy, gc, GCForeground, &gcv);
|
||||
XFillRectangle(dpy, desktopWin, gc, x+sx, y+sy, sw, sh);
|
||||
}
|
||||
unlockQt();
|
||||
|
||||
} else {
|
||||
if (!ReadFromRFBServer(buffer, nSubrects * 2))
|
||||
return False;
|
||||
|
||||
#if (BPP == 8)
|
||||
if (appData.useBGR233)
|
||||
gcv.foreground = BGR233ToPixel[fg];
|
||||
else
|
||||
#endif
|
||||
gcv.foreground = fg;
|
||||
|
||||
lockQt();
|
||||
XChangeGC(dpy, gc, GCForeground, &gcv);
|
||||
|
||||
for (i = 0; i < nSubrects; i++) {
|
||||
sx = rfbHextileExtractX(*ptr);
|
||||
sy = rfbHextileExtractY(*ptr);
|
||||
ptr++;
|
||||
sw = rfbHextileExtractW(*ptr);
|
||||
sh = rfbHextileExtractH(*ptr);
|
||||
ptr++;
|
||||
XFillRectangle(dpy, desktopWin, gc, x+sx, y+sy, sw, sh);
|
||||
}
|
||||
unlockQt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return True;
|
||||
}
|
180
client/krdc.cpp
180
client/krdc.cpp
|
@ -1,180 +0,0 @@
|
|||
/***************************************************************************
|
||||
krdc.cpp - main window
|
||||
-------------------
|
||||
begin : Tue May 13 23:07:42 CET 2002
|
||||
copyright : (C) 2002 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 "newconnectiondialog.h"
|
||||
#include "krdc.h"
|
||||
#include <kdebug.h>
|
||||
#include <kapplication.h>
|
||||
#include <kcombobox.h>
|
||||
#include <kconfig.h>
|
||||
#include <qlayout.h>
|
||||
|
||||
|
||||
|
||||
KRDC::KRDC(QWidget *w, const QString &host, Quality q) :
|
||||
QWidget(w, 0),
|
||||
m_view(0),
|
||||
m_host(host),
|
||||
m_quality(q)
|
||||
{
|
||||
m_scrollView = new QScrollView(this, "Remote View");
|
||||
QVBoxLayout *vbl = new QVBoxLayout(this);
|
||||
vbl->addWidget(m_scrollView);
|
||||
}
|
||||
|
||||
bool KRDC::start()
|
||||
{
|
||||
KConfig *config = KApplication::kApplication()->config();
|
||||
QString vncServerHost;
|
||||
int vncServerPort = 5900;
|
||||
|
||||
if (!m_host.isNull()) {
|
||||
parseHost(m_host, vncServerHost, vncServerPort);
|
||||
if (m_quality == QUALITY_UNKNOWN)
|
||||
m_quality = QUALITY_HIGH;
|
||||
} else {
|
||||
NewConnectionDialog ncd(0, 0, true);
|
||||
QStringList list = config->readListEntry("serverCompletions");
|
||||
ncd.serverInput->completionObject()->setItems(list);
|
||||
list = config->readListEntry("serverHistory");
|
||||
ncd.serverInput->setHistoryItems(list);
|
||||
|
||||
if ((ncd.exec() == QDialog::Rejected) ||
|
||||
(ncd.serverInput->currentText().length() == 0)) {
|
||||
return false;
|
||||
}
|
||||
QString host = ncd.serverInput->currentText();
|
||||
parseHost(host, vncServerHost, vncServerPort);
|
||||
int ci = ncd.qualityCombo->currentItem();
|
||||
if (ci == 0)
|
||||
m_quality = QUALITY_HIGH;
|
||||
else if (ci == 1)
|
||||
m_quality = QUALITY_MEDIUM;
|
||||
else if (ci == 2)
|
||||
m_quality = QUALITY_LOW;
|
||||
else {
|
||||
kdDebug() << "Unknown quality";
|
||||
return false;
|
||||
}
|
||||
|
||||
ncd.serverInput->addToHistory(host);
|
||||
list = ncd.serverInput->completionObject()->items();
|
||||
config->writeEntry("serverCompletions", list);
|
||||
list = ncd.serverInput->historyItems();
|
||||
config->writeEntry("serverHistory", list);
|
||||
}
|
||||
|
||||
configureApp(m_quality);
|
||||
|
||||
setFixedSize(640, 480);
|
||||
m_view = new KVncView(m_scrollView, 0, vncServerHost, vncServerPort,
|
||||
&m_appData);
|
||||
m_scrollView->addChild(m_view);
|
||||
connect(m_view, SIGNAL(changeSize(int,int)), SLOT(setSize(int,int)));
|
||||
show();
|
||||
m_view->start();
|
||||
return true;
|
||||
}
|
||||
|
||||
void KRDC::configureApp(Quality q) {
|
||||
m_appData.shareDesktop = True;
|
||||
m_appData.viewOnly = False;
|
||||
|
||||
if (q == QUALITY_LOW) {
|
||||
m_appData.useBGR233 = True;
|
||||
m_appData.encodingsString = "copyrect tight zlib hextile corre rre raw";
|
||||
m_appData.compressLevel = -1;
|
||||
m_appData.qualityLevel = 1;
|
||||
}
|
||||
else if (q == QUALITY_MEDIUM) {
|
||||
m_appData.useBGR233 = False;
|
||||
m_appData.encodingsString = "copyrect tight zlib hextile corre rre raw";
|
||||
m_appData.compressLevel = -1;
|
||||
m_appData.qualityLevel = 4;
|
||||
}
|
||||
else if ((q == QUALITY_HIGH) || (q == QUALITY_UNKNOWN)) {
|
||||
m_appData.useBGR233 = False;
|
||||
m_appData.encodingsString = "copyrect hextile corre rre raw";
|
||||
m_appData.compressLevel = -1;
|
||||
m_appData.qualityLevel = 9;
|
||||
}
|
||||
|
||||
m_appData.nColours = 256;
|
||||
m_appData.useSharedColours = True;
|
||||
m_appData.requestedDepth = 0;
|
||||
m_appData.useRemoteCursor = True;
|
||||
|
||||
m_appData.rawDelay = 0;
|
||||
m_appData.copyRectDelay = 0;
|
||||
}
|
||||
|
||||
void KRDC::parseHost(QString &s, QString &serverHost, int &serverPort) {
|
||||
QString host = s;
|
||||
int pos = s.find(':');
|
||||
if (pos < 0) {
|
||||
s+= ":0";
|
||||
host+= ":0";
|
||||
pos = s.find(':');
|
||||
}
|
||||
|
||||
bool portOk = false;
|
||||
QString portS = s.mid(pos+1);
|
||||
int port = portS.toInt(&portOk);
|
||||
if (portOk) {
|
||||
host = s.left(pos);
|
||||
if (port < 100)
|
||||
serverPort = port + 5900;
|
||||
else
|
||||
serverPort = port;
|
||||
}
|
||||
|
||||
serverHost = host;
|
||||
}
|
||||
|
||||
KRDC::~KRDC()
|
||||
{
|
||||
}
|
||||
|
||||
void KRDC::setSize(int w, int h)
|
||||
{
|
||||
int newW, newH, dw, dh, fx, fy;
|
||||
setMaximumSize(w, h);
|
||||
QWidget *desktop = QApplication::desktop();
|
||||
// todo: switch to fullscreen if desktop is too small
|
||||
dw = desktop->width();
|
||||
dh = desktop->height();
|
||||
newW = (w > dw) ? dw : w;
|
||||
newH = (h > dh) ? dh : h;
|
||||
|
||||
QRect g = geometry();
|
||||
QRect f = frameGeometry();
|
||||
fx = g.x() - f.x();
|
||||
fy = g.y() - f.y();
|
||||
|
||||
g.setWidth(newW);
|
||||
g.setHeight(newH);
|
||||
if (g.right() > dw)
|
||||
g.setX(dw - g.width());
|
||||
if (g.x() < fx)
|
||||
g.setX(fx);
|
||||
if (g.bottom() > dh)
|
||||
g.setY(dh - g.height());
|
||||
if (g.y() < fy)
|
||||
g.setY(fy);
|
||||
setGeometry(g);
|
||||
}
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
/***************************************************************************
|
||||
krdc.h - main window
|
||||
-------------------
|
||||
begin : Tue May 13 23:10:42 CET 2002
|
||||
copyright : (C) 2002 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 KRDC_H
|
||||
#define KRDC_H
|
||||
|
||||
#include <qscrollview.h>
|
||||
#include "kvncview.h"
|
||||
|
||||
|
||||
class KRDC : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
QScrollView *m_scrollView;
|
||||
KVncView *m_view;
|
||||
QString m_host;
|
||||
Quality m_quality;
|
||||
AppData m_appData;
|
||||
|
||||
void configureApp(Quality q);
|
||||
void parseHost(QString &s, QString &serverHost, int &serverPort);
|
||||
|
||||
protected:
|
||||
|
||||
public:
|
||||
KRDC(QWidget *parent = 0,
|
||||
const QString &host = QString::null,
|
||||
Quality q = QUALITY_UNKNOWN);
|
||||
~KRDC();
|
||||
bool start();
|
||||
|
||||
private slots:
|
||||
void setSize(int w, int h);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1 +0,0 @@
|
|||
|
|
@ -1,383 +0,0 @@
|
|||
/***************************************************************************
|
||||
kvncview.cpp - main widget
|
||||
-------------------
|
||||
begin : Thu Dec 20 15:11:42 CET 2001
|
||||
copyright : (C) 2001-2002 by Tim Jansen
|
||||
contains portions (event handling) from Keystone:
|
||||
(C) 1999-2000 Richard Moore
|
||||
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 "passworddialog.h"
|
||||
#include "kvncview.h"
|
||||
#include <kdebug.h>
|
||||
#include <qlineedit.h>
|
||||
#include <qdialog.h>
|
||||
#include <qmutex.h>
|
||||
#include <qwaitcondition.h>
|
||||
|
||||
/*
|
||||
* appData is our application-specific data which can be set by the user with
|
||||
* application resource specs. The AppData structure is defined in the header
|
||||
* file.
|
||||
*/
|
||||
|
||||
AppData appData;
|
||||
|
||||
Display* dpy;
|
||||
|
||||
static KVncView *kvncview;
|
||||
|
||||
static QString password;
|
||||
static QMutex passwordLock;
|
||||
static QWaitCondition passwordWaiter;
|
||||
|
||||
|
||||
|
||||
KVncView::KVncView(QWidget *parent,
|
||||
const char *name,
|
||||
const QString &_host,
|
||||
int _port,
|
||||
AppData *data) :
|
||||
QWidget(parent, name),
|
||||
m_cthread(this, m_wthread, m_quitFlag),
|
||||
m_wthread(m_quitFlag),
|
||||
m_quitFlag(false),
|
||||
m_host(_host),
|
||||
m_port(_port)
|
||||
{
|
||||
kvncview = this;
|
||||
password = QString::null;
|
||||
dpy = qt_xdisplay();
|
||||
if (data)
|
||||
appData = *data;
|
||||
else
|
||||
setDefaultAppData();
|
||||
setFixedSize(512, 384);
|
||||
setFocusPolicy(QWidget::StrongFocus);
|
||||
emit changeSize(512, 384);
|
||||
}
|
||||
|
||||
void KVncView::setDefaultAppData() {
|
||||
appData.shareDesktop = True;
|
||||
appData.viewOnly = False;
|
||||
|
||||
appData.useBGR233 = False;
|
||||
appData.encodingsString = "copyrect hextile corre rre raw";
|
||||
appData.compressLevel = -1;
|
||||
appData.qualityLevel = 9;
|
||||
|
||||
appData.nColours = 256;
|
||||
appData.useSharedColours = True;
|
||||
appData.requestedDepth = 0;
|
||||
appData.useRemoteCursor = True;
|
||||
|
||||
appData.rawDelay = 0;
|
||||
appData.copyRectDelay = 0;
|
||||
}
|
||||
|
||||
QString KVncView::host() {
|
||||
return m_host;
|
||||
}
|
||||
|
||||
int KVncView::port() {
|
||||
return m_port;
|
||||
}
|
||||
|
||||
void KVncView::startQuitting() {
|
||||
m_quitFlag = true;
|
||||
m_wthread.kick();
|
||||
}
|
||||
|
||||
bool KVncView::isQuitting() {
|
||||
return m_quitFlag;
|
||||
}
|
||||
|
||||
enum RemoteViewStatus KVncView::status() {
|
||||
return m_status;
|
||||
}
|
||||
|
||||
void KVncView::start() {
|
||||
m_cthread.start();
|
||||
}
|
||||
|
||||
KVncView::~KVncView()
|
||||
{
|
||||
m_cthread.wait();
|
||||
m_wthread.wait();
|
||||
}
|
||||
|
||||
void KVncView::paintEvent(QPaintEvent *e) {
|
||||
if (status() == REMOTE_VIEW_CONNECTED)
|
||||
m_wthread.queueUpdateRequest(e->region());
|
||||
}
|
||||
|
||||
void KVncView::customEvent(QCustomEvent *e)
|
||||
{
|
||||
if (e->type() == ScreenResizeEventType) {
|
||||
ScreenResizeEvent *sre = (ScreenResizeEvent*) e;
|
||||
setFixedSize(sre->width(), sre->height());
|
||||
emit changeSize(sre->width(), sre->height());
|
||||
}
|
||||
else if (e->type() == StatusChangeEventType) {
|
||||
StatusChangeEvent *sce = (StatusChangeEvent*) e;
|
||||
m_status = sce->status();
|
||||
if (m_status == REMOTE_VIEW_CONNECTED) {
|
||||
setFocus();
|
||||
setMouseTracking(true);
|
||||
}
|
||||
if (m_status == REMOTE_VIEW_DISCONNECTED) {
|
||||
setMouseTracking(false);
|
||||
emit disconnected();
|
||||
}
|
||||
}
|
||||
else if (e->type() == PasswordRequiredEventType) {
|
||||
PasswordDialog pd(0, 0, true);
|
||||
if (pd.exec() == QDialog::Accepted)
|
||||
password = pd.passwordInput->text();
|
||||
else
|
||||
password = QString::null;
|
||||
|
||||
passwordLock.lock(); // to guarantee that thread is waiting
|
||||
passwordWaiter.wakeAll();
|
||||
passwordLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void KVncView::mouseEvent(QMouseEvent *e) {
|
||||
if (status() != REMOTE_VIEW_CONNECTED)
|
||||
return;
|
||||
|
||||
if ( e->type() != QEvent::MouseMove ) {
|
||||
m_buttonMask = 0;
|
||||
if ( e->type() == QEvent::MouseButtonPress ) {
|
||||
if ( e->button() & LeftButton )
|
||||
m_buttonMask |= 0x01;
|
||||
if ( e->button() & MidButton )
|
||||
m_buttonMask |= 0x04;
|
||||
if ( e->button() & RightButton )
|
||||
m_buttonMask |= 0x02;
|
||||
}
|
||||
else if ( e->type() == QEvent::MouseButtonRelease ) {
|
||||
if ( e->button() & LeftButton )
|
||||
m_buttonMask &= 0x06;
|
||||
if ( e->button() & MidButton )
|
||||
m_buttonMask &= 0x04;
|
||||
if ( e->button() & RightButton )
|
||||
m_buttonMask &= 0x02;
|
||||
}
|
||||
}
|
||||
m_wthread.queueMouseEvent(e->x(), e->y(), m_buttonMask);
|
||||
}
|
||||
|
||||
void KVncView::mousePressEvent(QMouseEvent *e) {
|
||||
mouseEvent(e);
|
||||
}
|
||||
|
||||
void KVncView::mouseReleaseEvent(QMouseEvent *e) {
|
||||
mouseEvent(e);
|
||||
}
|
||||
|
||||
void KVncView::mouseMoveEvent(QMouseEvent *e) {
|
||||
mouseEvent(e);
|
||||
}
|
||||
|
||||
void KVncView::keyPressEvent(QKeyEvent *e) {
|
||||
m_wthread.queueKeyEvent(toKeySym(e), true);
|
||||
}
|
||||
|
||||
void KVncView::keyReleaseEvent(QKeyEvent *e) {
|
||||
m_wthread.queueKeyEvent(toKeySym(e), false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int getPassword(char *passwd, int pwlen) {
|
||||
int retV = 1;
|
||||
|
||||
passwordLock.lock();
|
||||
if (password.isNull()) {
|
||||
QThread::postEvent(kvncview, new PasswordRequiredEvent());
|
||||
passwordWaiter.wait(&passwordLock);
|
||||
}
|
||||
if (!password.isNull())
|
||||
strncpy(passwd, password.latin1(), pwlen);
|
||||
else {
|
||||
passwd[0] = 0;
|
||||
retV = 0;
|
||||
}
|
||||
passwordLock.unlock();
|
||||
|
||||
if (!retV)
|
||||
kvncview->startQuitting();
|
||||
return retV;
|
||||
}
|
||||
|
||||
extern int isQuitFlagSet() {
|
||||
return kvncview->isQuitting() ? 1 : 0;
|
||||
}
|
||||
|
||||
void lockQt() {
|
||||
KApplication::kApplication()->lock();
|
||||
}
|
||||
|
||||
void unlockQt() {
|
||||
KApplication::kApplication()->unlock(false);
|
||||
}
|
||||
|
||||
void unlockQtGui() {
|
||||
KApplication::kApplication()->unlock(true);
|
||||
}
|
||||
|
||||
KeySym KVncView::toKeySym(QKeyEvent *k)
|
||||
{
|
||||
int ke = 0;
|
||||
|
||||
ke = k->ascii();
|
||||
// Markus: Crappy hack. I dont know why lower case letters are
|
||||
// not defined in qkeydefs.h. The key() for e.g. 'l' == 'L'.
|
||||
// This sucks. :-(
|
||||
|
||||
if ( (ke >= 'a') && (ke <= 'z') ) {
|
||||
ke = k->key();
|
||||
ke = ke + 0x20;
|
||||
return ke;
|
||||
}
|
||||
|
||||
// qkeydefs = xkeydefs! :-)
|
||||
if ( ( k->key() >= 0x0a0 ) && k->key() <= 0x0ff )
|
||||
return k->key();
|
||||
|
||||
if ( ( k->key() >= 0x20 ) && ( k->key() <= 0x7e ) )
|
||||
return k->key();
|
||||
|
||||
// qkeydefs != xkeydefs! :-(
|
||||
// This is gonna suck :-(
|
||||
|
||||
switch( k->key() ) {
|
||||
case SHIFT:
|
||||
return XK_Shift_L;
|
||||
case CTRL:
|
||||
return XK_Control_L;
|
||||
case ALT:
|
||||
return XK_Alt_L;
|
||||
|
||||
case Key_Escape:
|
||||
return XK_Escape;
|
||||
case Key_Tab:
|
||||
return XK_Tab;
|
||||
case Key_Backspace:
|
||||
return XK_BackSpace;
|
||||
case Key_Return:
|
||||
return XK_Return;
|
||||
case Key_Enter:
|
||||
return XK_Return;
|
||||
case Key_Insert:
|
||||
return XK_Insert;
|
||||
case Key_Delete:
|
||||
return XK_Delete;
|
||||
case Key_Pause:
|
||||
return XK_Pause;
|
||||
case Key_Print:
|
||||
return XK_Print;
|
||||
case Key_SysReq:
|
||||
return XK_Sys_Req;
|
||||
case Key_Home:
|
||||
return XK_Home;
|
||||
case Key_End:
|
||||
return XK_End;
|
||||
case Key_Left:
|
||||
return XK_Left;
|
||||
case Key_Up:
|
||||
return XK_Up;
|
||||
case Key_Right:
|
||||
return XK_Right;
|
||||
case Key_Down:
|
||||
return XK_Down;
|
||||
case Key_Prior:
|
||||
return XK_Prior;
|
||||
case Key_Next:
|
||||
return XK_Next;
|
||||
|
||||
case Key_Shift:
|
||||
return XK_Shift_L;
|
||||
case Key_Control:
|
||||
return XK_Control_L;
|
||||
case Key_Meta:
|
||||
return XK_Meta_L;
|
||||
case Key_Alt:
|
||||
return XK_Alt_L;
|
||||
case Key_CapsLock:
|
||||
return XK_Caps_Lock;
|
||||
case Key_NumLock:
|
||||
return XK_Num_Lock;
|
||||
case Key_ScrollLock:
|
||||
return XK_Scroll_Lock;
|
||||
|
||||
case Key_F1:
|
||||
return XK_F1;
|
||||
case Key_F2:
|
||||
return XK_F2;
|
||||
case Key_F3:
|
||||
return XK_F3;
|
||||
case Key_F4:
|
||||
return XK_F4;
|
||||
case Key_F5:
|
||||
return XK_F5;
|
||||
case Key_F6:
|
||||
return XK_F6;
|
||||
case Key_F7:
|
||||
return XK_F7;
|
||||
case Key_F8:
|
||||
return XK_F8;
|
||||
case Key_F9:
|
||||
return XK_F9;
|
||||
case Key_F10:
|
||||
return XK_F10;
|
||||
case Key_F11:
|
||||
return XK_F11;
|
||||
case Key_F12:
|
||||
return XK_F12;
|
||||
case Key_F13:
|
||||
return XK_F13;
|
||||
case Key_F14:
|
||||
return XK_F14;
|
||||
case Key_F15:
|
||||
return XK_F15;
|
||||
case Key_F16:
|
||||
return XK_F16;
|
||||
case Key_F17:
|
||||
return XK_F17;
|
||||
case Key_F18:
|
||||
return XK_F18;
|
||||
case Key_F19:
|
||||
return XK_F19;
|
||||
case Key_F20:
|
||||
return XK_F20;
|
||||
case Key_F21:
|
||||
return XK_F21;
|
||||
case Key_F22:
|
||||
return XK_F22;
|
||||
case Key_F23:
|
||||
return XK_F23;
|
||||
case Key_F24:
|
||||
return XK_F24;
|
||||
|
||||
case Key_unknown:
|
||||
return 0;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Puhhhhh done. :-)
|
||||
return 0;
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
/***************************************************************************
|
||||
kvncview.h - widget that shows the vnc client
|
||||
-------------------
|
||||
begin : Thu Dec 20 15:11:42 CET 2001
|
||||
copyright : (C) 2001-2002 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 KVNCVIEW_H
|
||||
#define KVNCVIEW_H
|
||||
|
||||
|
||||
#include <kapplication.h>
|
||||
#include <qwidget.h>
|
||||
|
||||
#define VNCVIEWER_H
|
||||
#include "threads.h"
|
||||
#undef VNCVIEWER_H
|
||||
|
||||
#ifndef VNCVIEWER_H
|
||||
#define VNCVIEWER_H
|
||||
#include "vncviewer.h"
|
||||
#endif
|
||||
|
||||
|
||||
class KVncView : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
ControllerThread m_cthread;
|
||||
WriterThread m_wthread;
|
||||
volatile bool m_quitFlag;
|
||||
enum RemoteViewStatus m_status;
|
||||
|
||||
int m_buttonMask;
|
||||
|
||||
QString m_host;
|
||||
int m_port;
|
||||
|
||||
void setDefaultAppData();
|
||||
void mouseEvent(QMouseEvent*);
|
||||
KeySym toKeySym(QKeyEvent *k);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent*);
|
||||
void customEvent(QCustomEvent*);
|
||||
void mousePressEvent(QMouseEvent*);
|
||||
void mouseReleaseEvent(QMouseEvent*);
|
||||
void mouseMoveEvent(QMouseEvent*);
|
||||
void keyPressEvent(QKeyEvent*);
|
||||
void keyReleaseEvent(QKeyEvent*);
|
||||
|
||||
public:
|
||||
KVncView(QWidget* parent=0, const char *name=0,
|
||||
const QString &host = QString(""), int port = 5900,
|
||||
AppData *data = 0);
|
||||
~KVncView();
|
||||
|
||||
void startQuitting();
|
||||
bool isQuitting();
|
||||
|
||||
QString host();
|
||||
int port();
|
||||
void start();
|
||||
enum RemoteViewStatus status();
|
||||
|
||||
signals:
|
||||
void changeSize(int x, int y);
|
||||
void disconnected();
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,73 +0,0 @@
|
|||
/***************************************************************************
|
||||
main.cpp - description
|
||||
-------------------
|
||||
begin : Thu Dec 20 15:11:42 CET 2001
|
||||
copyright : (C) 2001-2002 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 <kcmdlineargs.h>
|
||||
#include <kaboutdata.h>
|
||||
#include <kapplication.h>
|
||||
#include <klocale.h>
|
||||
#include <kdebug.h>
|
||||
#include <qwindowdefs.h>
|
||||
|
||||
#include "kvncview.h"
|
||||
#include "krdc.h"
|
||||
|
||||
|
||||
#define VERSION "0.1"
|
||||
|
||||
static const char *description = I18N_NOOP("Remote Desktop Connection");
|
||||
|
||||
|
||||
static KCmdLineOptions options[] =
|
||||
{
|
||||
{ "+[host]", I18N_NOOP("An optional argument 'arg1'."), 0 },
|
||||
{ 0, 0, 0 }
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
KAboutData aboutData( "krdc", I18N_NOOP("Remote Desktop Connection"),
|
||||
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 );
|
||||
|
||||
KApplication a;
|
||||
|
||||
Quality quality = QUALITY_HIGH;
|
||||
|
||||
KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
|
||||
|
||||
KRDC *krdc;
|
||||
|
||||
if (args->count() > 0) {
|
||||
QString host = args->arg(0);
|
||||
krdc = new KRDC(0, host, quality);
|
||||
}
|
||||
else
|
||||
krdc = new KRDC();
|
||||
|
||||
a.setMainWidget(krdc);
|
||||
|
||||
if (!krdc->start())
|
||||
return 0;
|
||||
|
||||
return a.exec();
|
||||
}
|
|
@ -1,273 +0,0 @@
|
|||
<!DOCTYPE UI><UI version="3.0" stdsetdef="1">
|
||||
<class>NewConnectionDialog</class>
|
||||
<widget class="QDialog">
|
||||
<property name="name">
|
||||
<cstring>NewConnectionDialog</cstring>
|
||||
</property>
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>412</width>
|
||||
<height>170</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="caption">
|
||||
<string>Remote Desktop Connection</string>
|
||||
</property>
|
||||
<property name="layoutMargin" stdset="0">
|
||||
</property>
|
||||
<property name="layoutSpacing" stdset="0">
|
||||
</property>
|
||||
<vbox>
|
||||
<property name="name">
|
||||
<cstring>unnamed</cstring>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="spacing">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<widget class="QFrame">
|
||||
<property name="name">
|
||||
<cstring>upperFrame</cstring>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>Plain</enum>
|
||||
</property>
|
||||
<property name="layoutMargin" stdset="0">
|
||||
</property>
|
||||
<grid>
|
||||
<property name="name">
|
||||
<cstring>unnamed</cstring>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>11</number>
|
||||
</property>
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<widget class="QLabel" row="1" column="0" rowspan="1" colspan="2">
|
||||
<property name="name">
|
||||
<cstring>serverDescLabel</cstring>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Please enter the name or address of the computer that you want to connect to.</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>WordBreak|AlignVCenter|AlignLeft</set>
|
||||
</property>
|
||||
<property name="wordwrap" stdset="0">
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" row="0" column="0">
|
||||
<property name="name">
|
||||
<cstring>serverLabel</cstring>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy>
|
||||
<hsizetype>0</hsizetype>
|
||||
<vsizetype>5</vsizetype>
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>MShape</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>MShadow</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Remote Desktop:</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="KHistoryCombo" row="0" column="1">
|
||||
<property name="name">
|
||||
<cstring>serverInput</cstring>
|
||||
</property>
|
||||
<property name="maxCount">
|
||||
<number>12</number>
|
||||
</property>
|
||||
<property name="duplicatesEnabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="toolTip" stdset="0">
|
||||
<string></string>
|
||||
</property>
|
||||
<property name="whatsThis" stdset="0">
|
||||
<string>Enter the name of the server you want to connect to. If you have a display number enter it as well, separated from the server by a colon, e.g. 'mycomputer:2'.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</grid>
|
||||
</widget>
|
||||
<widget class="QFrame">
|
||||
<property name="name">
|
||||
<cstring>middleFrame</cstring>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy>
|
||||
<hsizetype>5</hsizetype>
|
||||
<vsizetype>1</vsizetype>
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>Plain</enum>
|
||||
</property>
|
||||
<property name="layoutMargin" stdset="0">
|
||||
</property>
|
||||
<property name="layoutSpacing" stdset="0">
|
||||
</property>
|
||||
<hbox>
|
||||
<property name="name">
|
||||
<cstring>unnamed</cstring>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="spacing">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<widget class="QLabel">
|
||||
<property name="name">
|
||||
<cstring>connectionTypeLabel</cstring>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy>
|
||||
<hsizetype>0</hsizetype>
|
||||
<vsizetype>1</vsizetype>
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Connection type:</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QComboBox">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>High Quality (LAN, direct connection)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Medium Quality (DSL, Cable, fast Internet)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Low Quality (Modem, ISDN, slow Internet)</string>
|
||||
</property>
|
||||
</item>
|
||||
<property name="name">
|
||||
<cstring>qualityCombo</cstring>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy>
|
||||
<hsizetype>5</hsizetype>
|
||||
<vsizetype>0</vsizetype>
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>280</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="whatsThis" stdset="0">
|
||||
<string>Use this to specify the performance of your connection. Note that you should select the speed of the weakest link - even if you have a high speed connection this will not help you if the remote computer uses a slow modem. Choosing a too high quality on a slow link will cause slower response times. Choosing a lower quality will increase latencies in high speed connections and results in lower image quality, especially in 'Low Quality' mode.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</hbox>
|
||||
</widget>
|
||||
<widget class="QFrame">
|
||||
<property name="name">
|
||||
<cstring>bottomFrame</cstring>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>Plain</enum>
|
||||
</property>
|
||||
<property name="layoutMargin" stdset="0">
|
||||
</property>
|
||||
<hbox>
|
||||
<property name="name">
|
||||
<cstring>unnamed</cstring>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<spacer>
|
||||
<property name="name">
|
||||
<cstring>spacer</cstring>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>Expanding</enum>
|
||||
</property>
|
||||
</spacer>
|
||||
<widget class="QPushButton">
|
||||
<property name="name">
|
||||
<cstring>connectButton</cstring>
|
||||
</property>
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>C&onnect</string>
|
||||
</property>
|
||||
<property name="default">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton">
|
||||
<property name="name">
|
||||
<cstring>cancelButton</cstring>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Cancel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</hbox>
|
||||
</widget>
|
||||
</vbox>
|
||||
</widget>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>connectButton</sender>
|
||||
<signal>clicked()</signal>
|
||||
<receiver>NewConnectionDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>cancelButton</sender>
|
||||
<signal>clicked()</signal>
|
||||
<receiver>NewConnectionDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
</connection>
|
||||
</connections>
|
||||
<layoutdefaults spacing="6" margin="11"/>
|
||||
</UI>
|
|
@ -1,104 +0,0 @@
|
|||
<!DOCTYPE UI><UI version="3.0" stdsetdef="1">
|
||||
<class>PasswordDialog</class>
|
||||
<widget class="QDialog">
|
||||
<property name="name">
|
||||
<cstring>PasswordDialog</cstring>
|
||||
</property>
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>330</width>
|
||||
<height>112</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="caption">
|
||||
<string>Remote Desktop Connection</string>
|
||||
</property>
|
||||
<property name="layoutSpacing" stdset="0">
|
||||
</property>
|
||||
<grid>
|
||||
<property name="name">
|
||||
<cstring>unnamed</cstring>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>11</number>
|
||||
</property>
|
||||
<property name="spacing">
|
||||
<number>8</number>
|
||||
</property>
|
||||
<widget class="QLabel" row="1" column="0">
|
||||
<property name="name">
|
||||
<cstring>passwordLabel</cstring>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Password:</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLineEdit" row="1" column="1" rowspan="1" colspan="3">
|
||||
<property name="name">
|
||||
<cstring>passwordInput</cstring>
|
||||
</property>
|
||||
<property name="echoMode">
|
||||
<enum>Password</enum>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" row="0" column="0" rowspan="1" colspan="4">
|
||||
<property name="name">
|
||||
<cstring>descLabel</cstring>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Access to the system requires a password.</string>
|
||||
</property>
|
||||
</widget>
|
||||
<spacer row="2" column="0" rowspan="1" colspan="2">
|
||||
<property name="name">
|
||||
<cstring>spacer</cstring>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>Expanding</enum>
|
||||
</property>
|
||||
</spacer>
|
||||
<widget class="QPushButton" row="2" column="2">
|
||||
<property name="name">
|
||||
<cstring>okButton</cstring>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&OK</string>
|
||||
</property>
|
||||
<property name="default">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPushButton" row="2" column="3">
|
||||
<property name="name">
|
||||
<cstring>cancelButton</cstring>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Cancel</string>
|
||||
</property>
|
||||
<property name="default">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</grid>
|
||||
</widget>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>okButton</sender>
|
||||
<signal>clicked()</signal>
|
||||
<receiver>PasswordDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>cancelButton</sender>
|
||||
<signal>clicked()</signal>
|
||||
<receiver>PasswordDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
</connection>
|
||||
</connections>
|
||||
<layoutdefaults spacing="6" margin="11"/>
|
||||
</UI>
|
|
@ -1,981 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2000, 2001 Const Kaplinsky. All Rights Reserved.
|
||||
* Copyright (C) 2000 Tridia Corporation. All Rights Reserved.
|
||||
* Copyright (C) 1999 AT&T Laboratories Cambridge. 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* rfbproto.c - functions to deal with client side of RFB protocol.
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <pwd.h>
|
||||
#include "vncviewer.h"
|
||||
#include "vncauth.h"
|
||||
#include <zlib.h>
|
||||
#include <jpeglib.h>
|
||||
|
||||
static Bool HandleRRE8(int rx, int ry, int rw, int rh);
|
||||
static Bool HandleRRE16(int rx, int ry, int rw, int rh);
|
||||
static Bool HandleRRE32(int rx, int ry, int rw, int rh);
|
||||
static Bool HandleCoRRE8(int rx, int ry, int rw, int rh);
|
||||
static Bool HandleCoRRE16(int rx, int ry, int rw, int rh);
|
||||
static Bool HandleCoRRE32(int rx, int ry, int rw, int rh);
|
||||
static Bool HandleHextile8(int rx, int ry, int rw, int rh);
|
||||
static Bool HandleHextile16(int rx, int ry, int rw, int rh);
|
||||
static Bool HandleHextile32(int rx, int ry, int rw, int rh);
|
||||
static Bool HandleZlib8(int rx, int ry, int rw, int rh);
|
||||
static Bool HandleZlib16(int rx, int ry, int rw, int rh);
|
||||
static Bool HandleZlib32(int rx, int ry, int rw, int rh);
|
||||
static Bool HandleTight8(int rx, int ry, int rw, int rh);
|
||||
static Bool HandleTight16(int rx, int ry, int rw, int rh);
|
||||
static Bool HandleTight32(int rx, int ry, int rw, int rh);
|
||||
|
||||
static long ReadCompactLen (void);
|
||||
|
||||
static void JpegInitSource(j_decompress_ptr cinfo);
|
||||
static boolean JpegFillInputBuffer(j_decompress_ptr cinfo);
|
||||
static void JpegSkipInputData(j_decompress_ptr cinfo, long num_bytes);
|
||||
static void JpegTermSource(j_decompress_ptr cinfo);
|
||||
static void JpegSetSrcManager(j_decompress_ptr cinfo, CARD8 *compressedData,
|
||||
int compressedLen);
|
||||
|
||||
|
||||
int rfbsock;
|
||||
char *desktopName;
|
||||
rfbPixelFormat myFormat;
|
||||
rfbServerInitMsg si;
|
||||
char *serverCutText = NULL;
|
||||
Bool newServerCutText = False;
|
||||
|
||||
int endianTest = 1;
|
||||
|
||||
|
||||
/* Note that the CoRRE encoding uses this buffer and assumes it is big enough
|
||||
to hold 255 * 255 * 32 bits -> 260100 bytes. 640*480 = 307200 bytes.
|
||||
Hextile also assumes it is big enough to hold 16 * 16 * 32 bits.
|
||||
Tight encoding assumes BUFFER_SIZE is at least 16384 bytes. */
|
||||
|
||||
#define BUFFER_SIZE (640*480)
|
||||
static char buffer[BUFFER_SIZE];
|
||||
|
||||
|
||||
/* The zlib encoding requires expansion/decompression/deflation of the
|
||||
compressed data in the "buffer" above into another, result buffer.
|
||||
However, the size of the result buffer can be determined precisely
|
||||
based on the bitsPerPixel, height and width of the rectangle. We
|
||||
allocate this buffer one time to be the full size of the buffer. */
|
||||
|
||||
static int raw_buffer_size = -1;
|
||||
static char *raw_buffer;
|
||||
|
||||
static z_stream decompStream;
|
||||
static Bool decompStreamInited = False;
|
||||
|
||||
|
||||
/*
|
||||
* Variables for the ``tight'' encoding implementation.
|
||||
*/
|
||||
|
||||
/* Separate buffer for compressed data. */
|
||||
#define ZLIB_BUFFER_SIZE 512
|
||||
static char zlib_buffer[ZLIB_BUFFER_SIZE];
|
||||
|
||||
/* Four independent compression streams for zlib library. */
|
||||
static z_stream zlibStream[4];
|
||||
static Bool zlibStreamActive[4] = {
|
||||
False, False, False, False
|
||||
};
|
||||
|
||||
/* Filter stuff. Should be initialized by filter initialization code. */
|
||||
static Bool cutZeros;
|
||||
static int rectWidth, rectColors;
|
||||
static char tightPalette[256*4];
|
||||
static CARD8 tightPrevRow[2048*3*sizeof(CARD16)];
|
||||
|
||||
/* JPEG decoder state. */
|
||||
static Bool jpegError;
|
||||
|
||||
|
||||
/*
|
||||
* ConnectToRFBServer.
|
||||
*/
|
||||
|
||||
Bool
|
||||
ConnectToRFBServer(const char *hostname, int port)
|
||||
{
|
||||
unsigned int host;
|
||||
|
||||
if (!StringToIPAddr(hostname, &host)) {
|
||||
fprintf(stderr,"Couldn't convert '%s' to host address\n", hostname);
|
||||
return False;
|
||||
}
|
||||
|
||||
rfbsock = ConnectToTcpAddr(host, port);
|
||||
|
||||
if (rfbsock < 0) {
|
||||
fprintf(stderr,"Unable to connect to VNC server\n");
|
||||
return False;
|
||||
}
|
||||
|
||||
return SetNonBlocking(rfbsock);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* InitialiseRFBConnection.
|
||||
*/
|
||||
|
||||
Bool
|
||||
InitialiseRFBConnection()
|
||||
{
|
||||
rfbProtocolVersionMsg pv;
|
||||
int major,minor;
|
||||
CARD32 authScheme, reasonLen, authResult;
|
||||
char *reason;
|
||||
CARD8 challenge[CHALLENGESIZE];
|
||||
char passwd[9];
|
||||
int i;
|
||||
rfbClientInitMsg ci;
|
||||
|
||||
/* if the connection is immediately closed, don't report anything, so
|
||||
that pmw's monitor can make test connections */
|
||||
|
||||
if (!ReadFromRFBServer(pv, sz_rfbProtocolVersionMsg)) return False;
|
||||
|
||||
errorMessageOnReadFailure = True;
|
||||
|
||||
pv[sz_rfbProtocolVersionMsg] = 0;
|
||||
|
||||
if (sscanf(pv,rfbProtocolVersionFormat,&major,&minor) != 2) {
|
||||
fprintf(stderr,"Not a valid VNC server\n");
|
||||
return False;
|
||||
}
|
||||
|
||||
fprintf(stderr,"VNC server supports protocol version %d.%d (viewer %d.%d)\n",
|
||||
major, minor, rfbProtocolMajorVersion, rfbProtocolMinorVersion);
|
||||
|
||||
major = rfbProtocolMajorVersion;
|
||||
minor = rfbProtocolMinorVersion;
|
||||
|
||||
sprintf(pv,rfbProtocolVersionFormat,major,minor);
|
||||
|
||||
if (!WriteExact(rfbsock, pv, sz_rfbProtocolVersionMsg)) return False;
|
||||
|
||||
if (!ReadFromRFBServer((char *)&authScheme, 4)) return False;
|
||||
|
||||
authScheme = Swap32IfLE(authScheme);
|
||||
|
||||
switch (authScheme) {
|
||||
|
||||
case rfbConnFailed:
|
||||
if (!ReadFromRFBServer((char *)&reasonLen, 4)) return False;
|
||||
reasonLen = Swap32IfLE(reasonLen);
|
||||
|
||||
reason = malloc(reasonLen);
|
||||
|
||||
if (!ReadFromRFBServer(reason, reasonLen)) return False;
|
||||
|
||||
fprintf(stderr,"VNC connection failed: %.*s\n",(int)reasonLen, reason);
|
||||
free(reason);
|
||||
return False;
|
||||
|
||||
case rfbNoAuth:
|
||||
fprintf(stderr,"No authentication needed\n");
|
||||
break;
|
||||
|
||||
case rfbVncAuth:
|
||||
if (!ReadFromRFBServer((char *)challenge, CHALLENGESIZE)) return False;
|
||||
|
||||
if (!getPassword(passwd, 8))
|
||||
return False;
|
||||
|
||||
passwd[8] = '\0';
|
||||
|
||||
vncEncryptBytes(challenge, passwd);
|
||||
|
||||
/* Lose the password from memory */
|
||||
for (i = strlen(passwd); i >= 0; i--) {
|
||||
passwd[i] = '\0';
|
||||
}
|
||||
|
||||
if (!WriteExact(rfbsock, (char *)challenge, CHALLENGESIZE)) return False;
|
||||
|
||||
if (!ReadFromRFBServer((char *)&authResult, 4)) return False;
|
||||
|
||||
authResult = Swap32IfLE(authResult);
|
||||
|
||||
switch (authResult) {
|
||||
case rfbVncAuthOK:
|
||||
fprintf(stderr,"VNC authentication succeeded\n");
|
||||
break;
|
||||
case rfbVncAuthFailed:
|
||||
fprintf(stderr,"VNC authentication failed\n");
|
||||
return False;
|
||||
case rfbVncAuthTooMany:
|
||||
fprintf(stderr,"VNC authentication failed - too many tries\n");
|
||||
return False;
|
||||
default:
|
||||
fprintf(stderr,"Unknown VNC authentication result: %d\n",
|
||||
(int)authResult);
|
||||
return False;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr,"Unknown authentication scheme from VNC server: %d\n",
|
||||
(int)authScheme);
|
||||
return False;
|
||||
}
|
||||
|
||||
ci.shared = (appData.shareDesktop ? 1 : 0);
|
||||
|
||||
if (!WriteExact(rfbsock, (char *)&ci, sz_rfbClientInitMsg)) return False;
|
||||
|
||||
if (!ReadFromRFBServer((char *)&si, sz_rfbServerInitMsg)) return False;
|
||||
|
||||
si.framebufferWidth = Swap16IfLE(si.framebufferWidth);
|
||||
si.framebufferHeight = Swap16IfLE(si.framebufferHeight);
|
||||
si.format.redMax = Swap16IfLE(si.format.redMax);
|
||||
si.format.greenMax = Swap16IfLE(si.format.greenMax);
|
||||
si.format.blueMax = Swap16IfLE(si.format.blueMax);
|
||||
si.nameLength = Swap32IfLE(si.nameLength);
|
||||
|
||||
desktopName = malloc(si.nameLength + 1);
|
||||
if (!desktopName) {
|
||||
fprintf(stderr, "Error allocating memory for desktop name, %lu bytes\n",
|
||||
(unsigned long)si.nameLength);
|
||||
return False;
|
||||
}
|
||||
|
||||
if (!ReadFromRFBServer(desktopName, si.nameLength)) return False;
|
||||
|
||||
desktopName[si.nameLength] = 0;
|
||||
|
||||
fprintf(stderr,"Desktop name \"%s\"\n",desktopName);
|
||||
|
||||
fprintf(stderr,"Connected to VNC server, using protocol version %d.%d\n",
|
||||
rfbProtocolMajorVersion, rfbProtocolMinorVersion);
|
||||
|
||||
fprintf(stderr,"VNC server default format:\n");
|
||||
PrintPixelFormat(&si.format);
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* SetFormatAndEncodings.
|
||||
*/
|
||||
|
||||
Bool
|
||||
SetFormatAndEncodings()
|
||||
{
|
||||
rfbSetPixelFormatMsg spf;
|
||||
char buf[sz_rfbSetEncodingsMsg + MAX_ENCODINGS * 4];
|
||||
rfbSetEncodingsMsg *se = (rfbSetEncodingsMsg *)buf;
|
||||
CARD32 *encs = (CARD32 *)(&buf[sz_rfbSetEncodingsMsg]);
|
||||
int len = 0;
|
||||
Bool requestCompressLevel = False;
|
||||
Bool requestQualityLevel = False;
|
||||
Bool requestLastRectEncoding = False;
|
||||
|
||||
spf.type = rfbSetPixelFormat;
|
||||
spf.format = myFormat;
|
||||
spf.format.redMax = Swap16IfLE(spf.format.redMax);
|
||||
spf.format.greenMax = Swap16IfLE(spf.format.greenMax);
|
||||
spf.format.blueMax = Swap16IfLE(spf.format.blueMax);
|
||||
|
||||
if (!WriteExact(rfbsock, (char *)&spf, sz_rfbSetPixelFormatMsg))
|
||||
return False;
|
||||
|
||||
se->type = rfbSetEncodings;
|
||||
se->nEncodings = 0;
|
||||
|
||||
if (appData.encodingsString) {
|
||||
const char *encStr = appData.encodingsString;
|
||||
int encStrLen;
|
||||
do {
|
||||
char *nextEncStr = strchr(encStr, ' ');
|
||||
if (nextEncStr) {
|
||||
encStrLen = nextEncStr - encStr;
|
||||
nextEncStr++;
|
||||
} else {
|
||||
encStrLen = strlen(encStr);
|
||||
}
|
||||
|
||||
if (strncasecmp(encStr,"raw",encStrLen) == 0) {
|
||||
encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRaw);
|
||||
} else if (strncasecmp(encStr,"copyrect",encStrLen) == 0) {
|
||||
encs[se->nEncodings++] = Swap32IfLE(rfbEncodingCopyRect);
|
||||
} else if (strncasecmp(encStr,"tight",encStrLen) == 0) {
|
||||
encs[se->nEncodings++] = Swap32IfLE(rfbEncodingTight);
|
||||
requestLastRectEncoding = True;
|
||||
if (appData.compressLevel >= 0 && appData.compressLevel <= 9)
|
||||
requestCompressLevel = True;
|
||||
if (appData.qualityLevel >= 0 && appData.qualityLevel <= 9)
|
||||
requestQualityLevel = True;
|
||||
} else if (strncasecmp(encStr,"hextile",encStrLen) == 0) {
|
||||
encs[se->nEncodings++] = Swap32IfLE(rfbEncodingHextile);
|
||||
} else if (strncasecmp(encStr,"zlib",encStrLen) == 0) {
|
||||
encs[se->nEncodings++] = Swap32IfLE(rfbEncodingZlib);
|
||||
if (appData.compressLevel >= 0 && appData.compressLevel <= 9)
|
||||
requestCompressLevel = True;
|
||||
} else if (strncasecmp(encStr,"corre",encStrLen) == 0) {
|
||||
encs[se->nEncodings++] = Swap32IfLE(rfbEncodingCoRRE);
|
||||
} else if (strncasecmp(encStr,"rre",encStrLen) == 0) {
|
||||
encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRRE);
|
||||
} else {
|
||||
fprintf(stderr,"Unknown encoding '%.*s'\n",encStrLen,encStr);
|
||||
}
|
||||
|
||||
encStr = nextEncStr;
|
||||
} while (encStr && se->nEncodings < MAX_ENCODINGS);
|
||||
|
||||
if (se->nEncodings < MAX_ENCODINGS && requestCompressLevel) {
|
||||
encs[se->nEncodings++] = Swap32IfLE(appData.compressLevel +
|
||||
rfbEncodingCompressLevel0);
|
||||
}
|
||||
|
||||
if (se->nEncodings < MAX_ENCODINGS && requestQualityLevel) {
|
||||
encs[se->nEncodings++] = Swap32IfLE(appData.qualityLevel +
|
||||
rfbEncodingQualityLevel0);
|
||||
}
|
||||
|
||||
if (appData.useRemoteCursor) {
|
||||
if (se->nEncodings < MAX_ENCODINGS)
|
||||
encs[se->nEncodings++] = Swap32IfLE(rfbEncodingXCursor);
|
||||
if (se->nEncodings < MAX_ENCODINGS)
|
||||
encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRichCursor);
|
||||
}
|
||||
|
||||
if (se->nEncodings < MAX_ENCODINGS && requestLastRectEncoding) {
|
||||
encs[se->nEncodings++] = Swap32IfLE(rfbEncodingLastRect);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (SameMachine(rfbsock)) {
|
||||
fprintf(stderr,"Same machine: preferring raw encoding\n");
|
||||
encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRaw);
|
||||
}
|
||||
|
||||
encs[se->nEncodings++] = Swap32IfLE(rfbEncodingCopyRect);
|
||||
encs[se->nEncodings++] = Swap32IfLE(rfbEncodingTight);
|
||||
encs[se->nEncodings++] = Swap32IfLE(rfbEncodingHextile);
|
||||
encs[se->nEncodings++] = Swap32IfLE(rfbEncodingZlib);
|
||||
encs[se->nEncodings++] = Swap32IfLE(rfbEncodingCoRRE);
|
||||
encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRRE);
|
||||
|
||||
if (appData.compressLevel >= 0 && appData.compressLevel <= 9) {
|
||||
encs[se->nEncodings++] = Swap32IfLE(appData.compressLevel +
|
||||
rfbEncodingCompressLevel0);
|
||||
}
|
||||
|
||||
if (appData.qualityLevel >= 0 && appData.qualityLevel <= 9) {
|
||||
encs[se->nEncodings++] = Swap32IfLE(appData.qualityLevel +
|
||||
rfbEncodingQualityLevel0);
|
||||
}
|
||||
|
||||
if (appData.useRemoteCursor) {
|
||||
encs[se->nEncodings++] = Swap32IfLE(rfbEncodingXCursor);
|
||||
encs[se->nEncodings++] = Swap32IfLE(rfbEncodingRichCursor);
|
||||
}
|
||||
|
||||
encs[se->nEncodings++] = Swap32IfLE(rfbEncodingLastRect);
|
||||
}
|
||||
|
||||
len = sz_rfbSetEncodingsMsg + se->nEncodings * 4;
|
||||
|
||||
se->nEncodings = Swap16IfLE(se->nEncodings);
|
||||
|
||||
if (!WriteExact(rfbsock, buf, len)) return False;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* SendIncrementalFramebufferUpdateRequest.
|
||||
* Note: this should only be called by the WriterThread
|
||||
*/
|
||||
|
||||
Bool
|
||||
SendIncrementalFramebufferUpdateRequest()
|
||||
{
|
||||
return SendFramebufferUpdateRequest(0, 0, si.framebufferWidth,
|
||||
si.framebufferHeight, True);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* SendFramebufferUpdateRequest.
|
||||
* Note: this should only be called by the WriterThread
|
||||
*/
|
||||
|
||||
Bool
|
||||
SendFramebufferUpdateRequest(int x, int y, int w, int h, Bool incremental)
|
||||
{
|
||||
rfbFramebufferUpdateRequestMsg fur;
|
||||
|
||||
fur.type = rfbFramebufferUpdateRequest;
|
||||
fur.incremental = incremental ? 1 : 0;
|
||||
fur.x = Swap16IfLE(x);
|
||||
fur.y = Swap16IfLE(y);
|
||||
fur.w = Swap16IfLE(w);
|
||||
fur.h = Swap16IfLE(h);
|
||||
|
||||
if (!WriteExact(rfbsock, (char *)&fur, sz_rfbFramebufferUpdateRequestMsg))
|
||||
return False;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* SendPointerEvent.
|
||||
* Note: this should only be called by the WriterThread
|
||||
*/
|
||||
|
||||
Bool
|
||||
SendPointerEvent(int x, int y, int buttonMask)
|
||||
{
|
||||
rfbPointerEventMsg pe;
|
||||
|
||||
pe.type = rfbPointerEvent;
|
||||
pe.buttonMask = buttonMask;
|
||||
if (x < 0) x = 0;
|
||||
if (y < 0) y = 0;
|
||||
SoftCursorMove(x, y);
|
||||
pe.x = Swap16IfLE(x);
|
||||
pe.y = Swap16IfLE(y);
|
||||
return WriteExact(rfbsock, (char *)&pe, sz_rfbPointerEventMsg);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* SendKeyEvent.
|
||||
* Note: this should only be called by the WriterThread
|
||||
*/
|
||||
|
||||
Bool
|
||||
SendKeyEvent(CARD32 key, Bool down)
|
||||
{
|
||||
rfbKeyEventMsg ke;
|
||||
|
||||
ke.type = rfbKeyEvent;
|
||||
ke.down = down ? 1 : 0;
|
||||
ke.key = Swap32IfLE(key);
|
||||
return WriteExact(rfbsock, (char *)&ke, sz_rfbKeyEventMsg);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* SendClientCutText.
|
||||
* Note: this should only be called by the WriterThread
|
||||
*/
|
||||
|
||||
Bool
|
||||
SendClientCutText(char *str, int len)
|
||||
{
|
||||
rfbClientCutTextMsg cct;
|
||||
|
||||
if (serverCutText)
|
||||
free(serverCutText);
|
||||
serverCutText = NULL;
|
||||
|
||||
cct.type = rfbClientCutText;
|
||||
cct.length = Swap32IfLE(len);
|
||||
return (WriteExact(rfbsock, (char *)&cct, sz_rfbClientCutTextMsg) &&
|
||||
WriteExact(rfbsock, str, len));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* HandleRFBServerMessage.
|
||||
*/
|
||||
|
||||
Bool
|
||||
HandleRFBServerMessage()
|
||||
{
|
||||
rfbServerToClientMsg msg;
|
||||
if (!ReadFromRFBServer((char *)&msg, 1))
|
||||
return False;
|
||||
|
||||
switch (msg.type) {
|
||||
|
||||
case rfbSetColourMapEntries:
|
||||
{
|
||||
int i;
|
||||
CARD16 rgb[3];
|
||||
XColor xc;
|
||||
|
||||
if (!ReadFromRFBServer(((char *)&msg) + 1,
|
||||
sz_rfbSetColourMapEntriesMsg - 1))
|
||||
return False;
|
||||
|
||||
msg.scme.firstColour = Swap16IfLE(msg.scme.firstColour);
|
||||
msg.scme.nColours = Swap16IfLE(msg.scme.nColours);
|
||||
|
||||
for (i = 0; i < msg.scme.nColours; i++) {
|
||||
if (!ReadFromRFBServer((char *)rgb, 6))
|
||||
return False;
|
||||
xc.pixel = msg.scme.firstColour + i;
|
||||
xc.red = Swap16IfLE(rgb[0]);
|
||||
xc.green = Swap16IfLE(rgb[1]);
|
||||
xc.blue = Swap16IfLE(rgb[2]);
|
||||
xc.flags = DoRed|DoGreen|DoBlue;
|
||||
lockQt();
|
||||
XStoreColor(dpy, cmap, &xc);
|
||||
unlockQt();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case rfbFramebufferUpdate:
|
||||
{
|
||||
rfbFramebufferUpdateRectHeader rect;
|
||||
int linesToRead;
|
||||
int bytesPerLine;
|
||||
int i;
|
||||
|
||||
if (!ReadFromRFBServer(((char *)&msg.fu) + 1,
|
||||
sz_rfbFramebufferUpdateMsg - 1))
|
||||
return False;
|
||||
|
||||
msg.fu.nRects = Swap16IfLE(msg.fu.nRects);
|
||||
|
||||
for (i = 0; i < msg.fu.nRects; i++) {
|
||||
if (!ReadFromRFBServer((char *)&rect, sz_rfbFramebufferUpdateRectHeader))
|
||||
return False;
|
||||
|
||||
rect.encoding = Swap32IfLE(rect.encoding);
|
||||
if (rect.encoding == rfbEncodingLastRect)
|
||||
break;
|
||||
|
||||
rect.r.x = Swap16IfLE(rect.r.x);
|
||||
rect.r.y = Swap16IfLE(rect.r.y);
|
||||
rect.r.w = Swap16IfLE(rect.r.w);
|
||||
rect.r.h = Swap16IfLE(rect.r.h);
|
||||
|
||||
if (rect.encoding == rfbEncodingXCursor) {
|
||||
if (!HandleXCursor(rect.r.x, rect.r.y, rect.r.w, rect.r.h)) {
|
||||
return False;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (rect.encoding == rfbEncodingRichCursor) {
|
||||
if (!HandleRichCursor(rect.r.x, rect.r.y, rect.r.w, rect.r.h)) {
|
||||
return False;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((rect.r.x + rect.r.w > si.framebufferWidth) ||
|
||||
(rect.r.y + rect.r.h > si.framebufferHeight))
|
||||
{
|
||||
fprintf(stderr,"Rect too large: %dx%d at (%d, %d)\n",
|
||||
rect.r.w, rect.r.h, rect.r.x, rect.r.y);
|
||||
return False;
|
||||
}
|
||||
|
||||
if (rect.r.h * rect.r.w == 0) {
|
||||
fprintf(stderr,"Zero size rect - ignoring\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If RichCursor encoding is used, we should prevent collisions
|
||||
between framebuffer updates and cursor drawing operations. */
|
||||
SoftCursorLockArea(rect.r.x, rect.r.y, rect.r.w, rect.r.h);
|
||||
|
||||
switch (rect.encoding) {
|
||||
|
||||
case rfbEncodingRaw:
|
||||
|
||||
bytesPerLine = rect.r.w * myFormat.bitsPerPixel / 8;
|
||||
linesToRead = BUFFER_SIZE / bytesPerLine;
|
||||
|
||||
while (rect.r.h > 0) {
|
||||
if (linesToRead > rect.r.h)
|
||||
linesToRead = rect.r.h;
|
||||
|
||||
if (!ReadFromRFBServer(buffer,bytesPerLine * linesToRead))
|
||||
return False;
|
||||
|
||||
CopyDataToScreen(buffer, rect.r.x, rect.r.y, rect.r.w,
|
||||
linesToRead);
|
||||
|
||||
rect.r.h -= linesToRead;
|
||||
rect.r.y += linesToRead;
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case rfbEncodingCopyRect:
|
||||
{
|
||||
rfbCopyRect cr;
|
||||
|
||||
if (!ReadFromRFBServer((char *)&cr, sz_rfbCopyRect))
|
||||
return False;
|
||||
|
||||
cr.srcX = Swap16IfLE(cr.srcX);
|
||||
cr.srcY = Swap16IfLE(cr.srcY);
|
||||
|
||||
/* If RichCursor encoding is used, we should extend our
|
||||
"cursor lock area" (previously set to destination
|
||||
rectangle) to the source rectangle as well. */
|
||||
SoftCursorLockArea(cr.srcX, cr.srcY, rect.r.w, rect.r.h);
|
||||
|
||||
lockQt();
|
||||
if (appData.copyRectDelay != 0) {
|
||||
XFillRectangle(dpy, desktopWin, srcGC, cr.srcX, cr.srcY,
|
||||
rect.r.w, rect.r.h);
|
||||
XFillRectangle(dpy, desktopWin, dstGC, rect.r.x, rect.r.y,
|
||||
rect.r.w, rect.r.h);
|
||||
XSync(dpy,False);
|
||||
|
||||
unlockQt();
|
||||
usleep(appData.copyRectDelay * 1000);
|
||||
lockQt();
|
||||
|
||||
XFillRectangle(dpy, desktopWin, dstGC, rect.r.x, rect.r.y,
|
||||
rect.r.w, rect.r.h);
|
||||
XFillRectangle(dpy, desktopWin, srcGC, cr.srcX, cr.srcY,
|
||||
rect.r.w, rect.r.h);
|
||||
}
|
||||
|
||||
XCopyArea(dpy, desktopWin, desktopWin, gc, cr.srcX, cr.srcY,
|
||||
rect.r.w, rect.r.h, rect.r.x, rect.r.y);
|
||||
unlockQt();
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case rfbEncodingRRE:
|
||||
{
|
||||
switch (myFormat.bitsPerPixel) {
|
||||
case 8:
|
||||
if (!HandleRRE8(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
|
||||
return False;
|
||||
break;
|
||||
case 16:
|
||||
if (!HandleRRE16(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
|
||||
return False;
|
||||
break;
|
||||
case 32:
|
||||
if (!HandleRRE32(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
|
||||
return False;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case rfbEncodingCoRRE:
|
||||
{
|
||||
switch (myFormat.bitsPerPixel) {
|
||||
case 8:
|
||||
if (!HandleCoRRE8(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
|
||||
return False;
|
||||
break;
|
||||
case 16:
|
||||
if (!HandleCoRRE16(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
|
||||
return False;
|
||||
break;
|
||||
case 32:
|
||||
if (!HandleCoRRE32(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
|
||||
return False;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case rfbEncodingHextile:
|
||||
{
|
||||
switch (myFormat.bitsPerPixel) {
|
||||
case 8:
|
||||
if (!HandleHextile8(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
|
||||
return False;
|
||||
break;
|
||||
case 16:
|
||||
if (!HandleHextile16(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
|
||||
return False;
|
||||
break;
|
||||
case 32:
|
||||
if (!HandleHextile32(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
|
||||
return False;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case rfbEncodingZlib:
|
||||
{
|
||||
switch (myFormat.bitsPerPixel) {
|
||||
case 8:
|
||||
if (!HandleZlib8(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
|
||||
return False;
|
||||
break;
|
||||
case 16:
|
||||
if (!HandleZlib16(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
|
||||
return False;
|
||||
break;
|
||||
case 32:
|
||||
if (!HandleZlib32(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
|
||||
return False;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case rfbEncodingTight:
|
||||
{
|
||||
switch (myFormat.bitsPerPixel) {
|
||||
case 8:
|
||||
if (!HandleTight8(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
|
||||
return False;
|
||||
break;
|
||||
case 16:
|
||||
if (!HandleTight16(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
|
||||
return False;
|
||||
break;
|
||||
case 32:
|
||||
if (!HandleTight32(rect.r.x,rect.r.y,rect.r.w,rect.r.h))
|
||||
return False;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
fprintf(stderr,"Unknown rect encoding %d\n",
|
||||
(int)rect.encoding);
|
||||
return False;
|
||||
}
|
||||
|
||||
/* Now we may discard "soft cursor locks". */
|
||||
SoftCursorUnlockScreen();
|
||||
}
|
||||
|
||||
/* if using shared memory PutImage, make sure that the X server has
|
||||
updated its framebuffer before we reuse the shared memory. This is
|
||||
mainly to avoid copyrect using invalid screen contents - not sure
|
||||
if we'd need it otherwise. */
|
||||
ShmSync();
|
||||
|
||||
queueIncrementalUpdateRequest();
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case rfbBell:
|
||||
{
|
||||
Window toplevelWin;
|
||||
fprintf(stderr, "tugce bell\n");
|
||||
lockQt();
|
||||
XBell(dpy, 0);
|
||||
unlockQt();
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case rfbServerCutText:
|
||||
{
|
||||
fprintf(stderr, "tugce cut\n");
|
||||
if (!ReadFromRFBServer(((char *)&msg) + 1,
|
||||
sz_rfbServerCutTextMsg - 1))
|
||||
return False;
|
||||
|
||||
msg.sct.length = Swap32IfLE(msg.sct.length);
|
||||
|
||||
if (serverCutText)
|
||||
free(serverCutText);
|
||||
|
||||
serverCutText = malloc(msg.sct.length+1);
|
||||
|
||||
if (!ReadFromRFBServer(serverCutText, msg.sct.length))
|
||||
return False;
|
||||
|
||||
serverCutText[msg.sct.length] = 0;
|
||||
|
||||
newServerCutText = True;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
fprintf(stderr,"Unknown message type %d from VNC server\n",msg.type);
|
||||
return False;
|
||||
}
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
|
||||
#define GET_PIXEL8(pix, ptr) ((pix) = *(ptr)++)
|
||||
|
||||
#define GET_PIXEL16(pix, ptr) (((CARD8*)&(pix))[0] = *(ptr)++, \
|
||||
((CARD8*)&(pix))[1] = *(ptr)++)
|
||||
|
||||
#define GET_PIXEL32(pix, ptr) (((CARD8*)&(pix))[0] = *(ptr)++, \
|
||||
((CARD8*)&(pix))[1] = *(ptr)++, \
|
||||
((CARD8*)&(pix))[2] = *(ptr)++, \
|
||||
((CARD8*)&(pix))[3] = *(ptr)++)
|
||||
|
||||
/* CONCAT2 concatenates its two arguments. CONCAT2E does the same but also
|
||||
expands its arguments if they are macros */
|
||||
|
||||
#define CONCAT2(a,b) a##b
|
||||
#define CONCAT2E(a,b) CONCAT2(a,b)
|
||||
|
||||
#define BPP 8
|
||||
#include "rre.c"
|
||||
#include "corre.c"
|
||||
#include "hextile.c"
|
||||
#include "zlib.c"
|
||||
#include "tight.c"
|
||||
#undef BPP
|
||||
#define BPP 16
|
||||
#include "rre.c"
|
||||
#include "corre.c"
|
||||
#include "hextile.c"
|
||||
#include "zlib.c"
|
||||
#include "tight.c"
|
||||
#undef BPP
|
||||
#define BPP 32
|
||||
#include "rre.c"
|
||||
#include "corre.c"
|
||||
#include "hextile.c"
|
||||
#include "zlib.c"
|
||||
#include "tight.c"
|
||||
#undef BPP
|
||||
|
||||
|
||||
/*
|
||||
* PrintPixelFormat.
|
||||
*/
|
||||
|
||||
void
|
||||
PrintPixelFormat(format)
|
||||
rfbPixelFormat *format;
|
||||
{
|
||||
if (format->bitsPerPixel == 1) {
|
||||
fprintf(stderr," Single bit per pixel.\n");
|
||||
fprintf(stderr,
|
||||
" %s significant bit in each byte is leftmost on the screen.\n",
|
||||
(format->bigEndian ? "Most" : "Least"));
|
||||
} else {
|
||||
fprintf(stderr," %d bits per pixel.\n",format->bitsPerPixel);
|
||||
if (format->bitsPerPixel != 8) {
|
||||
fprintf(stderr," %s significant byte first in each pixel.\n",
|
||||
(format->bigEndian ? "Most" : "Least"));
|
||||
}
|
||||
if (format->trueColour) {
|
||||
fprintf(stderr," True colour: max red %d green %d blue %d",
|
||||
format->redMax, format->greenMax, format->blueMax);
|
||||
fprintf(stderr,", shift red %d green %d blue %d\n",
|
||||
format->redShift, format->greenShift, format->blueShift);
|
||||
} else {
|
||||
fprintf(stderr," Colour map (not true colour).\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static long
|
||||
ReadCompactLen (void)
|
||||
{
|
||||
long len;
|
||||
CARD8 b;
|
||||
|
||||
if (!ReadFromRFBServer((char *)&b, 1))
|
||||
return -1;
|
||||
len = (int)b & 0x7F;
|
||||
if (b & 0x80) {
|
||||
if (!ReadFromRFBServer((char *)&b, 1))
|
||||
return -1;
|
||||
len |= ((int)b & 0x7F) << 7;
|
||||
if (b & 0x80) {
|
||||
if (!ReadFromRFBServer((char *)&b, 1))
|
||||
return -1;
|
||||
len |= ((int)b & 0xFF) << 14;
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
* JPEG source manager functions for JPEG decompression in Tight decoder.
|
||||
*/
|
||||
|
||||
static struct jpeg_source_mgr jpegSrcManager;
|
||||
static JOCTET *jpegBufferPtr;
|
||||
static size_t jpegBufferLen;
|
||||
|
||||
static void
|
||||
JpegInitSource(j_decompress_ptr cinfo)
|
||||
{
|
||||
jpegError = False;
|
||||
}
|
||||
|
||||
static boolean
|
||||
JpegFillInputBuffer(j_decompress_ptr cinfo)
|
||||
{
|
||||
jpegError = True;
|
||||
jpegSrcManager.bytes_in_buffer = jpegBufferLen;
|
||||
jpegSrcManager.next_input_byte = (JOCTET *)jpegBufferPtr;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
JpegSkipInputData(j_decompress_ptr cinfo, long num_bytes)
|
||||
{
|
||||
if (num_bytes < 0 || num_bytes > jpegSrcManager.bytes_in_buffer) {
|
||||
jpegError = True;
|
||||
jpegSrcManager.bytes_in_buffer = jpegBufferLen;
|
||||
jpegSrcManager.next_input_byte = (JOCTET *)jpegBufferPtr;
|
||||
} else {
|
||||
jpegSrcManager.next_input_byte += (size_t) num_bytes;
|
||||
jpegSrcManager.bytes_in_buffer -= (size_t) num_bytes;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
JpegTermSource(j_decompress_ptr cinfo)
|
||||
{
|
||||
/* No work necessary here. */
|
||||
}
|
||||
|
||||
static void
|
||||
JpegSetSrcManager(j_decompress_ptr cinfo, CARD8 *compressedData,
|
||||
int compressedLen)
|
||||
{
|
||||
jpegBufferPtr = (JOCTET *)compressedData;
|
||||
jpegBufferLen = (size_t)compressedLen;
|
||||
|
||||
jpegSrcManager.init_source = JpegInitSource;
|
||||
jpegSrcManager.fill_input_buffer = JpegFillInputBuffer;
|
||||
jpegSrcManager.skip_input_data = JpegSkipInputData;
|
||||
jpegSrcManager.resync_to_restart = jpeg_resync_to_restart;
|
||||
jpegSrcManager.term_source = JpegTermSource;
|
||||
jpegSrcManager.next_input_byte = jpegBufferPtr;
|
||||
jpegSrcManager.bytes_in_buffer = jpegBufferLen;
|
||||
|
||||
cinfo->src = &jpegSrcManager;
|
||||
}
|
||||
|
|
@ -1,785 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2000, 2001 Const Kaplinsky. All Rights Reserved.
|
||||
* Copyright (C) 2000 Tridia Corporation. All Rights Reserved.
|
||||
* Copyright (C) 1999 AT&T Laboratories Cambridge. 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* rfbproto.h - header file for the RFB protocol version 3.3
|
||||
*
|
||||
* Uses types CARD<n> for an n-bit unsigned integer, INT<n> for an n-bit signed
|
||||
* integer (for n = 8, 16 and 32).
|
||||
*
|
||||
* All multiple byte integers are in big endian (network) order (most
|
||||
* significant byte first). Unless noted otherwise there is no special
|
||||
* alignment of protocol structures.
|
||||
*
|
||||
*
|
||||
* Once the initial handshaking is done, all messages start with a type byte,
|
||||
* (usually) followed by message-specific data. The order of definitions in
|
||||
* this file is as follows:
|
||||
*
|
||||
* (1) Structures used in several types of message.
|
||||
* (2) Structures used in the initial handshaking.
|
||||
* (3) Message types.
|
||||
* (4) Encoding types.
|
||||
* (5) For each message type, the form of the data following the type byte.
|
||||
* Sometimes this is defined by a single structure but the more complex
|
||||
* messages have to be explained by comments.
|
||||
*/
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Structures used in several messages
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* Structure used to specify a rectangle. This structure is a multiple of 4
|
||||
* bytes so that it can be interspersed with 32-bit pixel data without
|
||||
* affecting alignment.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
CARD16 x;
|
||||
CARD16 y;
|
||||
CARD16 w;
|
||||
CARD16 h;
|
||||
} rfbRectangle;
|
||||
|
||||
#define sz_rfbRectangle 8
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* Structure used to specify pixel format.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
|
||||
CARD8 bitsPerPixel; /* 8,16,32 only */
|
||||
|
||||
CARD8 depth; /* 8 to 32 */
|
||||
|
||||
CARD8 bigEndian; /* True if multi-byte pixels are interpreted
|
||||
as big endian, or if single-bit-per-pixel
|
||||
has most significant bit of the byte
|
||||
corresponding to first (leftmost) pixel. Of
|
||||
course this is meaningless for 8 bits/pix */
|
||||
|
||||
CARD8 trueColour; /* If false then we need a "colour map" to
|
||||
convert pixels to RGB. If true, xxxMax and
|
||||
xxxShift specify bits used for red, green
|
||||
and blue */
|
||||
|
||||
/* the following fields are only meaningful if trueColour is true */
|
||||
|
||||
CARD16 redMax; /* maximum red value (= 2^n - 1 where n is the
|
||||
number of bits used for red). Note this
|
||||
value is always in big endian order. */
|
||||
|
||||
CARD16 greenMax; /* similar for green */
|
||||
|
||||
CARD16 blueMax; /* and blue */
|
||||
|
||||
CARD8 redShift; /* number of shifts needed to get the red
|
||||
value in a pixel to the least significant
|
||||
bit. To find the red value from a given
|
||||
pixel, do the following:
|
||||
1) Swap pixel value according to bigEndian
|
||||
(e.g. if bigEndian is false and host byte
|
||||
order is big endian, then swap).
|
||||
2) Shift right by redShift.
|
||||
3) AND with redMax (in host byte order).
|
||||
4) You now have the red value between 0 and
|
||||
redMax. */
|
||||
|
||||
CARD8 greenShift; /* similar for green */
|
||||
|
||||
CARD8 blueShift; /* and blue */
|
||||
|
||||
CARD8 pad1;
|
||||
CARD16 pad2;
|
||||
|
||||
} rfbPixelFormat;
|
||||
|
||||
#define sz_rfbPixelFormat 16
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Initial handshaking messages
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* Protocol Version
|
||||
*
|
||||
* The server always sends 12 bytes to start which identifies the latest RFB
|
||||
* protocol version number which it supports. These bytes are interpreted
|
||||
* as a string of 12 ASCII characters in the format "RFB xxx.yyy\n" where
|
||||
* xxx and yyy are the major and minor version numbers (for version 3.3
|
||||
* this is "RFB 003.003\n").
|
||||
*
|
||||
* The client then replies with a similar 12-byte message giving the version
|
||||
* number of the protocol which should actually be used (which may be different
|
||||
* to that quoted by the server).
|
||||
*
|
||||
* It is intended that both clients and servers may provide some level of
|
||||
* backwards compatibility by this mechanism. Servers in particular should
|
||||
* attempt to provide backwards compatibility, and even forwards compatibility
|
||||
* to some extent. For example if a client demands version 3.1 of the
|
||||
* protocol, a 3.0 server can probably assume that by ignoring requests for
|
||||
* encoding types it doesn't understand, everything will still work OK. This
|
||||
* will probably not be the case for changes in the major version number.
|
||||
*
|
||||
* The format string below can be used in sprintf or sscanf to generate or
|
||||
* decode the version string respectively.
|
||||
*/
|
||||
|
||||
#define rfbProtocolVersionFormat "RFB %03d.%03d\n"
|
||||
#define rfbProtocolMajorVersion 3
|
||||
#define rfbProtocolMinorVersion 3
|
||||
|
||||
typedef char rfbProtocolVersionMsg[13]; /* allow extra byte for null */
|
||||
|
||||
#define sz_rfbProtocolVersionMsg 12
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* Authentication
|
||||
*
|
||||
* Once the protocol version has been decided, the server then sends a 32-bit
|
||||
* word indicating whether any authentication is needed on the connection.
|
||||
* The value of this word determines the authentication scheme in use. For
|
||||
* version 3.0 of the protocol this may have one of the following values:
|
||||
*/
|
||||
|
||||
#define rfbConnFailed 0
|
||||
#define rfbNoAuth 1
|
||||
#define rfbVncAuth 2
|
||||
|
||||
/*
|
||||
* rfbConnFailed: For some reason the connection failed (e.g. the server
|
||||
* cannot support the desired protocol version). This is
|
||||
* followed by a string describing the reason (where a
|
||||
* string is specified as a 32-bit length followed by that
|
||||
* many ASCII characters).
|
||||
*
|
||||
* rfbNoAuth: No authentication is needed.
|
||||
*
|
||||
* rfbVncAuth: The VNC authentication scheme is to be used. A 16-byte
|
||||
* challenge follows, which the client encrypts as
|
||||
* appropriate using the password and sends the resulting
|
||||
* 16-byte response. If the response is correct, the
|
||||
* server sends the 32-bit word rfbVncAuthOK. If a simple
|
||||
* failure happens, the server sends rfbVncAuthFailed and
|
||||
* closes the connection. If the server decides that too
|
||||
* many failures have occurred, it sends rfbVncAuthTooMany
|
||||
* and closes the connection. In the latter case, the
|
||||
* server should not allow an immediate reconnection by
|
||||
* the client.
|
||||
*/
|
||||
|
||||
#define rfbVncAuthOK 0
|
||||
#define rfbVncAuthFailed 1
|
||||
#define rfbVncAuthTooMany 2
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* Client Initialisation Message
|
||||
*
|
||||
* Once the client and server are sure that they're happy to talk to one
|
||||
* another, the client sends an initialisation message. At present this
|
||||
* message only consists of a boolean indicating whether the server should try
|
||||
* to share the desktop by leaving other clients connected, or give exclusive
|
||||
* access to this client by disconnecting all other clients.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
CARD8 shared;
|
||||
} rfbClientInitMsg;
|
||||
|
||||
#define sz_rfbClientInitMsg 1
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* Server Initialisation Message
|
||||
*
|
||||
* After the client initialisation message, the server sends one of its own.
|
||||
* This tells the client the width and height of the server's framebuffer,
|
||||
* its pixel format and the name associated with the desktop.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
CARD16 framebufferWidth;
|
||||
CARD16 framebufferHeight;
|
||||
rfbPixelFormat format; /* the server's preferred pixel format */
|
||||
CARD32 nameLength;
|
||||
/* followed by char name[nameLength] */
|
||||
} rfbServerInitMsg;
|
||||
|
||||
#define sz_rfbServerInitMsg (8 + sz_rfbPixelFormat)
|
||||
|
||||
|
||||
/*
|
||||
* Following the server initialisation message it's up to the client to send
|
||||
* whichever protocol messages it wants. Typically it will send a
|
||||
* SetPixelFormat message and a SetEncodings message, followed by a
|
||||
* FramebufferUpdateRequest. From then on the server will send
|
||||
* FramebufferUpdate messages in response to the client's
|
||||
* FramebufferUpdateRequest messages. The client should send
|
||||
* FramebufferUpdateRequest messages with incremental set to true when it has
|
||||
* finished processing one FramebufferUpdate and is ready to process another.
|
||||
* With a fast client, the rate at which FramebufferUpdateRequests are sent
|
||||
* should be regulated to avoid hogging the network.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Message types
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/* server -> client */
|
||||
|
||||
#define rfbFramebufferUpdate 0
|
||||
#define rfbSetColourMapEntries 1
|
||||
#define rfbBell 2
|
||||
#define rfbServerCutText 3
|
||||
|
||||
|
||||
/* client -> server */
|
||||
|
||||
#define rfbSetPixelFormat 0
|
||||
#define rfbFixColourMapEntries 1 /* not currently supported */
|
||||
#define rfbSetEncodings 2
|
||||
#define rfbFramebufferUpdateRequest 3
|
||||
#define rfbKeyEvent 4
|
||||
#define rfbPointerEvent 5
|
||||
#define rfbClientCutText 6
|
||||
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Encoding types
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#define rfbEncodingRaw 0
|
||||
#define rfbEncodingCopyRect 1
|
||||
#define rfbEncodingRRE 2
|
||||
#define rfbEncodingCoRRE 4
|
||||
#define rfbEncodingHextile 5
|
||||
#define rfbEncodingZlib 6
|
||||
#define rfbEncodingTight 7
|
||||
#define rfbEncodingZlibHex 8
|
||||
|
||||
/*
|
||||
* Special encoding numbers:
|
||||
* 0xFFFFFF00 .. 0xFFFFFF0F -- encoding-specific compression levels;
|
||||
* 0xFFFFFF10 .. 0xFFFFFF1F -- mouse cursor shape data;
|
||||
* 0xFFFFFF20 .. 0xFFFFFF2F -- various protocol extensions;
|
||||
* 0xFFFFFF30 .. 0xFFFFFFDF -- not allocated yet;
|
||||
* 0xFFFFFFE0 .. 0xFFFFFFEF -- quality level for JPEG compressor;
|
||||
* 0xFFFFFFF0 .. 0xFFFFFFFF -- cross-encoding compression levels.
|
||||
*/
|
||||
|
||||
#define rfbEncodingCompressLevel0 0xFFFFFF00
|
||||
#define rfbEncodingCompressLevel1 0xFFFFFF01
|
||||
#define rfbEncodingCompressLevel2 0xFFFFFF02
|
||||
#define rfbEncodingCompressLevel3 0xFFFFFF03
|
||||
#define rfbEncodingCompressLevel4 0xFFFFFF04
|
||||
#define rfbEncodingCompressLevel5 0xFFFFFF05
|
||||
#define rfbEncodingCompressLevel6 0xFFFFFF06
|
||||
#define rfbEncodingCompressLevel7 0xFFFFFF07
|
||||
#define rfbEncodingCompressLevel8 0xFFFFFF08
|
||||
#define rfbEncodingCompressLevel9 0xFFFFFF09
|
||||
|
||||
#define rfbEncodingXCursor 0xFFFFFF10
|
||||
#define rfbEncodingRichCursor 0xFFFFFF11
|
||||
|
||||
#define rfbEncodingLastRect 0xFFFFFF20
|
||||
|
||||
#define rfbEncodingQualityLevel0 0xFFFFFFE0
|
||||
#define rfbEncodingQualityLevel1 0xFFFFFFE1
|
||||
#define rfbEncodingQualityLevel2 0xFFFFFFE2
|
||||
#define rfbEncodingQualityLevel3 0xFFFFFFE3
|
||||
#define rfbEncodingQualityLevel4 0xFFFFFFE4
|
||||
#define rfbEncodingQualityLevel5 0xFFFFFFE5
|
||||
#define rfbEncodingQualityLevel6 0xFFFFFFE6
|
||||
#define rfbEncodingQualityLevel7 0xFFFFFFE7
|
||||
#define rfbEncodingQualityLevel8 0xFFFFFFE8
|
||||
#define rfbEncodingQualityLevel9 0xFFFFFFE9
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Server -> client message definitions
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* FramebufferUpdate - a block of rectangles to be copied to the framebuffer.
|
||||
*
|
||||
* This message consists of a header giving the number of rectangles of pixel
|
||||
* data followed by the rectangles themselves. The header is padded so that
|
||||
* together with the type byte it is an exact multiple of 4 bytes (to help
|
||||
* with alignment of 32-bit pixels):
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
CARD8 type; /* always rfbFramebufferUpdate */
|
||||
CARD8 pad;
|
||||
CARD16 nRects;
|
||||
/* followed by nRects rectangles */
|
||||
} rfbFramebufferUpdateMsg;
|
||||
|
||||
#define sz_rfbFramebufferUpdateMsg 4
|
||||
|
||||
/*
|
||||
* Each rectangle of pixel data consists of a header describing the position
|
||||
* and size of the rectangle and a type word describing the encoding of the
|
||||
* pixel data, followed finally by the pixel data. Note that if the client has
|
||||
* not sent a SetEncodings message then it will only receive raw pixel data.
|
||||
* Also note again that this structure is a multiple of 4 bytes.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
rfbRectangle r;
|
||||
CARD32 encoding; /* one of the encoding types rfbEncoding... */
|
||||
} rfbFramebufferUpdateRectHeader;
|
||||
|
||||
#define sz_rfbFramebufferUpdateRectHeader (sz_rfbRectangle + 4)
|
||||
|
||||
|
||||
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
* Raw Encoding. Pixels are sent in top-to-bottom scanline order,
|
||||
* left-to-right within a scanline with no padding in between.
|
||||
*/
|
||||
|
||||
|
||||
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
* CopyRect Encoding. The pixels are specified simply by the x and y position
|
||||
* of the source rectangle.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
CARD16 srcX;
|
||||
CARD16 srcY;
|
||||
} rfbCopyRect;
|
||||
|
||||
#define sz_rfbCopyRect 4
|
||||
|
||||
|
||||
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
* RRE - Rise-and-Run-length Encoding. We have an rfbRREHeader structure
|
||||
* giving the number of subrectangles following. Finally the data follows in
|
||||
* the form [<bgpixel><subrect><subrect>...] where each <subrect> is
|
||||
* [<pixel><rfbRectangle>].
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
CARD32 nSubrects;
|
||||
} rfbRREHeader;
|
||||
|
||||
#define sz_rfbRREHeader 4
|
||||
|
||||
|
||||
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
* CoRRE - Compact RRE Encoding. We have an rfbRREHeader structure giving
|
||||
* the number of subrectangles following. Finally the data follows in the form
|
||||
* [<bgpixel><subrect><subrect>...] where each <subrect> is
|
||||
* [<pixel><rfbCoRRERectangle>]. This means that
|
||||
* the whole rectangle must be at most 255x255 pixels.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
CARD8 x;
|
||||
CARD8 y;
|
||||
CARD8 w;
|
||||
CARD8 h;
|
||||
} rfbCoRRERectangle;
|
||||
|
||||
#define sz_rfbCoRRERectangle 4
|
||||
|
||||
|
||||
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
* Hextile Encoding. The rectangle is divided up into "tiles" of 16x16 pixels,
|
||||
* starting at the top left going in left-to-right, top-to-bottom order. If
|
||||
* the width of the rectangle is not an exact multiple of 16 then the width of
|
||||
* the last tile in each row will be correspondingly smaller. Similarly if the
|
||||
* height is not an exact multiple of 16 then the height of each tile in the
|
||||
* final row will also be smaller. Each tile begins with a "subencoding" type
|
||||
* byte, which is a mask made up of a number of bits. If the Raw bit is set
|
||||
* then the other bits are irrelevant; w*h pixel values follow (where w and h
|
||||
* are the width and height of the tile). Otherwise the tile is encoded in a
|
||||
* similar way to RRE, except that the position and size of each subrectangle
|
||||
* can be specified in just two bytes. The other bits in the mask are as
|
||||
* follows:
|
||||
*
|
||||
* BackgroundSpecified - if set, a pixel value follows which specifies
|
||||
* the background colour for this tile. The first non-raw tile in a
|
||||
* rectangle must have this bit set. If this bit isn't set then the
|
||||
* background is the same as the last tile.
|
||||
*
|
||||
* ForegroundSpecified - if set, a pixel value follows which specifies
|
||||
* the foreground colour to be used for all subrectangles in this tile.
|
||||
* If this bit is set then the SubrectsColoured bit must be zero.
|
||||
*
|
||||
* AnySubrects - if set, a single byte follows giving the number of
|
||||
* subrectangles following. If not set, there are no subrectangles (i.e.
|
||||
* the whole tile is just solid background colour).
|
||||
*
|
||||
* SubrectsColoured - if set then each subrectangle is preceded by a pixel
|
||||
* value giving the colour of that subrectangle. If not set, all
|
||||
* subrectangles are the same colour, the foreground colour; if the
|
||||
* ForegroundSpecified bit wasn't set then the foreground is the same as
|
||||
* the last tile.
|
||||
*
|
||||
* The position and size of each subrectangle is specified in two bytes. The
|
||||
* Pack macros below can be used to generate the two bytes from x, y, w, h,
|
||||
* and the Extract macros can be used to extract the x, y, w, h values from
|
||||
* the two bytes.
|
||||
*/
|
||||
|
||||
#define rfbHextileRaw (1 << 0)
|
||||
#define rfbHextileBackgroundSpecified (1 << 1)
|
||||
#define rfbHextileForegroundSpecified (1 << 2)
|
||||
#define rfbHextileAnySubrects (1 << 3)
|
||||
#define rfbHextileSubrectsColoured (1 << 4)
|
||||
|
||||
#define rfbHextilePackXY(x,y) (((x) << 4) | (y))
|
||||
#define rfbHextilePackWH(w,h) ((((w)-1) << 4) | ((h)-1))
|
||||
#define rfbHextileExtractX(byte) ((byte) >> 4)
|
||||
#define rfbHextileExtractY(byte) ((byte) & 0xf)
|
||||
#define rfbHextileExtractW(byte) (((byte) >> 4) + 1)
|
||||
#define rfbHextileExtractH(byte) (((byte) & 0xf) + 1)
|
||||
|
||||
|
||||
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
* zlib - zlib compressed Encoding. We have an rfbZlibHeader structure
|
||||
* giving the number of bytes following. Finally the data follows is
|
||||
* zlib compressed version of the raw pixel data as negotiated.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
CARD32 nBytes;
|
||||
} rfbZlibHeader;
|
||||
|
||||
#define sz_rfbZlibHeader 4
|
||||
|
||||
|
||||
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
* Tight Encoding. FIXME: Add more documentation.
|
||||
*/
|
||||
|
||||
#define rfbTightExplicitFilter 0x04
|
||||
#define rfbTightFill 0x08
|
||||
#define rfbTightJpeg 0x09
|
||||
#define rfbTightMaxSubencoding 0x09
|
||||
|
||||
/* Filters to improve compression efficiency */
|
||||
#define rfbTightFilterCopy 0x00
|
||||
#define rfbTightFilterPalette 0x01
|
||||
#define rfbTightFilterGradient 0x02
|
||||
|
||||
|
||||
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
* XCursor encoding. This is a special encoding used to transmit X-style
|
||||
* cursor shapes from server to clients. Note that for this encoding,
|
||||
* coordinates in rfbFramebufferUpdateRectHeader structure hold hotspot
|
||||
* position (r.x, r.y) and cursor size (r.w, r.h). If (w * h != 0), two RGB
|
||||
* samples are sent after header in the rfbXCursorColors structure. They
|
||||
* denote foreground and background colors of the cursor. If a client
|
||||
* supports only black-and-white cursors, it should ignore these colors and
|
||||
* assume that foreground is black and background is white. Next, two bitmaps
|
||||
* (1 bits per pixel) follow: first one with actual data (value 0 denotes
|
||||
* background color, value 1 denotes foreground color), second one with
|
||||
* transparency data (bits with zero value mean that these pixels are
|
||||
* transparent). Both bitmaps represent cursor data in a byte stream, from
|
||||
* left to right, from top to bottom, and each row is byte-aligned. Most
|
||||
* significant bits correspond to leftmost pixels. The number of bytes in
|
||||
* each row can be calculated as ((w + 7) / 8). If (w * h == 0), cursor
|
||||
* should be hidden (or default local cursor should be set by the client).
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
CARD8 foreRed;
|
||||
CARD8 foreGreen;
|
||||
CARD8 foreBlue;
|
||||
CARD8 backRed;
|
||||
CARD8 backGreen;
|
||||
CARD8 backBlue;
|
||||
} rfbXCursorColors;
|
||||
|
||||
#define sz_rfbXCursorColors 6
|
||||
|
||||
|
||||
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
* RichCursor encoding. This is a special encoding used to transmit cursor
|
||||
* shapes from server to clients. It is similar to the XCursor encoding but
|
||||
* uses client pixel format instead of two RGB colors to represent cursor
|
||||
* image. For this encoding, coordinates in rfbFramebufferUpdateRectHeader
|
||||
* structure hold hotspot position (r.x, r.y) and cursor size (r.w, r.h).
|
||||
* After header, two pixmaps follow: first one with cursor image in current
|
||||
* client pixel format (like in raw encoding), second with transparency data
|
||||
* (1 bit per pixel, exactly the same format as used for transparency bitmap
|
||||
* in the XCursor encoding). If (w * h == 0), cursor should be hidden (or
|
||||
* default local cursor should be set by the client).
|
||||
*/
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* SetColourMapEntries - these messages are only sent if the pixel
|
||||
* format uses a "colour map" (i.e. trueColour false) and the client has not
|
||||
* fixed the entire colour map using FixColourMapEntries. In addition they
|
||||
* will only start being sent after the client has sent its first
|
||||
* FramebufferUpdateRequest. So if the client always tells the server to use
|
||||
* trueColour then it never needs to process this type of message.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
CARD8 type; /* always rfbSetColourMapEntries */
|
||||
CARD8 pad;
|
||||
CARD16 firstColour;
|
||||
CARD16 nColours;
|
||||
|
||||
/* Followed by nColours * 3 * CARD16
|
||||
r1, g1, b1, r2, g2, b2, r3, g3, b3, ..., rn, bn, gn */
|
||||
|
||||
} rfbSetColourMapEntriesMsg;
|
||||
|
||||
#define sz_rfbSetColourMapEntriesMsg 6
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* Bell - ring a bell on the client if it has one.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
CARD8 type; /* always rfbBell */
|
||||
} rfbBellMsg;
|
||||
|
||||
#define sz_rfbBellMsg 1
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* ServerCutText - the server has new text in its cut buffer.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
CARD8 type; /* always rfbServerCutText */
|
||||
CARD8 pad1;
|
||||
CARD16 pad2;
|
||||
CARD32 length;
|
||||
/* followed by char text[length] */
|
||||
} rfbServerCutTextMsg;
|
||||
|
||||
#define sz_rfbServerCutTextMsg 8
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* Union of all server->client messages.
|
||||
*/
|
||||
|
||||
typedef union {
|
||||
CARD8 type;
|
||||
rfbFramebufferUpdateMsg fu;
|
||||
rfbSetColourMapEntriesMsg scme;
|
||||
rfbBellMsg b;
|
||||
rfbServerCutTextMsg sct;
|
||||
} rfbServerToClientMsg;
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Message definitions (client -> server)
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* SetPixelFormat - tell the RFB server the format in which the client wants
|
||||
* pixels sent.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
CARD8 type; /* always rfbSetPixelFormat */
|
||||
CARD8 pad1;
|
||||
CARD16 pad2;
|
||||
rfbPixelFormat format;
|
||||
} rfbSetPixelFormatMsg;
|
||||
|
||||
#define sz_rfbSetPixelFormatMsg (sz_rfbPixelFormat + 4)
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* FixColourMapEntries - when the pixel format uses a "colour map", fix
|
||||
* read-only colour map entries.
|
||||
*
|
||||
* ***************** NOT CURRENTLY SUPPORTED *****************
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
CARD8 type; /* always rfbFixColourMapEntries */
|
||||
CARD8 pad;
|
||||
CARD16 firstColour;
|
||||
CARD16 nColours;
|
||||
|
||||
/* Followed by nColours * 3 * CARD16
|
||||
r1, g1, b1, r2, g2, b2, r3, g3, b3, ..., rn, bn, gn */
|
||||
|
||||
} rfbFixColourMapEntriesMsg;
|
||||
|
||||
#define sz_rfbFixColourMapEntriesMsg 6
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* SetEncodings - tell the RFB server which encoding types we accept. Put them
|
||||
* in order of preference, if we have any. We may always receive raw
|
||||
* encoding, even if we don't specify it here.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
CARD8 type; /* always rfbSetEncodings */
|
||||
CARD8 pad;
|
||||
CARD16 nEncodings;
|
||||
/* followed by nEncodings * CARD32 encoding types */
|
||||
} rfbSetEncodingsMsg;
|
||||
|
||||
#define sz_rfbSetEncodingsMsg 4
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* FramebufferUpdateRequest - request for a framebuffer update. If incremental
|
||||
* is true then the client just wants the changes since the last update. If
|
||||
* false then it wants the whole of the specified rectangle.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
CARD8 type; /* always rfbFramebufferUpdateRequest */
|
||||
CARD8 incremental;
|
||||
CARD16 x;
|
||||
CARD16 y;
|
||||
CARD16 w;
|
||||
CARD16 h;
|
||||
} rfbFramebufferUpdateRequestMsg;
|
||||
|
||||
#define sz_rfbFramebufferUpdateRequestMsg 10
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* KeyEvent - key press or release
|
||||
*
|
||||
* Keys are specified using the "keysym" values defined by the X Window System.
|
||||
* For most ordinary keys, the keysym is the same as the corresponding ASCII
|
||||
* value. Other common keys are:
|
||||
*
|
||||
* BackSpace 0xff08
|
||||
* Tab 0xff09
|
||||
* Return or Enter 0xff0d
|
||||
* Escape 0xff1b
|
||||
* Insert 0xff63
|
||||
* Delete 0xffff
|
||||
* Home 0xff50
|
||||
* End 0xff57
|
||||
* Page Up 0xff55
|
||||
* Page Down 0xff56
|
||||
* Left 0xff51
|
||||
* Up 0xff52
|
||||
* Right 0xff53
|
||||
* Down 0xff54
|
||||
* F1 0xffbe
|
||||
* F2 0xffbf
|
||||
* ... ...
|
||||
* F12 0xffc9
|
||||
* Shift 0xffe1
|
||||
* Control 0xffe3
|
||||
* Meta 0xffe7
|
||||
* Alt 0xffe9
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
CARD8 type; /* always rfbKeyEvent */
|
||||
CARD8 down; /* true if down (press), false if up */
|
||||
CARD16 pad;
|
||||
CARD32 key; /* key is specified as an X keysym */
|
||||
} rfbKeyEventMsg;
|
||||
|
||||
#define sz_rfbKeyEventMsg 8
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* PointerEvent - mouse/pen move and/or button press.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
CARD8 type; /* always rfbPointerEvent */
|
||||
CARD8 buttonMask; /* bits 0-7 are buttons 1-8, 0=up, 1=down */
|
||||
CARD16 x;
|
||||
CARD16 y;
|
||||
} rfbPointerEventMsg;
|
||||
|
||||
#define rfbButton1Mask 1
|
||||
#define rfbButton2Mask 2
|
||||
#define rfbButton3Mask 4
|
||||
|
||||
#define sz_rfbPointerEventMsg 6
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* ClientCutText - the client has new text in its cut buffer.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
CARD8 type; /* always rfbClientCutText */
|
||||
CARD8 pad1;
|
||||
CARD16 pad2;
|
||||
CARD32 length;
|
||||
/* followed by char text[length] */
|
||||
} rfbClientCutTextMsg;
|
||||
|
||||
#define sz_rfbClientCutTextMsg 8
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* Union of all client->server messages.
|
||||
*/
|
||||
|
||||
typedef union {
|
||||
CARD8 type;
|
||||
rfbSetPixelFormatMsg spf;
|
||||
rfbFixColourMapEntriesMsg fcme;
|
||||
rfbSetEncodingsMsg se;
|
||||
rfbFramebufferUpdateRequestMsg fur;
|
||||
rfbKeyEventMsg ke;
|
||||
rfbPointerEventMsg pe;
|
||||
rfbClientCutTextMsg cct;
|
||||
} rfbClientToServerMsg;
|
86
client/rre.c
86
client/rre.c
|
@ -1,86 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 1999 AT&T Laboratories Cambridge. 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* rre.c - handle RRE encoding.
|
||||
*
|
||||
* This file shouldn't be compiled directly. It is included multiple times by
|
||||
* rfbproto.c, each time with a different definition of the macro BPP. For
|
||||
* each value of BPP, this file defines a function which handles an RRE
|
||||
* encoded rectangle with BPP bits per pixel.
|
||||
*/
|
||||
|
||||
#define HandleRREBPP CONCAT2E(HandleRRE,BPP)
|
||||
#define CARDBPP CONCAT2E(CARD,BPP)
|
||||
|
||||
static Bool
|
||||
HandleRREBPP (int rx, int ry, int rw, int rh)
|
||||
{
|
||||
rfbRREHeader hdr;
|
||||
XGCValues gcv;
|
||||
int i;
|
||||
CARDBPP pix;
|
||||
rfbRectangle subrect;
|
||||
|
||||
if (!ReadFromRFBServer((char *)&hdr, sz_rfbRREHeader))
|
||||
return False;
|
||||
|
||||
hdr.nSubrects = Swap32IfLE(hdr.nSubrects);
|
||||
|
||||
if (!ReadFromRFBServer((char *)&pix, sizeof(pix)))
|
||||
return False;
|
||||
|
||||
#if (BPP == 8)
|
||||
gcv.foreground = (appData.useBGR233 ? BGR233ToPixel[pix] : pix);
|
||||
#else
|
||||
gcv.foreground = pix;
|
||||
#endif
|
||||
|
||||
lockQt();
|
||||
XChangeGC(dpy, gc, GCForeground, &gcv);
|
||||
XFillRectangle(dpy, desktopWin, gc, rx, ry, rw, rh);
|
||||
unlockQt();
|
||||
|
||||
for (i = 0; i < hdr.nSubrects; i++) {
|
||||
if (!ReadFromRFBServer((char *)&pix, sizeof(pix)))
|
||||
return False;
|
||||
|
||||
if (!ReadFromRFBServer((char *)&subrect, sz_rfbRectangle))
|
||||
return False;
|
||||
|
||||
subrect.x = Swap16IfLE(subrect.x);
|
||||
subrect.y = Swap16IfLE(subrect.y);
|
||||
subrect.w = Swap16IfLE(subrect.w);
|
||||
subrect.h = Swap16IfLE(subrect.h);
|
||||
|
||||
#if (BPP == 8)
|
||||
gcv.foreground = (appData.useBGR233 ? BGR233ToPixel[pix] : pix);
|
||||
#else
|
||||
gcv.foreground = pix;
|
||||
#endif
|
||||
|
||||
lockQt();
|
||||
XChangeGC(dpy, gc, GCForeground, &gcv);
|
||||
XFillRectangle(dpy, desktopWin, gc, rx + subrect.x, ry + subrect.y,
|
||||
subrect.w, subrect.h);
|
||||
unlockQt();
|
||||
}
|
||||
|
||||
return True;
|
||||
}
|
446
client/sockets.c
446
client/sockets.c
|
@ -1,446 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 1999 AT&T Laboratories Cambridge. 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*
|
||||
* 03-05-2002 tim@tjansen.de: removed Xt event processing for krdc
|
||||
*/
|
||||
|
||||
/*
|
||||
* sockets.c - functions to deal with sockets.
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <errno.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <fcntl.h>
|
||||
#include <assert.h>
|
||||
#include "vncviewer.h"
|
||||
|
||||
void PrintInHex(char *buf, int len);
|
||||
|
||||
Bool errorMessageOnReadFailure = True;
|
||||
|
||||
#define BUF_SIZE 8192
|
||||
static char buf[BUF_SIZE];
|
||||
static char *bufoutptr = buf;
|
||||
static unsigned int buffered = 0;
|
||||
|
||||
/* Wait duration of select in seconds */
|
||||
#define SELECT_PERIOD 3
|
||||
|
||||
|
||||
/*
|
||||
* ReadFromRFBServer is called whenever we want to read some data from the RFB
|
||||
* server.
|
||||
*/
|
||||
Bool
|
||||
ReadFromRFBServer(char *out, unsigned int n)
|
||||
{
|
||||
fd_set fds;
|
||||
int e;
|
||||
struct timeval tx;
|
||||
tx.tv_sec = SELECT_PERIOD;
|
||||
tx.tv_usec = 0;
|
||||
|
||||
if (isQuitFlagSet())
|
||||
return False;
|
||||
|
||||
if (n <= buffered) {
|
||||
memcpy(out, bufoutptr, n);
|
||||
bufoutptr += n;
|
||||
buffered -= n;
|
||||
return True;
|
||||
}
|
||||
|
||||
memcpy(out, bufoutptr, buffered);
|
||||
|
||||
out += buffered;
|
||||
n -= buffered;
|
||||
|
||||
bufoutptr = buf;
|
||||
buffered = 0;
|
||||
|
||||
if (n <= BUF_SIZE) {
|
||||
|
||||
while (buffered < n) {
|
||||
int i;
|
||||
if (isQuitFlagSet())
|
||||
return False;
|
||||
i = read(rfbsock, buf + buffered, BUF_SIZE - buffered);
|
||||
if (i <= 0) {
|
||||
if (i < 0) {
|
||||
if (errno == EWOULDBLOCK || errno == EAGAIN) {
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(rfbsock,&fds);
|
||||
|
||||
if ((e=select(rfbsock+1, &fds, NULL, &fds, &tx)) < 0) {
|
||||
perror("krdc: select read");
|
||||
return False;
|
||||
}
|
||||
i = 0;
|
||||
} else {
|
||||
perror("krdc: read");
|
||||
return False;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr,"VNC server closed connection\n");
|
||||
return False;
|
||||
}
|
||||
}
|
||||
buffered += i;
|
||||
}
|
||||
|
||||
memcpy(out, bufoutptr, n);
|
||||
bufoutptr += n;
|
||||
buffered -= n;
|
||||
return True;
|
||||
|
||||
} else {
|
||||
|
||||
while (n > 0) {
|
||||
int i;
|
||||
if (isQuitFlagSet())
|
||||
return False;
|
||||
i = read(rfbsock, out, n);
|
||||
if (i <= 0) {
|
||||
if (i < 0) {
|
||||
if (errno == EWOULDBLOCK || errno == EAGAIN) {
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(rfbsock,&fds);
|
||||
|
||||
if ((e=select(rfbsock+1, &fds, NULL, &fds, &tx)) < 0) {
|
||||
perror("krdc: select");
|
||||
return False;
|
||||
}
|
||||
i = 0;
|
||||
} else {
|
||||
perror("krdc: read");
|
||||
return False;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr,"VNC server closed connection\n");
|
||||
return False;
|
||||
}
|
||||
}
|
||||
out += i;
|
||||
n -= i;
|
||||
}
|
||||
|
||||
return True;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Write an exact number of bytes, and don't return until you've sent them.
|
||||
* Note: this should only be called by the WriterThread
|
||||
*/
|
||||
|
||||
Bool
|
||||
WriteExact(int sock, char *_buf, int n)
|
||||
{
|
||||
fd_set fds;
|
||||
int i = 0;
|
||||
int j;
|
||||
int e;
|
||||
struct timeval tx;
|
||||
tx.tv_sec = SELECT_PERIOD;
|
||||
tx.tv_usec = 0;
|
||||
|
||||
while (i < n) {
|
||||
if (isQuitFlagSet())
|
||||
return False;
|
||||
j = write(sock, _buf + i, (n - i));
|
||||
if (j <= 0) {
|
||||
if (j < 0) {
|
||||
if (errno == EWOULDBLOCK || errno == EAGAIN) {
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(rfbsock,&fds);
|
||||
|
||||
if ((e=select(rfbsock+1, NULL, &fds, NULL, &tx)) < 0) {
|
||||
perror("krdc: select write");
|
||||
return False;
|
||||
}
|
||||
j = 0;
|
||||
} else {
|
||||
perror("krdc: write");
|
||||
return False;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr,"write failed\n");
|
||||
return False;
|
||||
}
|
||||
}
|
||||
i += j;
|
||||
}
|
||||
return True;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ConnectToTcpAddr connects to the given TCP port.
|
||||
*/
|
||||
|
||||
int
|
||||
ConnectToTcpAddr(unsigned int host, int port)
|
||||
{
|
||||
int sock;
|
||||
struct sockaddr_in addr;
|
||||
int one = 1;
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
addr.sin_addr.s_addr = host;
|
||||
|
||||
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (sock < 0) {
|
||||
perror("krdc: ConnectToTcpAddr: socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
perror("krdc: ConnectToTcpAddr: connect");
|
||||
close(sock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
|
||||
(char *)&one, sizeof(one)) < 0) {
|
||||
perror("krdc: ConnectToTcpAddr: setsockopt");
|
||||
close(sock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* FindFreeTcpPort tries to find unused TCP port in the range
|
||||
* (TUNNEL_PORT_OFFSET, TUNNEL_PORT_OFFSET + 99]. Returns 0 on failure.
|
||||
*/
|
||||
|
||||
int
|
||||
FindFreeTcpPort(void)
|
||||
{
|
||||
int sock, port;
|
||||
struct sockaddr_in addr;
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = INADDR_ANY;
|
||||
|
||||
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (sock < 0) {
|
||||
perror("krdc: FindFreeTcpPort: socket");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (port = TUNNEL_PORT_OFFSET + 99; port > TUNNEL_PORT_OFFSET; port--) {
|
||||
addr.sin_port = htons((unsigned short)port);
|
||||
if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == 0) {
|
||||
close(sock);
|
||||
return port;
|
||||
}
|
||||
}
|
||||
|
||||
close(sock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ListenAtTcpPort starts listening at the given TCP port.
|
||||
*/
|
||||
|
||||
int
|
||||
ListenAtTcpPort(int port)
|
||||
{
|
||||
int sock;
|
||||
struct sockaddr_in addr;
|
||||
int one = 1;
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
addr.sin_addr.s_addr = INADDR_ANY;
|
||||
|
||||
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (sock < 0) {
|
||||
perror("krdc: ListenAtTcpPort: socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
|
||||
(const char *)&one, sizeof(one)) < 0) {
|
||||
perror("krdc: ListenAtTcpPort: setsockopt");
|
||||
close(sock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
perror("krdc: ListenAtTcpPort: bind");
|
||||
close(sock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (listen(sock, 5) < 0) {
|
||||
perror("krdc: ListenAtTcpPort: listen");
|
||||
close(sock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* AcceptTcpConnection accepts a TCP connection.
|
||||
*/
|
||||
|
||||
int
|
||||
AcceptTcpConnection(int listenSock)
|
||||
{
|
||||
int sock;
|
||||
struct sockaddr_in addr;
|
||||
int addrlen = sizeof(addr);
|
||||
int one = 1;
|
||||
|
||||
sock = accept(listenSock, (struct sockaddr *) &addr, &addrlen);
|
||||
if (sock < 0) {
|
||||
perror("krdc: AcceptTcpConnection: accept");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
|
||||
(char *)&one, sizeof(one)) < 0) {
|
||||
perror("krdc: AcceptTcpConnection: setsockopt");
|
||||
close(sock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* SetNonBlocking sets a socket into non-blocking mode.
|
||||
*/
|
||||
|
||||
Bool
|
||||
SetNonBlocking(int sock)
|
||||
{
|
||||
if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) {
|
||||
perror("krdc: AcceptTcpConnection: fcntl");
|
||||
return False;
|
||||
}
|
||||
return True;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* StringToIPAddr - convert a host string to an IP address.
|
||||
*/
|
||||
|
||||
Bool
|
||||
StringToIPAddr(const char *str, unsigned int *addr)
|
||||
{
|
||||
struct hostent *hp;
|
||||
|
||||
if (strcmp(str,"") == 0) {
|
||||
*addr = 0; /* local */
|
||||
return True;
|
||||
}
|
||||
|
||||
*addr = inet_addr(str);
|
||||
|
||||
if (*addr != -1)
|
||||
return True;
|
||||
|
||||
hp = gethostbyname(str);
|
||||
|
||||
if (hp) {
|
||||
*addr = *(unsigned int *)hp->h_addr;
|
||||
return True;
|
||||
}
|
||||
|
||||
return False;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Test if the other end of a socket is on the same machine.
|
||||
*/
|
||||
|
||||
Bool
|
||||
SameMachine(int sock)
|
||||
{
|
||||
struct sockaddr_in peeraddr, myaddr;
|
||||
int addrlen = sizeof(struct sockaddr_in);
|
||||
|
||||
getpeername(sock, (struct sockaddr *)&peeraddr, &addrlen);
|
||||
getsockname(sock, (struct sockaddr *)&myaddr, &addrlen);
|
||||
|
||||
return (peeraddr.sin_addr.s_addr == myaddr.sin_addr.s_addr);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Print out the contents of a packet for debugging.
|
||||
*/
|
||||
|
||||
void
|
||||
PrintInHex(char *_buf, int len)
|
||||
{
|
||||
int i, j;
|
||||
char c, str[17];
|
||||
|
||||
str[16] = 0;
|
||||
|
||||
fprintf(stderr,"ReadExact: ");
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
if ((i % 16 == 0) && (i != 0)) {
|
||||
fprintf(stderr," ");
|
||||
}
|
||||
c = _buf[i];
|
||||
str[i % 16] = (((c > 31) && (c < 127)) ? c : '.');
|
||||
fprintf(stderr,"%02x ",(unsigned char)c);
|
||||
if ((i % 4) == 3)
|
||||
fprintf(stderr," ");
|
||||
if ((i % 16) == 15)
|
||||
{
|
||||
fprintf(stderr,"%s\n",str);
|
||||
}
|
||||
}
|
||||
if ((i % 16) != 0)
|
||||
{
|
||||
for (j = i % 16; j < 16; j++)
|
||||
{
|
||||
fprintf(stderr," ");
|
||||
if ((j % 4) == 3) fprintf(stderr," ");
|
||||
}
|
||||
str[i % 16] = 0;
|
||||
fprintf(stderr,"%s\n",str);
|
||||
}
|
||||
|
||||
fflush(stderr);
|
||||
}
|
|
@ -1,242 +0,0 @@
|
|||
/***************************************************************************
|
||||
threads.cpp - threads
|
||||
-------------------
|
||||
begin : Thu May 09 17:01:44 CET 2002
|
||||
copyright : (C) 2002 by Tim Jansen
|
||||
email : tim@tjansen.de
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "kvncview.h"
|
||||
#include "threads.h"
|
||||
#include "kdebug.h"
|
||||
|
||||
static const int WAIT_PERIOD = 5000;
|
||||
static const unsigned int MOUSEPRESS_QUEUE_SIZE = 10;
|
||||
static const unsigned int MOUSEMOVE_QUEUE_SIZE = 5;
|
||||
static const unsigned int KEY_QUEUE_SIZE = 8192;
|
||||
|
||||
|
||||
ControllerThread::ControllerThread(KVncView *v, WriterThread &wt, volatile bool &quitFlag) :
|
||||
m_view(v),
|
||||
m_status(REMOTE_VIEW_CONNECTING),
|
||||
m_wthread(wt),
|
||||
m_quitFlag(quitFlag)
|
||||
{
|
||||
}
|
||||
|
||||
void ControllerThread::changeStatus(RemoteViewStatus s) {
|
||||
m_status = s;
|
||||
QThread::postEvent(m_view, new StatusChangeEvent(s));
|
||||
}
|
||||
|
||||
void ControllerThread::run() {
|
||||
if (!ConnectToRFBServer(m_view->host().latin1(), m_view->port())) {
|
||||
m_quitFlag = true;
|
||||
changeStatus(REMOTE_VIEW_DISCONNECTED);
|
||||
return;
|
||||
}
|
||||
|
||||
changeStatus(REMOTE_VIEW_AUTHENTICATING);
|
||||
|
||||
if (!InitialiseRFBConnection()) {
|
||||
m_quitFlag = true;
|
||||
changeStatus(REMOTE_VIEW_DISCONNECTED);
|
||||
return;
|
||||
}
|
||||
|
||||
QThread::postEvent(m_view, new ScreenResizeEvent(si.framebufferWidth,
|
||||
si.framebufferHeight));
|
||||
|
||||
changeStatus(REMOTE_VIEW_PREPARING);
|
||||
|
||||
lockQt();
|
||||
SetVisualAndCmap();
|
||||
ToplevelInit();
|
||||
DesktopInit(m_view->winId());
|
||||
unlockQt();
|
||||
|
||||
SetFormatAndEncodings();
|
||||
|
||||
changeStatus(REMOTE_VIEW_CONNECTED);
|
||||
|
||||
m_wthread.start();
|
||||
|
||||
while (!m_quitFlag) {
|
||||
if (!HandleRFBServerMessage())
|
||||
break;
|
||||
}
|
||||
|
||||
m_quitFlag = true;
|
||||
changeStatus(REMOTE_VIEW_DISCONNECTED);
|
||||
}
|
||||
|
||||
enum RemoteViewStatus ControllerThread::status() {
|
||||
return m_status;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static WriterThread *writerThread;
|
||||
void queueIncrementalUpdateRequest() {
|
||||
writerThread->queueIncrementalUpdateRequest();
|
||||
}
|
||||
|
||||
|
||||
WriterThread::WriterThread(volatile bool &quitFlag) :
|
||||
m_quitFlag(quitFlag)
|
||||
{
|
||||
writerThread = this;
|
||||
}
|
||||
|
||||
bool WriterThread::sendIncrementalUpdateRequest() {
|
||||
return SendIncrementalFramebufferUpdateRequest();
|
||||
}
|
||||
|
||||
bool WriterThread::sendUpdateRequest(const QRegion ®ion) {
|
||||
QMemArray<QRect> r = region.rects();
|
||||
for (unsigned int i = 0; i < r.size(); i++)
|
||||
if (!SendFramebufferUpdateRequest(r[i].x(),
|
||||
r[i].y(),
|
||||
r[i].width(),
|
||||
r[i].height(), False))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriterThread::sendMouseEvents(const QValueList<MouseEvent> &events) {
|
||||
QValueList<MouseEvent>::const_iterator it = events.begin();
|
||||
while (it != events.end()) {
|
||||
if (!SendPointerEvent((*it).x, (*it).y, (*it).buttons))
|
||||
return false;
|
||||
it++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriterThread::sendKeyEvents(const QValueList<KeyEvent> &events) {
|
||||
QValueList<KeyEvent>::const_iterator it = events.begin();
|
||||
while (it != events.end()) {
|
||||
if (!SendKeyEvent((*it).k, (*it).down ? True : False))
|
||||
return false;
|
||||
it++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void WriterThread::queueIncrementalUpdateRequest() {
|
||||
m_lock.lock();
|
||||
m_incrementalUpdateRQ = true;
|
||||
m_waiter.wakeAll();
|
||||
m_lock.unlock();
|
||||
}
|
||||
|
||||
|
||||
void WriterThread::queueUpdateRequest(const QRegion &r) {
|
||||
m_lock.lock();
|
||||
m_updateRegionRQ += r;
|
||||
m_waiter.wakeAll();
|
||||
m_lock.unlock();
|
||||
}
|
||||
|
||||
void WriterThread::queueMouseEvent(int x, int y, int buttonMask) {
|
||||
MouseEvent e;
|
||||
e.x = x;
|
||||
e.y = y;
|
||||
e.buttons = buttonMask;
|
||||
|
||||
m_lock.lock();
|
||||
if (m_mouseEvents.size() > 0) {
|
||||
if ((e.x == m_mouseEvents.last().x) &&
|
||||
(e.y == m_mouseEvents.last().y) &&
|
||||
(e.buttons == m_mouseEvents.last().buttons)) {
|
||||
m_lock.unlock();
|
||||
return;
|
||||
}
|
||||
if (m_mouseEvents.size() >= MOUSEPRESS_QUEUE_SIZE) {
|
||||
m_lock.unlock();
|
||||
return;
|
||||
}
|
||||
if ((m_mouseEvents.last().buttons == buttonMask) &&
|
||||
(m_mouseEvents.size() >= MOUSEMOVE_QUEUE_SIZE)) {
|
||||
m_lock.unlock();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_mouseEvents.push_back(e);
|
||||
m_waiter.wakeAll();
|
||||
m_lock.unlock();
|
||||
}
|
||||
|
||||
void WriterThread::queueKeyEvent(unsigned int k, bool down) {
|
||||
KeyEvent e;
|
||||
e.k = k;
|
||||
e.down = down;
|
||||
|
||||
m_lock.lock();
|
||||
if (m_keyEvents.size() >= KEY_QUEUE_SIZE) {
|
||||
m_lock.unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
m_keyEvents.push_back(e);
|
||||
m_waiter.wakeAll();
|
||||
m_lock.unlock();
|
||||
}
|
||||
|
||||
void WriterThread::kick() {
|
||||
m_waiter.wakeAll();
|
||||
}
|
||||
|
||||
void WriterThread::run() {
|
||||
bool incrementalUpdateRQ = false;
|
||||
QRegion updateRegionRQ;
|
||||
QValueList<MouseEvent> mouseEvents;
|
||||
QValueList<KeyEvent> keyEvents;
|
||||
|
||||
while (!m_quitFlag) {
|
||||
m_lock.lock();
|
||||
incrementalUpdateRQ = m_incrementalUpdateRQ;
|
||||
updateRegionRQ = m_updateRegionRQ;
|
||||
mouseEvents = m_mouseEvents;
|
||||
keyEvents = m_keyEvents;
|
||||
|
||||
if ((!incrementalUpdateRQ) &&
|
||||
(updateRegionRQ.isNull()) &&
|
||||
(mouseEvents.size() == 0) &&
|
||||
(keyEvents.size() == 0)) {
|
||||
m_waiter.wait(&m_lock, WAIT_PERIOD);
|
||||
m_lock.unlock();
|
||||
}
|
||||
else {
|
||||
m_incrementalUpdateRQ = false;
|
||||
m_updateRegionRQ = QRegion();
|
||||
m_mouseEvents.clear();
|
||||
m_keyEvents.clear();
|
||||
m_lock.unlock();
|
||||
|
||||
if (incrementalUpdateRQ)
|
||||
if (!sendIncrementalUpdateRequest())
|
||||
break;
|
||||
if (!updateRegionRQ.isNull())
|
||||
if (!sendUpdateRequest(updateRegionRQ))
|
||||
break;
|
||||
if (mouseEvents.size() != 0)
|
||||
if (!sendMouseEvents(mouseEvents))
|
||||
break;
|
||||
if (keyEvents.size() != 0)
|
||||
if (!sendKeyEvents(keyEvents))
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_quitFlag = true;
|
||||
}
|
146
client/threads.h
146
client/threads.h
|
@ -1,146 +0,0 @@
|
|||
/***************************************************************************
|
||||
threads.h - threads for kvncview
|
||||
-------------------
|
||||
begin : Thu May 09 16:01:42 CET 2002
|
||||
copyright : (C) 2002 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 THREADS_H
|
||||
#define THREADS_H
|
||||
|
||||
#ifndef VNCVIEWER_H
|
||||
#define VNCVIEWER_H
|
||||
#include "vncviewer.h"
|
||||
#endif
|
||||
|
||||
#include <qthread.h>
|
||||
#include <qregion.h>
|
||||
#include <qrect.h>
|
||||
#include <qmutex.h>
|
||||
#include <qwaitcondition.h>
|
||||
#include <qevent.h>
|
||||
#include <qvaluelist.h>
|
||||
|
||||
class KVncView;
|
||||
|
||||
enum RemoteViewStatus {
|
||||
REMOTE_VIEW_CONNECTING,
|
||||
REMOTE_VIEW_AUTHENTICATING,
|
||||
REMOTE_VIEW_PREPARING,
|
||||
REMOTE_VIEW_CONNECTED,
|
||||
REMOTE_VIEW_DISCONNECTED
|
||||
};
|
||||
|
||||
|
||||
|
||||
const int ScreenResizeEventType = 781001;
|
||||
|
||||
class ScreenResizeEvent : public QCustomEvent
|
||||
{
|
||||
private:
|
||||
int m_width, m_height;
|
||||
public:
|
||||
ScreenResizeEvent(int w, int h) :
|
||||
QCustomEvent(ScreenResizeEventType),
|
||||
m_width(w),
|
||||
m_height(h)
|
||||
{};
|
||||
int width() const { return m_width; };
|
||||
int height() const { return m_height; };
|
||||
};
|
||||
|
||||
const int StatusChangeEventType = 781002;
|
||||
|
||||
class StatusChangeEvent : public QCustomEvent
|
||||
{
|
||||
private:
|
||||
RemoteViewStatus m_status;
|
||||
public:
|
||||
StatusChangeEvent(RemoteViewStatus s) :
|
||||
QCustomEvent(StatusChangeEventType),
|
||||
m_status(s)
|
||||
{};
|
||||
RemoteViewStatus status() const { return m_status; };
|
||||
};
|
||||
|
||||
const int PasswordRequiredEventType = 781003;
|
||||
|
||||
class PasswordRequiredEvent : public QCustomEvent
|
||||
{
|
||||
public:
|
||||
PasswordRequiredEvent() :
|
||||
QCustomEvent(PasswordRequiredEventType)
|
||||
{};
|
||||
};
|
||||
|
||||
|
||||
struct MouseEvent {
|
||||
int x, y, buttons;
|
||||
};
|
||||
|
||||
struct KeyEvent {
|
||||
unsigned int k;
|
||||
bool down;
|
||||
};
|
||||
|
||||
|
||||
class WriterThread : public QThread {
|
||||
private:
|
||||
QMutex m_lock;
|
||||
QWaitCondition m_waiter;
|
||||
volatile bool &m_quitFlag;
|
||||
|
||||
// all things that can be send follow:
|
||||
int m_incrementalUpdateRQ; // for sending an incremental request
|
||||
QRegion m_updateRegionRQ; // for sending updates, null if it is done
|
||||
QValueList<MouseEvent> m_mouseEvents; // list of unsent mouse events
|
||||
QValueList<KeyEvent> m_keyEvents; // list of unsent key events
|
||||
|
||||
public:
|
||||
WriterThread(volatile bool &quitFlag);
|
||||
|
||||
void queueIncrementalUpdateRequest();
|
||||
void queueUpdateRequest(const QRegion &r);
|
||||
void queueMouseEvent(int x, int y, int buttonMask);
|
||||
void queueKeyEvent(unsigned int k, bool down);
|
||||
void kick();
|
||||
|
||||
protected:
|
||||
void run();
|
||||
bool sendIncrementalUpdateRequest();
|
||||
bool sendUpdateRequest(const QRegion &r);
|
||||
bool sendMouseEvents(const QValueList<MouseEvent> &events);
|
||||
bool sendKeyEvents(const QValueList<KeyEvent> &events);
|
||||
};
|
||||
|
||||
|
||||
|
||||
class ControllerThread : public QThread {
|
||||
private:
|
||||
KVncView *m_view;
|
||||
enum RemoteViewStatus m_status;
|
||||
WriterThread &m_wthread;
|
||||
volatile bool &m_quitFlag;
|
||||
|
||||
void changeStatus(RemoteViewStatus s);
|
||||
public:
|
||||
|
||||
ControllerThread(KVncView *v, WriterThread &wt, volatile bool &quitFlag);
|
||||
enum RemoteViewStatus status();
|
||||
protected:
|
||||
void run();
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
611
client/tight.c
611
client/tight.c
|
@ -1,611 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2000, 2001 Const Kaplinsky. 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* tight.c - handle ``tight'' encoding.
|
||||
*
|
||||
* This file shouldn't be compiled directly. It is included multiple
|
||||
* times by rfbproto.c, each time with a different definition of the
|
||||
* macro BPP. For each value of BPP, this file defines a function
|
||||
* which handles a tight-encoded rectangle with BPP bits per pixel.
|
||||
*
|
||||
*/
|
||||
|
||||
#define TIGHT_MIN_TO_COMPRESS 12
|
||||
|
||||
#define CARDBPP CONCAT2E(CARD,BPP)
|
||||
#define filterPtrBPP CONCAT2E(filterPtr,BPP)
|
||||
|
||||
#define HandleTightBPP CONCAT2E(HandleTight,BPP)
|
||||
#define InitFilterCopyBPP CONCAT2E(InitFilterCopy,BPP)
|
||||
#define InitFilterPaletteBPP CONCAT2E(InitFilterPalette,BPP)
|
||||
#define InitFilterGradientBPP CONCAT2E(InitFilterGradient,BPP)
|
||||
#define FilterCopyBPP CONCAT2E(FilterCopy,BPP)
|
||||
#define FilterPaletteBPP CONCAT2E(FilterPalette,BPP)
|
||||
#define FilterGradientBPP CONCAT2E(FilterGradient,BPP)
|
||||
|
||||
#if BPP != 8
|
||||
#define DecompressJpegRectBPP CONCAT2E(DecompressJpegRect,BPP)
|
||||
#endif
|
||||
|
||||
#ifndef RGB_TO_PIXEL
|
||||
|
||||
#define RGB_TO_PIXEL(bpp,r,g,b) \
|
||||
(((CARD##bpp)(r) & myFormat.redMax) << myFormat.redShift | \
|
||||
((CARD##bpp)(g) & myFormat.greenMax) << myFormat.greenShift | \
|
||||
((CARD##bpp)(b) & myFormat.blueMax) << myFormat.blueShift)
|
||||
|
||||
#define RGB24_TO_PIXEL(bpp,r,g,b) \
|
||||
((((CARD##bpp)(r) & 0xFF) * myFormat.redMax + 127) / 255 \
|
||||
<< myFormat.redShift | \
|
||||
(((CARD##bpp)(g) & 0xFF) * myFormat.greenMax + 127) / 255 \
|
||||
<< myFormat.greenShift | \
|
||||
(((CARD##bpp)(b) & 0xFF) * myFormat.blueMax + 127) / 255 \
|
||||
<< myFormat.blueShift)
|
||||
|
||||
#define RGB24_TO_PIXEL32(r,g,b) \
|
||||
(((CARD32)(r) & 0xFF) << myFormat.redShift | \
|
||||
((CARD32)(g) & 0xFF) << myFormat.greenShift | \
|
||||
((CARD32)(b) & 0xFF) << myFormat.blueShift)
|
||||
|
||||
#endif
|
||||
|
||||
/* Type declarations */
|
||||
|
||||
typedef void (*filterPtrBPP)(int, CARDBPP *);
|
||||
|
||||
/* Prototypes */
|
||||
|
||||
static int InitFilterCopyBPP (int rw, int rh);
|
||||
static int InitFilterPaletteBPP (int rw, int rh);
|
||||
static int InitFilterGradientBPP (int rw, int rh);
|
||||
static void FilterCopyBPP (int numRows, CARDBPP *destBuffer);
|
||||
static void FilterPaletteBPP (int numRows, CARDBPP *destBuffer);
|
||||
static void FilterGradientBPP (int numRows, CARDBPP *destBuffer);
|
||||
|
||||
static Bool DecompressJpegRectBPP(int x, int y, int w, int h);
|
||||
|
||||
/* Definitions */
|
||||
|
||||
static Bool
|
||||
HandleTightBPP (int rx, int ry, int rw, int rh)
|
||||
{
|
||||
CARDBPP fill_colour;
|
||||
XGCValues gcv;
|
||||
CARD8 comp_ctl;
|
||||
CARD8 filter_id;
|
||||
filterPtrBPP filterFn;
|
||||
z_streamp zs;
|
||||
char *buffer2;
|
||||
int err, stream_id, compressedLen, bitsPixel;
|
||||
int bufferSize, rowSize, numRows, portionLen, rowsProcessed, extraBytes;
|
||||
CARDBPP *rawData;
|
||||
|
||||
if (!ReadFromRFBServer((char *)&comp_ctl, 1))
|
||||
return False;
|
||||
|
||||
/* Flush zlib streams if we are told by the server to do so. */
|
||||
for (stream_id = 0; stream_id < 4; stream_id++) {
|
||||
if ((comp_ctl & 1) && zlibStreamActive[stream_id]) {
|
||||
if (inflateEnd (&zlibStream[stream_id]) != Z_OK &&
|
||||
zlibStream[stream_id].msg != NULL)
|
||||
fprintf(stderr, "inflateEnd: %s\n", zlibStream[stream_id].msg);
|
||||
zlibStreamActive[stream_id] = False;
|
||||
}
|
||||
comp_ctl >>= 1;
|
||||
}
|
||||
|
||||
/* Handle solid rectangles. */
|
||||
if (comp_ctl == rfbTightFill) {
|
||||
#if BPP == 32
|
||||
if (myFormat.depth == 24 && myFormat.redMax == 0xFF &&
|
||||
myFormat.greenMax == 0xFF && myFormat.blueMax == 0xFF) {
|
||||
if (!ReadFromRFBServer(buffer, 3))
|
||||
return False;
|
||||
fill_colour = RGB24_TO_PIXEL32(buffer[0], buffer[1], buffer[2]);
|
||||
} else {
|
||||
if (!ReadFromRFBServer((char*)&fill_colour, sizeof(fill_colour)))
|
||||
return False;
|
||||
}
|
||||
#else
|
||||
if (!ReadFromRFBServer((char*)&fill_colour, sizeof(fill_colour)))
|
||||
return False;
|
||||
#endif
|
||||
|
||||
#if (BPP == 8)
|
||||
gcv.foreground = (appData.useBGR233) ?
|
||||
BGR233ToPixel[fill_colour] : fill_colour;
|
||||
#else
|
||||
gcv.foreground = fill_colour;
|
||||
#endif
|
||||
|
||||
lockQt();
|
||||
XChangeGC(dpy, gc, GCForeground, &gcv);
|
||||
XFillRectangle(dpy, desktopWin, gc, rx, ry, rw, rh);
|
||||
unlockQt();
|
||||
return True;
|
||||
}
|
||||
|
||||
#if BPP == 8
|
||||
if (comp_ctl == rfbTightJpeg) {
|
||||
fprintf(stderr, "Tight encoding: JPEG is not supported in 8 bpp mode.\n");
|
||||
return False;
|
||||
}
|
||||
#else
|
||||
if (comp_ctl == rfbTightJpeg) {
|
||||
return DecompressJpegRectBPP(rx, ry, rw, rh);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Quit on unsupported subencoding value. */
|
||||
if (comp_ctl > rfbTightMaxSubencoding) {
|
||||
fprintf(stderr, "Tight encoding: bad subencoding value received.\n");
|
||||
return False;
|
||||
}
|
||||
|
||||
/*
|
||||
* Here primary compression mode handling begins.
|
||||
* Data was processed with optional filter + zlib compression.
|
||||
*/
|
||||
|
||||
/* First, we should identify a filter to use. */
|
||||
if ((comp_ctl & rfbTightExplicitFilter) != 0) {
|
||||
if (!ReadFromRFBServer((char*)&filter_id, 1))
|
||||
return False;
|
||||
|
||||
switch (filter_id) {
|
||||
case rfbTightFilterCopy:
|
||||
filterFn = FilterCopyBPP;
|
||||
bitsPixel = InitFilterCopyBPP(rw, rh);
|
||||
break;
|
||||
case rfbTightFilterPalette:
|
||||
filterFn = FilterPaletteBPP;
|
||||
bitsPixel = InitFilterPaletteBPP(rw, rh);
|
||||
break;
|
||||
case rfbTightFilterGradient:
|
||||
filterFn = FilterGradientBPP;
|
||||
bitsPixel = InitFilterGradientBPP(rw, rh);
|
||||
break;
|
||||
delault:
|
||||
fprintf(stderr, "Tight encoding: unknown filter code received.\n");
|
||||
return False;
|
||||
}
|
||||
} else {
|
||||
filterFn = FilterCopyBPP;
|
||||
bitsPixel = InitFilterCopyBPP(rw, rh);
|
||||
}
|
||||
if (bitsPixel == 0) {
|
||||
fprintf(stderr, "Tight encoding: error receiving palette.\n");
|
||||
return False;
|
||||
}
|
||||
|
||||
/* Determine if the data should be decompressed or just copied. */
|
||||
rowSize = (rw * bitsPixel + 7) / 8;
|
||||
if (rh * rowSize < TIGHT_MIN_TO_COMPRESS) {
|
||||
if (!ReadFromRFBServer((char*)buffer, rh * rowSize))
|
||||
return False;
|
||||
|
||||
buffer2 = &buffer[TIGHT_MIN_TO_COMPRESS * 4];
|
||||
filterFn(rh, (CARDBPP *)buffer2);
|
||||
CopyDataToScreen(buffer2, rx, ry, rw, rh);
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/* Read the length (1..3 bytes) of compressed data following. */
|
||||
compressedLen = (int)ReadCompactLen();
|
||||
if (compressedLen <= 0) {
|
||||
fprintf(stderr, "Incorrect data received from the server.\n");
|
||||
return False;
|
||||
}
|
||||
|
||||
/* Now let's initialize compression stream if needed. */
|
||||
stream_id = comp_ctl & 0x03;
|
||||
zs = &zlibStream[stream_id];
|
||||
if (!zlibStreamActive[stream_id]) {
|
||||
zs->zalloc = Z_NULL;
|
||||
zs->zfree = Z_NULL;
|
||||
zs->opaque = Z_NULL;
|
||||
err = inflateInit(zs);
|
||||
if (err != Z_OK) {
|
||||
if (zs->msg != NULL)
|
||||
fprintf(stderr, "InflateInit error: %s.\n", zs->msg);
|
||||
return False;
|
||||
}
|
||||
zlibStreamActive[stream_id] = True;
|
||||
}
|
||||
|
||||
/* Read, decode and draw actual pixel data in a loop. */
|
||||
|
||||
bufferSize = BUFFER_SIZE * bitsPixel / (bitsPixel + BPP) & 0xFFFFFFFC;
|
||||
buffer2 = &buffer[bufferSize];
|
||||
if (rowSize > bufferSize) {
|
||||
/* Should be impossible when BUFFER_SIZE >= 16384 */
|
||||
fprintf(stderr, "Internal error: incorrect buffer size.\n");
|
||||
return False;
|
||||
}
|
||||
|
||||
rowsProcessed = 0;
|
||||
extraBytes = 0;
|
||||
|
||||
while (compressedLen > 0) {
|
||||
if (compressedLen > ZLIB_BUFFER_SIZE)
|
||||
portionLen = ZLIB_BUFFER_SIZE;
|
||||
else
|
||||
portionLen = compressedLen;
|
||||
|
||||
if (!ReadFromRFBServer((char*)zlib_buffer, portionLen))
|
||||
return False;
|
||||
|
||||
compressedLen -= portionLen;
|
||||
|
||||
zs->next_in = (Bytef *)zlib_buffer;
|
||||
zs->avail_in = portionLen;
|
||||
|
||||
do {
|
||||
zs->next_out = (Bytef *)&buffer[extraBytes];
|
||||
zs->avail_out = bufferSize - extraBytes;
|
||||
|
||||
err = inflate(zs, Z_SYNC_FLUSH);
|
||||
if (err == Z_BUF_ERROR) /* Input exhausted -- no problem. */
|
||||
break;
|
||||
if (err != Z_OK && err != Z_STREAM_END) {
|
||||
if (zs->msg != NULL) {
|
||||
fprintf(stderr, "Inflate error: %s.\n", zs->msg);
|
||||
} else {
|
||||
fprintf(stderr, "Inflate error: %d.\n", err);
|
||||
}
|
||||
return False;
|
||||
}
|
||||
|
||||
numRows = (bufferSize - zs->avail_out) / rowSize;
|
||||
|
||||
filterFn(numRows, (CARDBPP *)buffer2);
|
||||
|
||||
extraBytes = bufferSize - zs->avail_out - numRows * rowSize;
|
||||
if (extraBytes > 0)
|
||||
memcpy(buffer, &buffer[numRows * rowSize], extraBytes);
|
||||
|
||||
CopyDataToScreen(buffer2, rx, ry + rowsProcessed, rw, numRows);
|
||||
rowsProcessed += numRows;
|
||||
}
|
||||
while (zs->avail_out == 0);
|
||||
}
|
||||
|
||||
if (rowsProcessed != rh) {
|
||||
fprintf(stderr, "Incorrect number of scan lines after decompression.\n");
|
||||
return False;
|
||||
}
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
*
|
||||
* Filter stuff.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
The following variables are defined in rfbproto.c:
|
||||
static Bool cutZeros;
|
||||
static int rectWidth, rectColors;
|
||||
static CARD8 tightPalette[256*4];
|
||||
static CARD8 tightPrevRow[2048*3*sizeof(CARD16)];
|
||||
*/
|
||||
|
||||
static int
|
||||
InitFilterCopyBPP (int rw, int rh)
|
||||
{
|
||||
rectWidth = rw;
|
||||
|
||||
#if BPP == 32
|
||||
if (myFormat.depth == 24 && myFormat.redMax == 0xFF &&
|
||||
myFormat.greenMax == 0xFF && myFormat.blueMax == 0xFF) {
|
||||
cutZeros = True;
|
||||
return 24;
|
||||
} else {
|
||||
cutZeros = False;
|
||||
}
|
||||
#endif
|
||||
|
||||
return BPP;
|
||||
}
|
||||
|
||||
static void
|
||||
FilterCopyBPP (int numRows, CARDBPP *dst)
|
||||
{
|
||||
|
||||
#if BPP == 32
|
||||
int x, y;
|
||||
|
||||
if (cutZeros) {
|
||||
for (y = 0; y < numRows; y++) {
|
||||
for (x = 0; x < rectWidth; x++) {
|
||||
dst[y*rectWidth+x] =
|
||||
RGB24_TO_PIXEL32(buffer[(y*rectWidth+x)*3],
|
||||
buffer[(y*rectWidth+x)*3+1],
|
||||
buffer[(y*rectWidth+x)*3+2]);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
memcpy (dst, buffer, numRows * rectWidth * (BPP / 8));
|
||||
}
|
||||
|
||||
static int
|
||||
InitFilterGradientBPP (int rw, int rh)
|
||||
{
|
||||
int bits;
|
||||
|
||||
bits = InitFilterCopyBPP(rw, rh);
|
||||
if (cutZeros)
|
||||
memset(tightPrevRow, 0, rw * 3);
|
||||
else
|
||||
memset(tightPrevRow, 0, rw * 3 * sizeof(CARD16));
|
||||
|
||||
return bits;
|
||||
}
|
||||
|
||||
#if BPP == 32
|
||||
|
||||
static void
|
||||
FilterGradient24 (int numRows, CARD32 *dst)
|
||||
{
|
||||
int x, y, c;
|
||||
CARD8 thisRow[2048*3];
|
||||
CARD8 pix[3];
|
||||
int est[3];
|
||||
|
||||
for (y = 0; y < numRows; y++) {
|
||||
|
||||
/* First pixel in a row */
|
||||
for (c = 0; c < 3; c++) {
|
||||
pix[c] = tightPrevRow[c] + buffer[y*rectWidth*3+c];
|
||||
thisRow[c] = pix[c];
|
||||
}
|
||||
dst[y*rectWidth] = RGB24_TO_PIXEL32(pix[0], pix[1], pix[2]);
|
||||
|
||||
/* Remaining pixels of a row */
|
||||
for (x = 1; x < rectWidth; x++) {
|
||||
for (c = 0; c < 3; c++) {
|
||||
est[c] = (int)tightPrevRow[x*3+c] + (int)pix[c] -
|
||||
(int)tightPrevRow[(x-1)*3+c];
|
||||
if (est[c] > 0xFF) {
|
||||
est[c] = 0xFF;
|
||||
} else if (est[c] < 0x00) {
|
||||
est[c] = 0x00;
|
||||
}
|
||||
pix[c] = (CARD8)est[c] + buffer[(y*rectWidth+x)*3+c];
|
||||
thisRow[x*3+c] = pix[c];
|
||||
}
|
||||
dst[y*rectWidth+x] = RGB24_TO_PIXEL32(pix[0], pix[1], pix[2]);
|
||||
}
|
||||
|
||||
memcpy(tightPrevRow, thisRow, rectWidth * 3);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void
|
||||
FilterGradientBPP (int numRows, CARDBPP *dst)
|
||||
{
|
||||
int x, y, c;
|
||||
CARDBPP *src = (CARDBPP *)buffer;
|
||||
CARD16 *thatRow = (CARD16 *)tightPrevRow;
|
||||
CARD16 thisRow[2048*3];
|
||||
CARD16 pix[3];
|
||||
CARD16 max[3];
|
||||
int shift[3];
|
||||
int est[3];
|
||||
|
||||
#if BPP == 32
|
||||
if (cutZeros) {
|
||||
FilterGradient24(numRows, dst);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
max[0] = myFormat.redMax;
|
||||
max[1] = myFormat.greenMax;
|
||||
max[2] = myFormat.blueMax;
|
||||
|
||||
shift[0] = myFormat.redShift;
|
||||
shift[1] = myFormat.greenShift;
|
||||
shift[2] = myFormat.blueShift;
|
||||
|
||||
for (y = 0; y < numRows; y++) {
|
||||
|
||||
/* First pixel in a row */
|
||||
for (c = 0; c < 3; c++) {
|
||||
pix[c] = (CARD16)((src[y*rectWidth] >> shift[c]) + thatRow[c] & max[c]);
|
||||
thisRow[c] = pix[c];
|
||||
}
|
||||
dst[y*rectWidth] = RGB_TO_PIXEL(BPP, pix[0], pix[1], pix[2]);
|
||||
|
||||
/* Remaining pixels of a row */
|
||||
for (x = 1; x < rectWidth; x++) {
|
||||
for (c = 0; c < 3; c++) {
|
||||
est[c] = (int)thatRow[x*3+c] + (int)pix[c] - (int)thatRow[(x-1)*3+c];
|
||||
if (est[c] > (int)max[c]) {
|
||||
est[c] = (int)max[c];
|
||||
} else if (est[c] < 0) {
|
||||
est[c] = 0;
|
||||
}
|
||||
pix[c] = (CARD16)((src[y*rectWidth+x] >> shift[c]) + est[c] & max[c]);
|
||||
thisRow[x*3+c] = pix[c];
|
||||
}
|
||||
dst[y*rectWidth+x] = RGB_TO_PIXEL(BPP, pix[0], pix[1], pix[2]);
|
||||
}
|
||||
memcpy(thatRow, thisRow, rectWidth * 3 * sizeof(CARD16));
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
InitFilterPaletteBPP (int rw, int rh)
|
||||
{
|
||||
int i;
|
||||
CARD8 numColors;
|
||||
CARDBPP *palette = (CARDBPP *)tightPalette;
|
||||
|
||||
rectWidth = rw;
|
||||
|
||||
if (!ReadFromRFBServer((char*)&numColors, 1))
|
||||
return 0;
|
||||
|
||||
rectColors = (int)numColors;
|
||||
if (++rectColors < 2)
|
||||
return 0;
|
||||
|
||||
#if BPP == 32
|
||||
if (myFormat.depth == 24 && myFormat.redMax == 0xFF &&
|
||||
myFormat.greenMax == 0xFF && myFormat.blueMax == 0xFF) {
|
||||
if (!ReadFromRFBServer((char*)&tightPalette, rectColors * 3))
|
||||
return 0;
|
||||
for (i = rectColors - 1; i >= 0; i--) {
|
||||
palette[i] = RGB24_TO_PIXEL32(tightPalette[i*3],
|
||||
tightPalette[i*3+1],
|
||||
tightPalette[i*3+2]);
|
||||
}
|
||||
return (rectColors == 2) ? 1 : 8;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!ReadFromRFBServer((char*)&tightPalette, rectColors * (BPP / 8)))
|
||||
return 0;
|
||||
|
||||
return (rectColors == 2) ? 1 : 8;
|
||||
}
|
||||
|
||||
static void
|
||||
FilterPaletteBPP (int numRows, CARDBPP *dst)
|
||||
{
|
||||
int x, y, b, w;
|
||||
CARD8 *src = (CARD8 *)buffer;
|
||||
CARDBPP *palette = (CARDBPP *)tightPalette;
|
||||
|
||||
if (rectColors == 2) {
|
||||
w = (rectWidth + 7) / 8;
|
||||
for (y = 0; y < numRows; y++) {
|
||||
for (x = 0; x < rectWidth / 8; x++) {
|
||||
for (b = 7; b >= 0; b--)
|
||||
dst[y*rectWidth+x*8+7-b] = palette[src[y*w+x] >> b & 1];
|
||||
}
|
||||
for (b = 7; b >= 8 - rectWidth % 8; b--) {
|
||||
dst[y*rectWidth+x*8+7-b] = palette[src[y*w+x] >> b & 1];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (y = 0; y < numRows; y++)
|
||||
for (x = 0; x < rectWidth; x++)
|
||||
dst[y*rectWidth+x] = palette[(int)src[y*rectWidth+x]];
|
||||
}
|
||||
}
|
||||
|
||||
#if BPP != 8
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
*
|
||||
* JPEG decompression.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
The following variables are defined in rfbproto.c:
|
||||
static Bool jpegError;
|
||||
static struct jpeg_source_mgr jpegSrcManager;
|
||||
static JOCTET *jpegBufferPtr;
|
||||
static size_t *jpegBufferLen;
|
||||
*/
|
||||
|
||||
static Bool
|
||||
DecompressJpegRectBPP(int x, int y, int w, int h)
|
||||
{
|
||||
struct jpeg_decompress_struct cinfo;
|
||||
struct jpeg_error_mgr jerr;
|
||||
int compressedLen;
|
||||
CARD8 *compressedData;
|
||||
CARDBPP *pixelPtr;
|
||||
JSAMPROW rowPointer[1];
|
||||
int dx, dy;
|
||||
|
||||
compressedLen = (int)ReadCompactLen();
|
||||
if (compressedLen <= 0) {
|
||||
fprintf(stderr, "Incorrect data received from the server.\n");
|
||||
return False;
|
||||
}
|
||||
|
||||
compressedData = malloc(compressedLen);
|
||||
if (compressedData == NULL) {
|
||||
fprintf(stderr, "Memory allocation error.\n");
|
||||
return False;
|
||||
}
|
||||
|
||||
if (!ReadFromRFBServer((char*)compressedData, compressedLen)) {
|
||||
free(compressedData);
|
||||
return False;
|
||||
}
|
||||
|
||||
cinfo.err = jpeg_std_error(&jerr);
|
||||
jpeg_create_decompress(&cinfo);
|
||||
|
||||
JpegSetSrcManager(&cinfo, compressedData, compressedLen);
|
||||
|
||||
jpeg_read_header(&cinfo, TRUE);
|
||||
cinfo.out_color_space = JCS_RGB;
|
||||
|
||||
jpeg_start_decompress(&cinfo);
|
||||
if (cinfo.output_width != w || cinfo.output_height != h ||
|
||||
cinfo.output_components != 3) {
|
||||
fprintf(stderr, "Tight Encoding: Wrong JPEG data received.\n");
|
||||
jpeg_destroy_decompress(&cinfo);
|
||||
free(compressedData);
|
||||
return False;
|
||||
}
|
||||
|
||||
rowPointer[0] = (JSAMPROW)buffer;
|
||||
dy = 0;
|
||||
while (cinfo.output_scanline < cinfo.output_height) {
|
||||
jpeg_read_scanlines(&cinfo, rowPointer, 1);
|
||||
if (jpegError) {
|
||||
break;
|
||||
}
|
||||
pixelPtr = (CARDBPP *)&buffer[BUFFER_SIZE / 2];
|
||||
for (dx = 0; dx < w; dx++) {
|
||||
*pixelPtr++ =
|
||||
RGB24_TO_PIXEL(BPP, buffer[dx*3], buffer[dx*3+1], buffer[dx*3+2]);
|
||||
}
|
||||
CopyDataToScreen(&buffer[BUFFER_SIZE / 2], x, y + dy, w, 1);
|
||||
dy++;
|
||||
}
|
||||
|
||||
if (!jpegError)
|
||||
jpeg_finish_decompress(&cinfo);
|
||||
|
||||
jpeg_destroy_decompress(&cinfo);
|
||||
free(compressedData);
|
||||
|
||||
return !jpegError;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
161
client/vncauth.c
161
client/vncauth.c
|
@ -1,161 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 1999 AT&T Laboratories Cambridge. 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 program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* vncauth.c - Functions for VNC password management and authentication.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <vncauth.h>
|
||||
#include <d3des.h>
|
||||
|
||||
|
||||
/*
|
||||
* We use a fixed key to store passwords, since we assume that our local
|
||||
* file system is secure but nonetheless don't want to store passwords
|
||||
* as plaintext.
|
||||
*/
|
||||
|
||||
unsigned char fixedkey[8] = {23,82,107,6,35,78,88,7};
|
||||
|
||||
|
||||
/*
|
||||
* Encrypt a password and store it in a file. Returns 0 if successful,
|
||||
* 1 if the file could not be written.
|
||||
*/
|
||||
|
||||
int
|
||||
vncEncryptAndStorePasswd(char *passwd, char *fname)
|
||||
{
|
||||
FILE *fp;
|
||||
int i;
|
||||
unsigned char encryptedPasswd[8];
|
||||
|
||||
if ((fp = fopen(fname,"w")) == NULL) return 1;
|
||||
|
||||
chmod(fname, S_IRUSR|S_IWUSR);
|
||||
|
||||
/* pad password with nulls */
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (i < strlen(passwd)) {
|
||||
encryptedPasswd[i] = passwd[i];
|
||||
} else {
|
||||
encryptedPasswd[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Do encryption in-place - this way we overwrite our copy of the plaintext
|
||||
password */
|
||||
|
||||
deskey(fixedkey, EN0);
|
||||
des(encryptedPasswd, encryptedPasswd);
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
putc(encryptedPasswd[i], fp);
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Decrypt a password from a file. Returns a pointer to a newly allocated
|
||||
* string containing the password or a null pointer if the password could
|
||||
* not be retrieved for some reason.
|
||||
*/
|
||||
|
||||
char *
|
||||
vncDecryptPasswdFromFile(char *fname)
|
||||
{
|
||||
FILE *fp;
|
||||
int i, ch;
|
||||
unsigned char *passwd = (unsigned char *)malloc(9);
|
||||
|
||||
if ((fp = fopen(fname,"r")) == NULL) return NULL;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
ch = getc(fp);
|
||||
if (ch == EOF) {
|
||||
fclose(fp);
|
||||
return NULL;
|
||||
}
|
||||
passwd[i] = ch;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
deskey(fixedkey, DE1);
|
||||
des(passwd, passwd);
|
||||
|
||||
passwd[8] = 0;
|
||||
|
||||
return (char *)passwd;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Generate CHALLENGESIZE random bytes for use in challenge-response
|
||||
* authentication.
|
||||
*/
|
||||
|
||||
void
|
||||
vncRandomBytes(unsigned char *bytes)
|
||||
{
|
||||
int i;
|
||||
unsigned int seed = (unsigned int) time(0);
|
||||
|
||||
srandom(seed);
|
||||
for (i = 0; i < CHALLENGESIZE; i++) {
|
||||
bytes[i] = (unsigned char)(random() & 255);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Encrypt CHALLENGESIZE bytes in memory using a password.
|
||||
*/
|
||||
|
||||
void
|
||||
vncEncryptBytes(unsigned char *bytes, char *passwd)
|
||||
{
|
||||
unsigned char key[8];
|
||||
int i;
|
||||
|
||||
/* key is simply password padded with nulls */
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (i < strlen(passwd)) {
|
||||
key[i] = passwd[i];
|
||||
} else {
|
||||
key[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
deskey(key, EN0);
|
||||
|
||||
for (i = 0; i < CHALLENGESIZE; i += 8) {
|
||||
des(bytes+i, bytes+i);
|
||||
}
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 1999 AT&T Laboratories Cambridge. 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* vncauth.h - describes the functions provided by the vncauth library.
|
||||
*/
|
||||
|
||||
#define MAXPWLEN 8
|
||||
#define CHALLENGESIZE 16
|
||||
|
||||
extern int vncEncryptAndStorePasswd(char *passwd, char *fname);
|
||||
extern char *vncDecryptPasswdFromFile(char *fname);
|
||||
extern void vncRandomBytes(unsigned char *bytes);
|
||||
extern void vncEncryptBytes(unsigned char *bytes, char *passwd);
|
|
@ -1,205 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2000, 2001 Const Kaplinsky. All Rights Reserved.
|
||||
* Copyright (C) 2000 Tridia Corporation. All Rights Reserved.
|
||||
* Copyright (C) 1999 AT&T Laboratories Cambridge. 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* vncviewer.h
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#include <X11/IntrinsicP.h>
|
||||
#include <X11/StringDefs.h>
|
||||
#include <X11/Shell.h>
|
||||
#include <X11/Xmd.h>
|
||||
#include <X11/keysym.h>
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/Xmu/StdSel.h>
|
||||
|
||||
#if(defined __cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include "rfbproto.h"
|
||||
|
||||
extern int endianTest;
|
||||
|
||||
#define Swap16IfLE(s) \
|
||||
(*(char *)&endianTest ? ((((s) & 0xff) << 8) | (((s) >> 8) & 0xff)) : (s))
|
||||
|
||||
#define Swap32IfLE(l) \
|
||||
(*(char *)&endianTest ? ((((l) & 0xff000000) >> 24) | \
|
||||
(((l) & 0x00ff0000) >> 8) | \
|
||||
(((l) & 0x0000ff00) << 8) | \
|
||||
(((l) & 0x000000ff) << 24)) : (l))
|
||||
|
||||
#define MAX_ENCODINGS 20
|
||||
|
||||
#define FLASH_PORT_OFFSET 5400
|
||||
#define LISTEN_PORT_OFFSET 5500
|
||||
#define TUNNEL_PORT_OFFSET 5500
|
||||
#define SERVER_PORT_OFFSET 5900
|
||||
|
||||
#define DEFAULT_SSH_CMD "/usr/bin/ssh"
|
||||
#define DEFAULT_TUNNEL_CMD \
|
||||
(DEFAULT_SSH_CMD " -f -L %L:localhost:%R %H sleep 20")
|
||||
#define DEFAULT_VIA_CMD \
|
||||
(DEFAULT_SSH_CMD " -f -L %L:%H:%R %G sleep 20")
|
||||
|
||||
|
||||
/** main.cpp **/
|
||||
|
||||
typedef enum {
|
||||
QUALITY_UNKNOWN,
|
||||
QUALITY_HIGH,
|
||||
QUALITY_MEDIUM,
|
||||
QUALITY_LOW
|
||||
} Quality;
|
||||
|
||||
typedef struct {
|
||||
Bool shareDesktop;
|
||||
Bool viewOnly;
|
||||
|
||||
const char* encodingsString;
|
||||
|
||||
Bool useBGR233;
|
||||
int nColours;
|
||||
Bool useSharedColours;
|
||||
int requestedDepth;
|
||||
|
||||
int rawDelay;
|
||||
int copyRectDelay;
|
||||
|
||||
Bool debug;
|
||||
|
||||
int compressLevel;
|
||||
int qualityLevel;
|
||||
Bool useRemoteCursor;
|
||||
|
||||
} AppData;
|
||||
|
||||
extern AppData appData;
|
||||
|
||||
extern Display* dpy;
|
||||
extern const char *vncServerHost;
|
||||
extern int vncServerPort;
|
||||
|
||||
extern int isQuitFlagSet();
|
||||
extern void lockQt();
|
||||
extern void unlockQt();
|
||||
extern void unlockQtGui();
|
||||
extern int getPassword(char *passwd, int pwlen);
|
||||
|
||||
/* threads.cpp */
|
||||
extern void queueIncrementalUpdateRequest();
|
||||
|
||||
/* colour.c */
|
||||
|
||||
extern unsigned long BGR233ToPixel[];
|
||||
|
||||
extern Colormap cmap;
|
||||
extern Visual *vis;
|
||||
extern unsigned int visdepth, visbpp;
|
||||
|
||||
extern void SetVisualAndCmap(void);
|
||||
|
||||
/* cursor.c */
|
||||
|
||||
extern Bool HandleXCursor(int xhot, int yhot, int width, int height);
|
||||
extern Bool HandleRichCursor(int xhot, int yhot, int width, int height);
|
||||
extern void SoftCursorLockArea(int x, int y, int w, int h);
|
||||
extern void SoftCursorUnlockScreen(void);
|
||||
extern void SoftCursorMove(int x, int y);
|
||||
|
||||
/* desktop.c */
|
||||
|
||||
extern Widget form, viewport, desktop;
|
||||
extern Window desktopWin;
|
||||
extern Cursor dotCursor;
|
||||
extern GC gc;
|
||||
extern GC srcGC, dstGC;
|
||||
extern Dimension dpyWidth, dpyHeight;
|
||||
|
||||
extern void DesktopInit(Window win);
|
||||
extern void ToplevelInit(void);
|
||||
extern void SendRFBEvent(XEvent *event, String *params, Cardinal *num_params);
|
||||
extern void CopyDataToScreen(char *buf, int x, int y, int width, int height);
|
||||
extern void ShmSync(void);
|
||||
extern void Cleanup(void);
|
||||
|
||||
/* rfbproto.c */
|
||||
|
||||
extern int rfbsock;
|
||||
extern Bool canUseCoRRE;
|
||||
extern Bool canUseHextile;
|
||||
extern char *desktopName;
|
||||
extern rfbPixelFormat myFormat;
|
||||
extern rfbServerInitMsg si;
|
||||
extern char *serverCutText;
|
||||
extern Bool newServerCutText;
|
||||
|
||||
extern Bool ConnectToRFBServer(const char *hostname, int port);
|
||||
extern Bool InitialiseRFBConnection(void);
|
||||
extern Bool SetFormatAndEncodings(void);
|
||||
extern Bool SendIncrementalFramebufferUpdateRequest(void);
|
||||
extern Bool SendFramebufferUpdateRequest(int x, int y, int w, int h,
|
||||
Bool incremental);
|
||||
extern Bool SendPointerEvent(int x, int y, int buttonMask);
|
||||
extern Bool SendKeyEvent(CARD32 key, Bool down);
|
||||
extern Bool SendClientCutText(char *str, int len);
|
||||
extern Bool HandleRFBServerMessage(void);
|
||||
|
||||
extern void PrintPixelFormat(rfbPixelFormat *format);
|
||||
|
||||
/* selection.c */
|
||||
|
||||
extern void InitialiseSelection(void);
|
||||
extern void SelectionToVNC(Widget w, XEvent *event, String *params,
|
||||
Cardinal *num_params);
|
||||
extern void SelectionFromVNC(Widget w, XEvent *event, String *params,
|
||||
Cardinal *num_params);
|
||||
|
||||
/* shm.c */
|
||||
|
||||
extern XImage *CreateShmImage(void);
|
||||
extern void ShmCleanup(void);
|
||||
|
||||
/* sockets.c */
|
||||
|
||||
extern Bool errorMessageOnReadFailure;
|
||||
|
||||
extern Bool ReadFromRFBServer(char *out, unsigned int n);
|
||||
extern Bool WriteExact(int sock, char *buf, int n);
|
||||
extern int FindFreeTcpPort(void);
|
||||
extern int ListenAtTcpPort(int port);
|
||||
extern int ConnectToTcpAddr(unsigned int host, int port);
|
||||
extern int AcceptTcpConnection(int listenSock);
|
||||
extern Bool SetNonBlocking(int sock);
|
||||
|
||||
extern int StringToIPAddr(const char *str, unsigned int *addr);
|
||||
extern Bool SameMachine(int sock);
|
||||
|
||||
#if(defined __cplusplus)
|
||||
}
|
||||
#endif
|
157
client/zlib.c
157
client/zlib.c
|
@ -1,157 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2000 Tridia Corporation. All Rights Reserved.
|
||||
* Copyright (C) 1999 AT&T Laboratories Cambridge. 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* zlib.c - handle zlib encoding.
|
||||
*
|
||||
* This file shouldn't be compiled directly. It is included multiple times by
|
||||
* rfbproto.c, each time with a different definition of the macro BPP. For
|
||||
* each value of BPP, this file defines a function which handles an zlib
|
||||
* encoded rectangle with BPP bits per pixel.
|
||||
*/
|
||||
|
||||
#define HandleZlibBPP CONCAT2E(HandleZlib,BPP)
|
||||
#define CARDBPP CONCAT2E(CARD,BPP)
|
||||
|
||||
static Bool
|
||||
HandleZlibBPP (int rx, int ry, int rw, int rh)
|
||||
{
|
||||
rfbZlibHeader hdr;
|
||||
int remaining;
|
||||
int inflateResult;
|
||||
int toRead;
|
||||
|
||||
/* First make sure we have a large enough raw buffer to hold the
|
||||
* decompressed data. In practice, with a fixed BPP, fixed frame
|
||||
* buffer size and the first update containing the entire frame
|
||||
* buffer, this buffer allocation should only happen once, on the
|
||||
* first update.
|
||||
*/
|
||||
if ( raw_buffer_size < (( rw * rh ) * ( BPP / 8 ))) {
|
||||
|
||||
if ( raw_buffer != NULL ) {
|
||||
|
||||
free( raw_buffer );
|
||||
|
||||
}
|
||||
|
||||
raw_buffer_size = (( rw * rh ) * ( BPP / 8 ));
|
||||
raw_buffer = (char*) malloc( raw_buffer_size );
|
||||
|
||||
}
|
||||
|
||||
if (!ReadFromRFBServer((char *)&hdr, sz_rfbZlibHeader))
|
||||
return False;
|
||||
|
||||
remaining = Swap32IfLE(hdr.nBytes);
|
||||
|
||||
/* Need to initialize the decompressor state. */
|
||||
decompStream.next_in = ( Bytef * )buffer;
|
||||
decompStream.avail_in = 0;
|
||||
decompStream.next_out = ( Bytef * )raw_buffer;
|
||||
decompStream.avail_out = raw_buffer_size;
|
||||
decompStream.data_type = Z_BINARY;
|
||||
|
||||
/* Initialize the decompression stream structures on the first invocation. */
|
||||
if ( decompStreamInited == False ) {
|
||||
|
||||
inflateResult = inflateInit( &decompStream );
|
||||
|
||||
if ( inflateResult != Z_OK ) {
|
||||
fprintf(stderr,
|
||||
"inflateInit returned error: %d, msg: %s\n",
|
||||
inflateResult,
|
||||
decompStream.msg);
|
||||
return False;
|
||||
}
|
||||
|
||||
decompStreamInited = True;
|
||||
|
||||
}
|
||||
|
||||
inflateResult = Z_OK;
|
||||
|
||||
/* Process buffer full of data until no more to process, or
|
||||
* some type of inflater error, or Z_STREAM_END.
|
||||
*/
|
||||
while (( remaining > 0 ) &&
|
||||
( inflateResult == Z_OK )) {
|
||||
|
||||
if ( remaining > BUFFER_SIZE ) {
|
||||
toRead = BUFFER_SIZE;
|
||||
}
|
||||
else {
|
||||
toRead = remaining;
|
||||
}
|
||||
|
||||
/* Fill the buffer, obtaining data from the server. */
|
||||
if (!ReadFromRFBServer(buffer,toRead))
|
||||
return False;
|
||||
|
||||
decompStream.next_in = ( Bytef * )buffer;
|
||||
decompStream.avail_in = toRead;
|
||||
|
||||
/* Need to uncompress buffer full. */
|
||||
inflateResult = inflate( &decompStream, Z_SYNC_FLUSH );
|
||||
|
||||
/* We never supply a dictionary for compression. */
|
||||
if ( inflateResult == Z_NEED_DICT ) {
|
||||
fprintf(stderr,"zlib inflate needs a dictionary!\n");
|
||||
return False;
|
||||
}
|
||||
if ( inflateResult < 0 ) {
|
||||
fprintf(stderr,
|
||||
"zlib inflate returned error: %d, msg: %s\n",
|
||||
inflateResult,
|
||||
decompStream.msg);
|
||||
return False;
|
||||
}
|
||||
|
||||
/* Result buffer allocated to be at least large enough. We should
|
||||
* never run out of space!
|
||||
*/
|
||||
if (( decompStream.avail_in > 0 ) &&
|
||||
( decompStream.avail_out <= 0 )) {
|
||||
fprintf(stderr,"zlib inflate ran out of space!\n");
|
||||
return False;
|
||||
}
|
||||
|
||||
remaining -= toRead;
|
||||
|
||||
} /* while ( remaining > 0 ) */
|
||||
|
||||
if ( inflateResult == Z_OK ) {
|
||||
|
||||
/* Put the uncompressed contents of the update on the screen. */
|
||||
CopyDataToScreen(raw_buffer, rx, ry, rw, rh);
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
fprintf(stderr,
|
||||
"zlib inflate returned error: %d, msg: %s\n",
|
||||
inflateResult,
|
||||
decompStream.msg);
|
||||
return False;
|
||||
|
||||
}
|
||||
|
||||
return True;
|
||||
}
|
Loading…
Reference in New Issue
Block a user