Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
L
libvncserver
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
rasky
libvncserver
Commits
4d871894
Commit
4d871894
authored
Dec 06, 2002
by
dscho
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
compiler warnings, contrib directory, new x11vnc from Karl Runge
parent
d60fda11
Changes
8
Show whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
1389 additions
and
606 deletions
+1389
-606
CHANGES
CHANGES
+1
-0
Makefile
Makefile
+17
-14
x11vnc.c
contrib/x11vnc.c
+1352
-0
zippy.c
contrib/zippy.c
+0
-0
httpd.c
httpd.c
+2
-2
main.c
main.c
+1
-1
rfb.h
rfb.h
+16
-6
x11vnc.c
x11vnc.c
+0
-583
No files found.
CHANGES
View file @
4d871894
Better x11vnc from Karl J. Runge!
fixed severe bug (Const Kaplinsky)
fixed severe bug (Const Kaplinsky)
got patch from Const Kaplisnky with CursorPosUpdate encoding and some Docs
got patch from Const Kaplisnky with CursorPosUpdate encoding and some Docs
sync'ed with newest RealVNC (ZRLE encoding)
sync'ed with newest RealVNC (ZRLE encoding)
...
...
Makefile
View file @
4d871894
...
@@ -3,6 +3,7 @@ VNCSERVERLIB=-L. -lvncserver -L/usr/local/lib -lz -ljpeg
...
@@ -3,6 +3,7 @@ VNCSERVERLIB=-L. -lvncserver -L/usr/local/lib -lz -ljpeg
CXX
=
g++
CXX
=
g++
CC
=
gcc
CC
=
gcc
LINK
=
gcc
# for Solaris
# for Solaris
#EXTRALIBS=-lsocket -lnsl -L/usr/X/lib
#EXTRALIBS=-lsocket -lnsl -L/usr/X/lib
...
@@ -36,6 +37,7 @@ ZRLE_SRCS=zrle.cc rdr/FdInStream.cxx rdr/FdOutStream.cxx rdr/InStream.cxx \
...
@@ -36,6 +37,7 @@ ZRLE_SRCS=zrle.cc rdr/FdInStream.cxx rdr/FdOutStream.cxx rdr/InStream.cxx \
ZRLE_OBJS
=
zrle.o rdr/FdInStream.o rdr/FdOutStream.o rdr/InStream.o
\
ZRLE_OBJS
=
zrle.o rdr/FdInStream.o rdr/FdOutStream.o rdr/InStream.o
\
rdr/NullOutStream.o rdr/ZlibInStream.o rdr/ZlibOutStream.o
rdr/NullOutStream.o rdr/ZlibInStream.o rdr/ZlibOutStream.o
ZRLE_DEF
=
-DHAVE_ZRLE
ZRLE_DEF
=
-DHAVE_ZRLE
LINK
=
$(CXX)
%.o
:
%.cxx
%.o
:
%.cxx
$(CXX)
$(CXXFLAGS)
-c
-o
$@
$<
$(CXX)
$(CXXFLAGS)
-c
-o
$@
$<
...
@@ -75,52 +77,53 @@ libvncserver.a: $(OBJS)
...
@@ -75,52 +77,53 @@ libvncserver.a: $(OBJS)
translate.o
:
translate.c tableinit24.c tableinitcmtemplate.c tableinittctemplate.c tabletrans24template.c tabletranstemplate.c
translate.o
:
translate.c tableinit24.c tableinitcmtemplate.c tableinittctemplate.c tabletrans24template.c tabletranstemplate.c
example
:
example.o libvncserver.a
example
:
example.o libvncserver.a
$(
CC
)
-o
example example.o
$(LIBS)
$(
LINK
)
-o
example example.o
$(LIBS)
pnmshow
:
pnmshow.o libvncserver.a
pnmshow
:
pnmshow.o libvncserver.a
$(
CC
)
-o
pnmshow pnmshow.o
$(LIBS)
$(
LINK
)
-o
pnmshow pnmshow.o
$(LIBS)
mac.o
:
mac.c 1instance.c
mac.o
:
mac.c 1instance.c
OSXvnc-server
:
mac.o libvncserver.a
OSXvnc-server
:
mac.o libvncserver.a
$(
CC
)
-o
OSXvnc-server mac.o
$(LIBS)
$(OSX_LIBS)
$(
LINK
)
-o
OSXvnc-server mac.o
$(LIBS)
$(OSX_LIBS)
x11vnc.o
:
x11vnc.c 1instance.c
x11vnc.o
:
contrib/x11vnc.c rfb.h 1instance.c Makefile
$(CC)
$(CFLAGS)
-I
.
-c
-o
x11vnc.o contrib/x11vnc.c
x11vnc
:
x11vnc.o libvncserver.a
x11vnc
:
x11vnc.o libvncserver.a
$(
CC
)
-g
-o
x11vnc x11vnc.o
$(LIBS)
$(XLIBS)
$(
LINK
)
-g
-o
x11vnc x11vnc.o
$(LIBS)
$(XLIBS)
x11vnc_static
:
x11vnc.o libvncserver.a
x11vnc_static
:
x11vnc.o libvncserver.a
$(
CC
)
-o
x11vnc_static x11vnc.o libvncserver.a /usr/lib/libz.a /usr/lib/libjpeg.a
$(XLIBS)
$(
LINK
)
-o
x11vnc_static x11vnc.o libvncserver.a /usr/lib/libz.a /usr/lib/libjpeg.a
$(XLIBS)
#$(LIBS) $(XLIBS)
#$(LIBS) $(XLIBS)
storepasswd
:
storepasswd.o d3des.o vncauth.o
storepasswd
:
storepasswd.o d3des.o vncauth.o
$(
CC
)
-o
storepasswd storepasswd.o d3des.o vncauth.o
$(
LINK
)
-o
storepasswd storepasswd.o d3des.o vncauth.o
sratest
:
sratest.o
sratest
:
sratest.o
$(
CC
)
-o
sratest sratest.o
$(
LINK
)
-o
sratest sratest.o
sratest.o
:
sraRegion.c
sratest.o
:
sraRegion.c
$(CC)
$(CFLAGS)
-DSRA_TEST
-c
-o
sratest.o sraRegion.c
$(CC)
$(CFLAGS)
-DSRA_TEST
-c
-o
sratest.o sraRegion.c
blooptest
:
blooptest.o libvncserver.a
blooptest
:
blooptest.o libvncserver.a
$(
CC
)
-o
blooptest blooptest.o
$(LIBS)
$(
LINK
)
-o
blooptest blooptest.o
$(LIBS)
blooptest.o
:
example.c rfb.h
blooptest.o
:
example.c rfb.h
$(CC)
$(CFLAGS)
-DBACKGROUND_LOOP_TEST
-c
-o
blooptest.o example.c
$(CC)
$(CFLAGS)
-DBACKGROUND_LOOP_TEST
-c
-o
blooptest.o example.c
pnmshow24
:
pnmshow24.o libvncserver.a
pnmshow24
:
pnmshow24.o libvncserver.a
$(
CC
)
-o
pnmshow24 pnmshow24.o
$(LIBS)
$(
LINK
)
-o
pnmshow24 pnmshow24.o
$(LIBS)
fontsel
:
fontsel.o libvncserver.a
fontsel
:
fontsel.o libvncserver.a
$(
CC
)
-o
fontsel fontsel.o
-L
.
-lvncserver
-lz
-ljpeg
$(
LINK
)
-o
fontsel fontsel.o
-L
.
-lvncserver
-lz
-ljpeg
vncev
:
vncev.o libvncserver.a
vncev
:
vncev.o libvncserver.a
$(
CC
)
-o
vncev vncev.o
-L
.
-lvncserver
-lz
-ljpeg
$(
LINK
)
-o
vncev vncev.o
-L
.
-lvncserver
-lz
-ljpeg
# Example from Justin
# Example from Justin
zippy
:
zippy.o libvncserver.a
zippy
:
contrib/
zippy.o libvncserver.a
$(
CC)
-o
zippy
zippy.o
-L
.
-lvncserver
-lz
-ljpeg
$(
LINK)
-o
zippy contrib/
zippy.o
-L
.
-lvncserver
-lz
-ljpeg
clean
:
clean
:
rm
-f
$(OBJS)
*
~ core
"#"
*
*
.bak
*
.orig storepasswd.o
\
rm
-f
$(OBJS)
*
~ core
"#"
*
*
.bak
*
.orig storepasswd.o
\
...
...
contrib/x11vnc.c
0 → 100644
View file @
4d871894
/*
* x0vnc.c: a VNC server for X displays.
*
* Copyright (c) 2002 Karl J. Runge <runge@karlrunge.com> 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.
*
*
* This program is based heavily on the following programs:
*
* x11vnc.c of the libvncserver project (Johannes E. Schindelin)
* krfb, the KDE desktopsharing project (Tim Jansen)
* x0rfbserver, the original native X vnc server (Jens Wagner)
*
* The primary goal of this program is to create a portable and simple
* command-line server utility that allows a VNC viewer to connect to an
* actual X display (as x11vnc, krfb, and x0rfbserver do). The only
* non-standard dependency of this program is the static library
* libvncserver.a (although in some environments libjpeg.so may not be
* readily available). To increase portability it is written in plain C.
*
* The next goal is to improve performance and interactive response.
* The algorithm currently used here to achieve this is that of krfb
* (based on x0rfbserver algorithm). Additional heuristics are also
* applied. Currently there are a bit too many of these...
*
* To build:
* Obtain the libvncserver package (http://libvncserver.sourceforge.net)
* and ensure that "make" and "make x11vnc" work correctly. Defining
* HAVE_PTHREADS in the Makefile is recommended. One then could move the
* x11vnc.c file aside, copy this file in its place into the source tree,
* and issue:
*
* make x11vnc
* mv x11vnc x0vnc
*
* to create the x0vnc binary. Otherwise, with x0vnc.c copied to
* libvncserver source directory, something like this should work:
*
* gcc -Wall -DALLOW24BPP -I. -DBACKCHANNEL -c x0vnc.c
* gcc -o x0vnc x0vnc.o -L. -lvncserver -L/usr/local/lib -lz -ljpeg \
* -L/usr/X11R6/lib -lX11 -lXext -lXtst
*
* include -DHAVE_PTHREADS ... -lpthread to use threads.
*
* On Solaris the 2nd command might look something like:
*
* gcc -o x0vnc x0vnc.o -L. -lvncserver -L/usr/local/lib -lz -ljpeg \
* -lsocket -lnsl -L/usr/X/lib -R/usr/X/lib -lX11 -lXext -lXtst
*/
#define KeySym RFBKeySym
#include "rfb.h"
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/XShm.h>
#include <X11/extensions/XTest.h>
#include <X11/keysym.h>
Display
*
dpy
=
0
;
int
dpy_x
,
dpy_y
;
int
bpp
;
int
window
;
int
button_mask
=
0
;
XImage
*
tile
;
XImage
*
scanline
;
XImage
*
fullscreen
;
int
fs_factor
=
0
;
XShmSegmentInfo
tile_shm
;
XShmSegmentInfo
scanline_shm
;
XShmSegmentInfo
fullscreen_shm
;
rfbScreenInfoPtr
screen
;
rfbCursorPtr
cursor
;
int
bytes_per_line
;
/* size of the basic tile unit that is polled for changes: */
int
tile_x
=
32
;
int
tile_y
=
32
;
int
ntiles
,
ntiles_x
,
ntiles_y
;
/* arrays that indicate changed or checked tiles. */
char
*
tile_has_diff
,
*
tile_tried
;
typedef
struct
tile_change_region
{
short
first_line
,
last_line
;
/* start and end lines, along y, */
/* of the changed area inside a tile. */
short
left_diff
,
right_diff
;
/* info about differences along edges. */
short
top_diff
,
bot_diff
;
}
region_t
;
/* array to hold the tiles region_t-s. */
region_t
*
tile_region
;
typedef
struct
hint
{
/* location x, y, height, and width of a change-rectangle */
/* (grows as adjacent horizontal tiles are glued together) */
int
x
,
y
,
w
,
h
;
}
hint_t
;
/* array to hold the hints: */
hint_t
*
hint_list
;
int
shared
=
0
;
/* share vnc display. */
int
view_only
=
0
;
/* client can only watch. */
int
connect_once
=
1
;
/* allow only one client connection. */
/*
* waitms is the msec to wait between screen polls. Not too old h/w shows
* poll times of 15-35ms, so maybe this value cuts the rest load by 2 or so.
*/
int
waitms
=
30
;
int
defer_update
=
30
;
/* rfbDeferUpdateTime ms to wait before sends. */
int
use_threads
=
1
;
/* but only if compiled with HAVE_PTHREADS */
/* tile heuristics: */
int
use_hints
=
1
;
/* use the krfb scheme of gluing tiles together. */
int
tile_fuzz
=
2
;
/* tolerance for suspecting changed tiles touching */
/* a known changed tile. */
int
grow_fill
=
3
;
/* do the grow islands heuristic with this width. */
int
gaps_fill
=
4
;
/* do a final pass to try to fill gaps between tiles. */
double
fs_frac
=
0
.
5
;
/* threshold tile fraction to do fullscreen updates. */
#define NSCAN 32
int
scanlines
[
NSCAN
]
=
{
/* scan pattern jitter from x0rfbserver */
0
,
16
,
8
,
24
,
4
,
20
,
12
,
28
,
10
,
26
,
18
,
2
,
22
,
6
,
30
,
14
,
1
,
17
,
9
,
25
,
7
,
23
,
15
,
31
,
19
,
3
,
27
,
11
,
29
,
13
,
5
,
21
};
int
got_user_input
;
int
count
=
0
;
int
shut_down
=
0
;
/*
* Not sure why... but when threaded we have to mutex our X11 calls to
* avoid XIO crashes. This should not be too bad since keyboard and pointer
* updates are infrequent compared to the scanning. (note: these lines are
* noops unless HAVE_PTHREADS) XXX: what is going on?
*/
MUTEX
(
x11Mutex
);
#define X_LOCK LOCK(x11Mutex);
#define X_UNLOCK UNLOCK(x11Mutex);
void
mark_hint
(
hint_t
);
void
clean_up_exit
(
void
)
{
X_LOCK
XTestDiscard
(
dpy
);
/* remove the shm areas: */
XShmDetach
(
dpy
,
&
tile_shm
);
XDestroyImage
(
tile
);
shmdt
(
tile_shm
.
shmaddr
);
shmctl
(
tile_shm
.
shmid
,
IPC_RMID
,
0
);
XShmDetach
(
dpy
,
&
scanline_shm
);
XDestroyImage
(
scanline
);
shmdt
(
scanline_shm
.
shmaddr
);
shmctl
(
scanline_shm
.
shmid
,
IPC_RMID
,
0
);
XShmDetach
(
dpy
,
&
fullscreen_shm
);
XDestroyImage
(
fullscreen
);
shmdt
(
fullscreen_shm
.
shmaddr
);
shmctl
(
fullscreen_shm
.
shmid
,
IPC_RMID
,
0
);
/* more cleanup? */
X_UNLOCK
exit
(
0
);
}
void
client_gone
(
rfbClientPtr
client
)
{
if
(
connect_once
)
{
printf
(
"only one connection allowed.
\n
"
);
clean_up_exit
();
}
}
enum
rfbNewClientAction
new_client
(
rfbClientPtr
client
)
{
if
(
connect_once
)
{
client
->
clientGoneHook
=
client_gone
;
}
if
(
view_only
)
{
client
->
clientData
=
(
void
*
)
-
1
;
}
else
{
client
->
clientData
=
(
void
*
)
0
;
}
return
(
RFB_CLIENT_ACCEPT
);
}
/* key event handler */
static
void
keyboard
(
Bool
down
,
KeySym
keysym
,
rfbClientPtr
client
)
{
KeyCode
k
;
if
(
view_only
)
{
return
;
}
X_LOCK
k
=
XKeysymToKeycode
(
dpy
,
keysym
);
if
(
k
!=
NoSymbol
)
{
XTestFakeKeyEvent
(
dpy
,
k
,
down
,
CurrentTime
);
XFlush
(
dpy
);
got_user_input
++
;
}
X_UNLOCK
}
/* mouse event handler */
static
void
pointer
(
int
mask
,
int
x
,
int
y
,
rfbClientPtr
client
)
{
int
i
;
if
(
view_only
)
{
return
;
}
X_LOCK
XTestFakeMotionEvent
(
dpy
,
0
,
x
,
y
,
CurrentTime
);
got_user_input
++
;
for
(
i
=
0
;
i
<
5
;
i
++
)
{
if
(
(
button_mask
&
(
1
<<
i
))
!=
(
mask
&
(
1
<<
i
))
)
{
XTestFakeButtonEvent
(
dpy
,
i
+
1
,
(
mask
&
(
1
<<
i
))
?
True
:
False
,
CurrentTime
);
}
}
X_UNLOCK
/* remember the button state for next time: */
button_mask
=
mask
;
}
/* simple fixed cursor */
static
char
*
cur_data
=
" "
" "
" x "
" xx "
" xxx "
" xxxx "
" xxxxx "
" xxxxxx "
" xxxxxxx "
" xxxxxxxx "
" xxxxx "
" xx xx "
" x xx "
" xx "
" xx "
" xx "
" "
" "
;
static
char
*
cur_mask
=
" "
" xx "
" xxx "
" xxxx "
" xxxxx "
" xxxxxx "
" xxxxxxx "
" xxxxxxxx "
" xxxxxxxxx "
" xxxxxxxxxx "
" xxxxxxxxxx "
" xxxxxxx "
" xxx xxxx "
" xx xxxx "
" xxxx "
" xxxx "
" xx "
" "
;
int
cursor_x
=
18
;
int
cursor_y
=
18
;
void
initialize_screen
(
int
*
argc
,
char
**
argv
,
XImage
*
fb
)
{
screen
=
rfbGetScreen
(
argc
,
argv
,
fb
->
width
,
fb
->
height
,
fb
->
bits_per_pixel
,
8
,
fb
->
bits_per_pixel
/
8
);
screen
->
paddedWidthInBytes
=
fb
->
bytes_per_line
;
screen
->
rfbServerFormat
.
bitsPerPixel
=
fb
->
bits_per_pixel
;
screen
->
rfbServerFormat
.
depth
=
fb
->
depth
;
screen
->
rfbServerFormat
.
trueColour
=
(
CARD8
)
TRUE
;
if
(
screen
->
rfbServerFormat
.
bitsPerPixel
==
8
)
{
/* 8 bpp */
screen
->
rfbServerFormat
.
redShift
=
0
;
screen
->
rfbServerFormat
.
greenShift
=
2
;
screen
->
rfbServerFormat
.
blueShift
=
5
;
screen
->
rfbServerFormat
.
redMax
=
3
;
screen
->
rfbServerFormat
.
greenMax
=
7
;
screen
->
rfbServerFormat
.
blueMax
=
3
;
}
else
{
/* general case ... */
screen
->
rfbServerFormat
.
redShift
=
0
;
if
(
fb
->
red_mask
)
{
while
(
!
(
fb
->
red_mask
&
(
1
<<
screen
->
rfbServerFormat
.
redShift
)
)
)
{
screen
->
rfbServerFormat
.
redShift
++
;
}
}
screen
->
rfbServerFormat
.
greenShift
=
0
;
if
(
fb
->
green_mask
)
{
while
(
!
(
fb
->
green_mask
&
(
1
<<
screen
->
rfbServerFormat
.
greenShift
)
)
)
{
screen
->
rfbServerFormat
.
greenShift
++
;
}
}
screen
->
rfbServerFormat
.
blueShift
=
0
;
if
(
fb
->
blue_mask
)
{
while
(
!
(
fb
->
blue_mask
&
(
1
<<
screen
->
rfbServerFormat
.
blueShift
)
)
)
{
screen
->
rfbServerFormat
.
blueShift
++
;
}
}
screen
->
rfbServerFormat
.
redMax
=
fb
->
red_mask
>>
screen
->
rfbServerFormat
.
redShift
;
screen
->
rfbServerFormat
.
greenMax
=
fb
->
green_mask
>>
screen
->
rfbServerFormat
.
greenShift
;
screen
->
rfbServerFormat
.
blueMax
=
fb
->
blue_mask
>>
screen
->
rfbServerFormat
.
blueShift
;
}
screen
->
frameBuffer
=
fb
->
data
;
/* XXX the following 3 settings are based on libvncserver defaults. */
if
(
screen
->
rfbPort
==
5900
)
{
screen
->
autoPort
=
TRUE
;
}
if
(
screen
->
rfbDeferUpdateTime
==
5
)
{
screen
->
rfbDeferUpdateTime
=
defer_update
;
}
if
(
shared
&&
!
screen
->
rfbNeverShared
)
{
screen
->
rfbAlwaysShared
=
TRUE
;
}
/* event callbacks: */
screen
->
newClientHook
=
new_client
;
screen
->
kbdAddEvent
=
keyboard
;
screen
->
ptrAddEvent
=
pointer
;
cursor
=
rfbMakeXCursor
(
cursor_x
,
cursor_y
,
cur_data
,
cur_mask
);
screen
->
cursor
=
cursor
;
rfbInitServer
(
screen
);
bytes_per_line
=
screen
->
paddedWidthInBytes
;
bpp
=
screen
->
rfbServerFormat
.
bitsPerPixel
;
}
/*
* setup tile numbers and allocate the tile and hint arrays:
*/
void
initialize_tiles
()
{
ntiles_x
=
(
dpy_x
-
1
)
/
tile_x
+
1
;
ntiles_y
=
(
dpy_y
-
1
)
/
tile_y
+
1
;
ntiles
=
ntiles_x
*
ntiles_y
;
tile_has_diff
=
(
char
*
)
malloc
((
size_t
)
(
ntiles
*
sizeof
(
char
)));
tile_tried
=
(
char
*
)
malloc
((
size_t
)
(
ntiles
*
sizeof
(
char
)));
tile_region
=
(
region_t
*
)
malloc
((
size_t
)
(
ntiles
*
sizeof
(
region_t
)));
/* there will never be more hints than tiles: */
hint_list
=
(
hint_t
*
)
malloc
((
size_t
)
(
ntiles
*
sizeof
(
hint_t
)));
}
/*
* silly function to factor dpy_y until fullscreen shm is not bigger than max.
* should always work unless dpy_y is a large prime or something... under
* failure fs_factor remains 0 and no fullscreen updates will be tried.
*/
void
set_fs_factor
(
int
max
)
{
int
f
,
fac
=
1
,
n
=
dpy_y
;
if
(
(
bpp
/
8
)
*
dpy_x
*
dpy_y
<=
max
)
{
fs_factor
=
1
;
return
;
}
for
(
f
=
2
;
f
<=
101
;
f
++
)
{
while
(
n
%
f
==
0
)
{
n
=
n
/
f
;
fac
=
fac
*
f
;
if
(
(
bpp
/
8
)
*
dpy_x
*
(
dpy_y
/
fac
)
<=
max
)
{
fs_factor
=
fac
;
return
;
}
}
}
}
void
initialize_shm
()
{
/* the tile (e.g. 32x32) shared memory area image: */
tile
=
XShmCreateImage
(
dpy
,
DefaultVisual
(
dpy
,
0
),
bpp
,
ZPixmap
,
NULL
,
&
tile_shm
,
tile_x
,
tile_y
);
tile_shm
.
shmid
=
shmget
(
IPC_PRIVATE
,
tile
->
bytes_per_line
*
tile
->
height
,
IPC_CREAT
|
0777
);
tile_shm
.
shmaddr
=
tile
->
data
=
(
char
*
)
shmat
(
tile_shm
.
shmid
,
0
,
0
);
tile_shm
.
readOnly
=
False
;
XShmAttach
(
dpy
,
&
tile_shm
);
/* the scanline (e.g. 1280x1) shared memory area image: */
scanline
=
XShmCreateImage
(
dpy
,
DefaultVisual
(
dpy
,
0
),
bpp
,
ZPixmap
,
NULL
,
&
scanline_shm
,
dpy_x
,
1
);
scanline_shm
.
shmid
=
shmget
(
IPC_PRIVATE
,
scanline
->
bytes_per_line
*
scanline
->
height
,
IPC_CREAT
|
0777
);
scanline_shm
.
shmaddr
=
scanline
->
data
=
(
char
*
)
shmat
(
scanline_shm
.
shmid
,
0
,
0
);
scanline_shm
.
readOnly
=
False
;
XShmAttach
(
dpy
,
&
scanline_shm
);
/*
* the fullscreen (e.g. 1280x1024/fs_factor) shared memory area image:
* (we cut down the size of the shm area to try avoid and shm segment
* limits, e.g. the default 1MB on Solaris)
*/
set_fs_factor
(
1024
*
1024
);
if
(
!
fs_factor
)
{
printf
(
"warning: fullscreen updates are disabled.
\n
"
);
return
;
}
fullscreen
=
XShmCreateImage
(
dpy
,
DefaultVisual
(
dpy
,
0
),
bpp
,
ZPixmap
,
NULL
,
&
fullscreen_shm
,
dpy_x
,
dpy_y
/
fs_factor
);
fullscreen_shm
.
shmid
=
shmget
(
IPC_PRIVATE
,
fullscreen
->
bytes_per_line
*
fullscreen
->
height
,
IPC_CREAT
|
0777
);
fullscreen_shm
.
shmaddr
=
fullscreen
->
data
=
(
char
*
)
shmat
(
fullscreen_shm
.
shmid
,
0
,
0
);
fullscreen_shm
.
readOnly
=
False
;
XShmAttach
(
dpy
,
&
fullscreen_shm
);
}
/*
* A hint is a rectangular region built from 1 or more adjacent tiles
* glued together. Ultimately, this information in a single hint is sent
* to libvncserver rather than sending each tile separately.
*/
void
create_tile_hint
(
int
x
,
int
y
,
int
th
,
hint_t
*
hint
)
{
int
w
=
dpy_x
-
x
;
int
h
=
dpy_y
-
y
;
if
(
w
>
tile_x
)
{
w
=
tile_x
;
}
if
(
h
>
th
)
{
h
=
th
;
}
hint
->
x
=
x
;
hint
->
y
=
y
;
hint
->
w
=
w
;
hint
->
h
=
h
;
}
void
extend_tile_hint
(
int
x
,
int
y
,
int
th
,
hint_t
*
hint
)
{
int
w
=
dpy_x
-
x
;
int
h
=
dpy_y
-
y
;
if
(
w
>
tile_x
)
{
w
=
tile_x
;
}
if
(
h
>
th
)
{
h
=
th
;
}
if
(
hint
->
x
>
x
)
{
/* extend to the left */
hint
->
w
+=
hint
->
x
-
x
;
hint
->
x
=
x
;
}
if
(
hint
->
y
>
y
)
{
/* extend upward */
hint
->
h
+=
hint
->
y
-
y
;
hint
->
y
=
y
;
}
if
(
hint
->
x
+
hint
->
w
<
x
+
w
)
{
/* extend to the right */
hint
->
w
=
x
+
w
-
hint
->
x
;
}
if
(
hint
->
y
+
hint
->
h
<
y
+
h
)
{
/* extend downward */
hint
->
h
=
y
+
h
-
hint
->
y
;
}
}
void
save_hint
(
hint_t
hint
,
int
loc
)
{
/* copy it to the global array: */
hint_list
[
loc
].
x
=
hint
.
x
;
hint_list
[
loc
].
y
=
hint
.
y
;
hint_list
[
loc
].
w
=
hint
.
w
;
hint_list
[
loc
].
h
=
hint
.
h
;
}
/*
* Glue together horizontal "runs" of adjacent changed tiles into one big
* rectangle change "hint" to be passed to the vnc machinery.
*/
void
hint_updates
()
{
hint_t
hint
;
int
x
,
y
,
i
,
n
,
ty
,
th
;
int
hint_count
=
0
,
in_run
=
0
;
for
(
y
=
0
;
y
<
ntiles_y
;
y
++
)
{
for
(
x
=
0
;
x
<
ntiles_x
;
x
++
)
{
n
=
x
+
y
*
ntiles_x
;
if
(
tile_has_diff
[
n
])
{
ty
=
tile_region
[
n
].
first_line
;
th
=
tile_region
[
n
].
last_line
-
ty
+
1
;
if
(
!
in_run
)
{
create_tile_hint
(
x
*
tile_x
,
y
*
tile_y
+
ty
,
th
,
&
hint
);
in_run
=
1
;
}
else
{
extend_tile_hint
(
x
*
tile_x
,
y
*
tile_y
+
ty
,
th
,
&
hint
);
}
}
else
{
if
(
in_run
)
{
/* end of a row run of altered tiles: */
save_hint
(
hint
,
hint_count
++
);
in_run
=
0
;
}
}
}
if
(
in_run
)
{
/* save the last row run */
save_hint
(
hint
,
hint_count
++
);
in_run
=
0
;
}
}
for
(
i
=
0
;
i
<
hint_count
;
i
++
)
{
/* pass update info to vnc: */
mark_hint
(
hint_list
[
i
]);
}
}
/*
* Notifies libvncserver of a changed hint rectangle.
*/
void
mark_hint
(
hint_t
hint
)
{
int
x
=
hint
.
x
;
int
y
=
hint
.
y
;
int
w
=
hint
.
w
;
int
h
=
hint
.
h
;
rfbMarkRectAsModified
(
screen
,
x
,
y
,
x
+
w
,
y
+
h
);
}
/*
* Notifies libvncserver of a changed tile rectangle.
*/
void
mark_tile
(
int
x
,
int
y
,
int
height
)
{
int
w
=
dpy_x
-
x
;
int
h
=
dpy_y
-
y
;
if
(
w
>
tile_x
)
{
w
=
tile_x
;
}
/* height is the height of the changed portion of the tile */
if
(
h
>
height
)
{
h
=
height
;
}
rfbMarkRectAsModified
(
screen
,
x
,
y
,
x
+
w
,
y
+
h
);
}
/*
* Simply send each modified tile separately to the vnc machinery:
* (i.e. no hints)
*/
void
tile_updates
()
{
int
x
,
y
,
n
,
ty
,
th
;
for
(
y
=
0
;
y
<
ntiles_y
;
y
++
)
{
for
(
x
=
0
;
x
<
ntiles_x
;
x
++
)
{
n
=
x
+
y
*
ntiles_x
;
if
(
tile_has_diff
[
n
])
{
ty
=
tile_region
[
n
].
first_line
;
th
=
tile_region
[
n
].
last_line
-
ty
+
1
;
mark_tile
(
x
*
tile_x
,
y
*
tile_y
+
ty
,
th
);
}
}
}
}
/*
* copy_tile() is called on a tile with a known change (from a scanline
* diff) or a suspected change (from our various heuristics).
*
* Examine the whole tile for the y-range of difference, copy that
* image difference to the vnc framebuffer, and do bookkeepping wrt
* the y-range and edge differences.
*
* This call is somewhat costly, maybe 1-2 ms. Primarily the XShmGetImage
* and then the memcpy/memcmp.
*/
void
copy_tile
(
int
tx
,
int
ty
)
{
int
x
,
y
,
line
,
first_line
,
last_line
;
int
size_x
,
size_y
,
n
,
dw
,
dx
;
int
pixelsize
=
bpp
>>
3
;
short
l_diff
=
0
,
r_diff
=
0
;
char
*
src
,
*
dst
,
*
s_src
,
*
s_dst
,
*
m_src
,
*
m_dst
;
char
*
h_src
,
*
h_dst
;
x
=
tx
*
tile_x
;
y
=
ty
*
tile_y
;
size_x
=
dpy_x
-
x
;
if
(
size_x
>
tile_x
)
{
size_x
=
tile_x
;
}
size_y
=
dpy_y
-
y
;
if
(
size_y
>
tile_y
)
{
size_y
=
tile_y
;
}
n
=
tx
+
ty
*
ntiles_x
;
/* number of the tile */
X_LOCK
if
(
size_x
==
tile_x
&&
size_y
==
tile_y
)
{
/* general case: */
XShmGetImage
(
dpy
,
window
,
tile
,
x
,
y
,
AllPlanes
);
}
else
{
/*
* near bottom or rhs edge case:
* (but only if tile size does not divide screen size)
*/
XGetSubImage
(
dpy
,
window
,
x
,
y
,
size_x
,
size_y
,
AllPlanes
,
ZPixmap
,
tile
,
0
,
0
);
}
X_UNLOCK
src
=
(
unsigned
char
*
)
tile
->
data
;
dst
=
screen
->
frameBuffer
+
y
*
bytes_per_line
+
x
*
pixelsize
;
s_src
=
src
;
s_dst
=
dst
;
first_line
=
-
1
;
/* find the first line with difference: */
for
(
line
=
0
;
line
<
size_y
;
line
++
)
{
if
(
memcmp
(
s_dst
,
s_src
,
size_x
*
pixelsize
)
)
{
first_line
=
line
;
break
;
}
s_src
+=
tile
->
bytes_per_line
;
s_dst
+=
bytes_per_line
;
}
tile_tried
[
n
]
=
1
;
if
(
first_line
==
-
1
)
{
/* tile has no difference, note it and get out: */
tile_has_diff
[
n
]
=
0
;
return
;
}
else
{
/*
* make sure it is recorded (e.g. sometimes we guess tiles
* and they came in with tile_has_diff 0)
*/
tile_has_diff
[
n
]
=
1
;
}
m_src
=
src
+
(
tile
->
bytes_per_line
*
size_y
);
m_dst
=
dst
+
(
bytes_per_line
*
size_y
);
last_line
=
first_line
;
/* find the last line with difference: */
for
(
line
=
size_y
-
1
;
line
>
first_line
;
line
--
)
{
m_src
-=
tile
->
bytes_per_line
;
m_dst
-=
bytes_per_line
;
if
(
memcmp
(
m_dst
,
m_src
,
size_x
*
pixelsize
)
)
{
last_line
=
line
;
break
;
}
}
/* look for differences on left and right hand edges: */
dx
=
(
size_x
-
tile_fuzz
)
*
pixelsize
;
dw
=
tile_fuzz
*
pixelsize
;
h_src
=
src
;
h_dst
=
dst
;
for
(
line
=
0
;
line
<
size_y
;
line
++
)
{
if
(
!
l_diff
&&
memcmp
(
h_dst
,
h_src
,
dw
)
)
{
l_diff
=
1
;
}
if
(
!
r_diff
&&
memcmp
(
h_dst
+
dx
,
h_src
+
dx
,
dw
)
)
{
r_diff
=
1
;
}
if
(
l_diff
&&
r_diff
)
{
break
;
}
h_src
+=
tile
->
bytes_per_line
;
h_dst
+=
bytes_per_line
;
}
/* now copy the difference to the vnc framebuffer: */
for
(
line
=
first_line
;
line
<=
last_line
;
line
++
)
{
memcpy
(
s_dst
,
s_src
,
size_x
*
pixelsize
);
s_src
+=
tile
->
bytes_per_line
;
s_dst
+=
bytes_per_line
;
}
/* record all the info in the region array for this tile: */
tile_region
[
n
].
first_line
=
first_line
;
tile_region
[
n
].
last_line
=
last_line
;
tile_region
[
n
].
left_diff
=
l_diff
;
tile_region
[
n
].
right_diff
=
r_diff
;
tile_region
[
n
].
top_diff
=
0
;
tile_region
[
n
].
bot_diff
=
0
;
if
(
first_line
<
tile_fuzz
)
{
tile_region
[
n
].
top_diff
=
1
;
}
if
(
last_line
>
(
size_y
-
1
)
-
tile_fuzz
)
{
tile_region
[
n
].
bot_diff
=
1
;
}
}
/*
* The copy_tile() call in the loop below copies the changed tile into
* the vnc framebuffer. Note that copy_tile() sets the tile_region
* struct to have info about the y-range of the changed region and also
* whether the tile edges contain diffs (within distance tile_fuzz).
*
* We use this tile_region info to try to guess if the downward and right
* tiles will have diffs. These tiles will be checked later in the loop
* (since y+1 > y and x+1 > x).
*
* See copy_tiles_backward_pass() for analogous checking upward and
* left tiles.
*/
void
copy_all_tiles
()
{
int
x
,
y
,
n
,
m
;
for
(
y
=
0
;
y
<
ntiles_y
;
y
++
)
{
for
(
x
=
0
;
x
<
ntiles_x
;
x
++
)
{
n
=
x
+
y
*
ntiles_x
;
if
(
tile_has_diff
[
n
])
{
copy_tile
(
x
,
y
);
}
if
(
!
tile_has_diff
[
n
])
{
/*
* n.b. copy_tile() may have detected
* no change and reset tile_has_diff to 0.
*/
continue
;
}
/* neighboring tile downward: */
if
(
(
y
+
1
)
<
ntiles_y
&&
tile_region
[
n
].
bot_diff
)
{
m
=
x
+
(
y
+
1
)
*
ntiles_x
;
if
(
!
tile_has_diff
[
m
])
{
tile_has_diff
[
m
]
=
1
;
}
}
/* neighboring tile to right: */
if
(
(
x
+
1
)
<
ntiles_x
&&
tile_region
[
n
].
right_diff
)
{
m
=
(
x
+
1
)
+
y
*
ntiles_x
;
if
(
!
tile_has_diff
[
m
])
{
tile_has_diff
[
m
]
=
1
;
}
}
}
}
}
/*
* Here starts a bunch of heuristics to guess/detect changed tiles.
* They are:
* copy_tiles_backward_pass, fill_tile_gaps/gap_try, grow_islands/island_try
* They are of varying utility... and perhaps some should be dropped.
*/
/*
* Try to predict whether the upward and/or leftward tile has been modified.
* copy_all_tiles() has already done downward and rightward tiles.
*/
void
copy_tiles_backward_pass
()
{
int
x
,
y
,
n
,
m
;
for
(
y
=
ntiles_y
-
1
;
y
>=
0
;
y
--
)
{
for
(
x
=
ntiles_x
-
1
;
x
>=
0
;
x
--
)
{
n
=
x
+
y
*
ntiles_x
;
/* number of this tile */
if
(
!
tile_has_diff
[
n
])
{
continue
;
}
m
=
x
+
(
y
-
1
)
*
ntiles_x
;
/* neighboring tile upward */
if
(
y
>=
1
&&
!
tile_has_diff
[
m
]
&&
tile_region
[
n
].
top_diff
)
{
if
(
!
tile_tried
[
m
])
{
copy_tile
(
x
,
y
-
1
);
}
}
m
=
(
x
-
1
)
+
y
*
ntiles_x
;
/* neighboring tile to left */
if
(
x
>=
1
&&
!
tile_has_diff
[
m
]
&&
tile_region
[
n
].
left_diff
)
{
if
(
!
tile_tried
[
m
])
{
copy_tile
(
x
-
1
,
y
);
}
}
}
}
}
void
gap_try
(
int
x
,
int
y
,
int
*
run
,
int
*
saw
,
int
along_x
)
{
int
n
,
m
,
i
,
xt
,
yt
;
n
=
x
+
y
*
ntiles_x
;
if
(
!
tile_has_diff
[
n
])
{
if
(
*
saw
)
{
(
*
run
)
++
;
/* extend the gap run. */
}
return
;
}
if
(
!
*
saw
||
*
run
==
0
||
*
run
>
gaps_fill
)
{
*
run
=
0
;
/* unacceptable run. */
*
saw
=
1
;
return
;
}
for
(
i
=
1
;
i
<=
*
run
;
i
++
)
{
/* iterate thru the run. */
if
(
along_x
)
{
xt
=
x
-
i
;
yt
=
y
;
}
else
{
xt
=
x
;
yt
=
y
-
i
;
}
m
=
xt
+
yt
*
ntiles_x
;
if
(
tile_tried
[
m
])
{
/* do not repeat tiles */
continue
;
}
copy_tile
(
xt
,
yt
);
}
*
run
=
0
;
*
saw
=
1
;
}
/*
* Look for small gaps of unchanged tiles that may actually contain changes.
* E.g. when paging up and down in a web broswer or terminal there can
* be a distracting delayed filling in of such gaps. gaps_fill is the
* tweak parameter that sets the width of the gaps that are checked.
*
* btw, grow_islands() is actually pretty successful at doing this too.
*/
void
fill_tile_gaps
()
{
int
x
,
y
,
run
,
saw
;
/* horizontal: */
for
(
y
=
0
;
y
<
ntiles_y
;
y
++
)
{
run
=
0
;
saw
=
0
;
for
(
x
=
0
;
x
<
ntiles_x
;
x
++
)
{
gap_try
(
x
,
y
,
&
run
,
&
saw
,
1
);
}
}
/* vertical: */
for
(
x
=
0
;
x
<
ntiles_x
;
x
++
)
{
run
=
0
;
saw
=
0
;
for
(
y
=
0
;
y
<
ntiles_y
;
y
++
)
{
gap_try
(
x
,
y
,
&
run
,
&
saw
,
0
);
}
}
}
void
island_try
(
int
x
,
int
y
,
int
u
,
int
v
,
int
*
run
)
{
int
n
,
m
;
n
=
x
+
y
*
ntiles_x
;
m
=
u
+
v
*
ntiles_x
;
if
(
tile_has_diff
[
n
])
{
(
*
run
)
++
;
}
else
{
*
run
=
0
;
}
if
(
tile_has_diff
[
n
]
&&
!
tile_has_diff
[
m
])
{
/* found discontinuity */
if
(
tile_tried
[
m
])
{
return
;
}
else
if
(
*
run
<
grow_fill
)
{
return
;
}
copy_tile
(
u
,
v
);
}
}
/*
* Scan looking for discontinuities in tile_has_diff[]. Try to extend
* the boundary of the discontinuity (i.e. make the island larger).
* Vertical scans are skipped since they do not seem to yield much...
*/
void
grow_islands
()
{
int
x
,
y
,
run
;
/*
* n.b. the way we scan here should keep an extension going,
* and so also fill in gaps effectively...
*/
/* left to right: */
for
(
y
=
0
;
y
<
ntiles_y
;
y
++
)
{
run
=
0
;
for
(
x
=
0
;
x
<=
ntiles_x
-
2
;
x
++
)
{
island_try
(
x
,
y
,
x
+
1
,
y
,
&
run
);
}
}
/* right to left: */
for
(
y
=
0
;
y
<
ntiles_y
;
y
++
)
{
run
=
0
;
for
(
x
=
ntiles_x
-
1
;
x
>=
1
;
x
--
)
{
island_try
(
x
,
y
,
x
-
1
,
y
,
&
run
);
}
}
}
/*
* copy the whole X screen to the vnc framebuffer. For a large enough
* number of changed tiles, this is faster than tiles scheme at retrieving
* the info from the X server. Bandwidth to client is another issue...
* use -fs 1.0 to disable.
*/
void
copy_screen
()
{
int
pixelsize
=
bpp
>>
3
;
char
*
vnc_fb
;
int
i
,
y
,
block_size
,
xi
;
block_size
=
(
dpy_x
*
(
dpy_y
/
fs_factor
)
*
pixelsize
);
vnc_fb
=
screen
->
frameBuffer
;
y
=
0
;
for
(
i
=
0
;
i
<
fs_factor
;
i
++
)
{
xi
=
XShmGetImage
(
dpy
,
window
,
fullscreen
,
0
,
y
,
AllPlanes
);
memcpy
(
vnc_fb
,
fullscreen
->
data
,
(
size_t
)
block_size
);
y
+=
dpy_y
/
fs_factor
;
vnc_fb
+=
block_size
;
}
rfbMarkRectAsModified
(
screen
,
0
,
0
,
dpy_x
,
dpy_y
);
}
/*
* Loop over 1-pixel tall horizontal scanlines looking for changes.
* Record the changes in tile_has_diff[]. Scanlines in the loop are
* equally spaced along y by NSCAN pixels, but have a slightly random
* starting offset ystart ( < NSCAN ) from scanlines[].
*/
int
scan_display
(
int
ystart
,
int
rescan
)
{
int
x
,
y
,
w
,
n
;
int
tile_count
=
0
;
int
pixelsize
=
bpp
>>
3
;
char
*
src
,
*
dst
;
y
=
ystart
;
while
(
y
<
dpy_y
)
{
/* grab the horizontal scanline from the display: */
X_LOCK
XShmGetImage
(
dpy
,
window
,
scanline
,
0
,
y
,
AllPlanes
);
X_UNLOCK
x
=
0
;
while
(
x
<
dpy_x
)
{
n
=
(
x
/
tile_x
)
+
(
y
/
tile_y
)
*
ntiles_x
;
if
(
rescan
&&
tile_has_diff
[
n
])
{
tile_count
++
;
x
+=
NSCAN
;
continue
;
}
/* set ptrs to correspond to the x offset: */
src
=
(
unsigned
char
*
)
scanline
->
data
+
x
*
pixelsize
;
dst
=
screen
->
frameBuffer
+
y
*
bytes_per_line
+
x
*
pixelsize
;
/* compute the width of data to be compared: */
if
(
x
+
NSCAN
>
dpy_x
)
{
w
=
dpy_x
-
x
;
}
else
{
w
=
NSCAN
;
}
if
(
memcmp
(
dst
,
src
,
w
*
pixelsize
)
)
{
/* found a difference, record it: */
tile_has_diff
[
n
]
=
1
;
tile_count
++
;
}
x
+=
NSCAN
;
}
y
+=
NSCAN
;
}
return
tile_count
;
}
/*
* toplevel for the scanning, rescanning, and applying the heuristics.
*/
void
scan_for_updates
()
{
int
i
,
tile_count
;
double
frac1
=
0
.
1
;
/* tweak parameter to try a 2nd scan_display() */
for
(
i
=
0
;
i
<
ntiles
;
i
++
)
{
tile_has_diff
[
i
]
=
0
;
tile_tried
[
i
]
=
0
;
}
/*
* n.b. this program has only been tested so far with
* tile_x = tile_y = NSCAN = 32!
*/
count
++
;
count
%=
NSCAN
;
/* scan with the initial y to the jitter value from scanlines: */
tile_count
=
scan_display
(
scanlines
[
count
],
0
);
if
(
fs_factor
&&
frac1
>=
fs_frac
)
{
/* make frac1 < fs_frac if fullscreen updates are enabled */
frac1
=
fs_frac
/
2
.
0
;
}
if
(
tile_count
>
frac1
*
ntiles
)
{
/*
* many tiles have changed, so try a rescan (since it should
* be short compared to the many upcoming copy_tile() calls)
*/
/* this check is done to skip the extra scan_display() call */
if
(
!
fs_factor
||
tile_count
<=
fs_frac
*
ntiles
)
{
int
cp
;
/* choose a different y shift for the 2nd scan: */
cp
=
(
NSCAN
-
count
)
%
NSCAN
;
tile_count
=
scan_display
(
scanlines
[
cp
],
1
);
}
/*
* At some number of changed tiles it is better to just
* copy the full screen at once. I.e. time = c1 + m * r1
* where m is number of tiles and c1 is the scan_display()
* time: for some m it crosses the full screen update time.
*
* We try to predict that crossover with the fs_frac fudge
* factor... seems to be about 1/2 the total number
* of tiles. n.b. this ignores network bandwidth, etc.
* use -fs 1.0 to disable on slow links.
*/
if
(
fs_factor
&&
tile_count
>
fs_frac
*
ntiles
)
{
copy_screen
();
return
;
}
}
/* copy all tiles with differences from display to vnc framebuffer: */
copy_all_tiles
();
/*
* This backward pass for upward and left tiles complements what
* was done in copy_all_tiles() for downward and right tiles.
*/
copy_tiles_backward_pass
();
if
(
grow_fill
)
{
grow_islands
();
}
if
(
gaps_fill
)
{
fill_tile_gaps
();
}
if
(
use_hints
)
{
hint_updates
();
/* use krfb/x0rfbserver hints algorithm */
}
else
{
tile_updates
();
/* send each tile change individually */
}
}
void
watch_loop
(
void
)
{
int
cnt
=
0
;
#if !defined(HAVE_PTHREADS)
use_threads
=
0
;
#endif
if
(
use_threads
)
{
rfbRunEventLoop
(
screen
,
-
1
,
TRUE
);
}
while
(
1
)
{
got_user_input
=
0
;
if
(
!
use_threads
)
{
rfbProcessEvents
(
screen
,
-
1
);
if
(
got_user_input
&&
cnt
%
10
!=
0
)
{
/* every 10-th drops thru to code below... */
XFlush
(
dpy
);
continue
;
}
}
if
(
shut_down
)
{
clean_up_exit
();
}
if
(
!
screen
->
rfbClientHead
)
{
/* waiting for a client */
usleep
(
200
*
1000
);
continue
;
}
rfbUndrawCursor
(
screen
);
scan_for_updates
();
usleep
(
waitms
*
1000
);
cnt
++
;
}
}
void
print_help
()
{
char
help
[]
=
"
x0vnc options:
-defer time time in ms to wait for updates before sending to
client [rfbDeferUpdateTime] (default %d)
-wait time time in ms to pause between screen polls. used
to cut down on load (default %d)
-gaps n heuristic to fill in gaps in rows or cols of n or less
tiles. used to improve text paging (default %d).
-grow n heuristic to grow islands of changed tiles n or wider
by checking the tile near the boundary (default %d).
-fs f if the fraction of changed tiles in a poll is greater
than f, the whole screen is updated (default %.2f)
-fuzz n tolerance in pixels to mark a tiles edges as changed.
(default %d).
-hints use krfb/x0rfbserver hints (glue changed adjacent
horizontal tiles into one big rectangle) (default %s).
-nohints do not use hints; send each tile separately.
-threads use threaded algorithm [rfbRunEventLoop] if compiled
with threads (default %s).
-nothreads do not use [rfbRunEventLoop].
-viewonly clients can only watch (default %s).
-shared VNC display is shared (default %s)
These options are passed to libvncserver:
"
;
fprintf
(
stderr
,
help
,
defer_update
,
waitms
,
gaps_fill
,
grow_fill
,
fs_frac
,
tile_fuzz
,
use_hints
?
"on"
:
"off"
,
use_threads
?
"on"
:
"off"
,
view_only
?
"on"
:
"off"
,
shared
?
"on"
:
"off"
);
rfbUsage
();
exit
(
1
);
}
int
main
(
int
argc
,
char
**
argv
)
{
XImage
*
fb
;
int
i
,
scr
,
ev
,
er
,
maj
,
min
;
char
*
use_dpy
=
NULL
;
/* used to pass args we do not know about to rfbGetScreen(): */
int
argc2
=
1
;
char
*
argv2
[
100
];
argv2
[
0
]
=
argv
[
0
];
for
(
i
=
1
;
i
<
argc
;
i
++
)
{
if
(
!
strcmp
(
argv
[
i
],
"-display"
))
{
use_dpy
=
argv
[
++
i
];
}
else
if
(
!
strcmp
(
argv
[
i
],
"-defer"
))
{
defer_update
=
atoi
(
argv
[
++
i
]);
}
else
if
(
!
strcmp
(
argv
[
i
],
"-wait"
))
{
waitms
=
atoi
(
argv
[
++
i
]);
}
else
if
(
!
strcmp
(
argv
[
i
],
"-gaps"
))
{
gaps_fill
=
atoi
(
argv
[
++
i
]);
}
else
if
(
!
strcmp
(
argv
[
i
],
"-grow"
))
{
grow_fill
=
atoi
(
argv
[
++
i
]);
}
else
if
(
!
strcmp
(
argv
[
i
],
"-fs"
))
{
fs_frac
=
atof
(
argv
[
++
i
]);
}
else
if
(
!
strcmp
(
argv
[
i
],
"-fuzz"
))
{
tile_fuzz
=
atoi
(
argv
[
++
i
]);
}
else
if
(
!
strcmp
(
argv
[
i
],
"-hints"
))
{
use_hints
=
1
;
}
else
if
(
!
strcmp
(
argv
[
i
],
"-nohints"
))
{
use_hints
=
0
;
}
else
if
(
!
strcmp
(
argv
[
i
],
"-threads"
))
{
use_threads
=
1
;
}
else
if
(
!
strcmp
(
argv
[
i
],
"-nothreads"
))
{
use_threads
=
0
;
}
else
if
(
!
strcmp
(
argv
[
i
],
"-viewonly"
))
{
view_only
=
1
;
}
else
if
(
!
strcmp
(
argv
[
i
],
"-shared"
))
{
shared
=
1
;
}
else
if
(
!
strcmp
(
argv
[
i
],
"-h"
)
||
!
strcmp
(
argv
[
i
],
"-help"
))
{
print_help
();
}
else
{
/* otherwise copy it for use below. */
printf
(
"passing arg to libvncserver: %s
\n
"
,
argv
[
i
]);
if
(
argc2
<
100
)
{
argv2
[
argc2
++
]
=
argv
[
i
];
}
}
}
if
(
tile_fuzz
<
1
)
{
tile_fuzz
=
1
;
}
if
(
waitms
<
0
)
{
waitms
=
0
;
}
printf
(
"defer: %d
\n
"
,
defer_update
);
printf
(
"waitms: %d
\n
"
,
waitms
);
printf
(
"tile_fuzz: %d
\n
"
,
tile_fuzz
);
printf
(
"gaps_fill: %d
\n
"
,
gaps_fill
);
printf
(
"grow_fill: %d
\n
"
,
grow_fill
);
printf
(
"fs_frac: %.2f
\n
"
,
fs_frac
);
printf
(
"use_hints: %d
\n
"
,
use_hints
);
printf
(
"viewonly: %d
\n
"
,
view_only
);
printf
(
"shared: %d
\n
"
,
shared
);
if
(
use_dpy
)
{
dpy
=
XOpenDisplay
(
use_dpy
);
}
else
if
(
(
use_dpy
=
getenv
(
"DISPLAY"
))
)
{
dpy
=
XOpenDisplay
(
use_dpy
);
}
else
{
dpy
=
XOpenDisplay
(
""
);
}
if
(
!
dpy
)
{
printf
(
"XOpenDisplay failed (%s)
\n
"
,
use_dpy
);
exit
(
1
);
}
else
if
(
use_dpy
)
{
printf
(
"Using display %s
\n
"
,
use_dpy
);
}
else
{
printf
(
"Using default display.
\n
"
);
}
if
(
!
XTestQueryExtension
(
dpy
,
&
ev
,
&
er
,
&
maj
,
&
min
))
{
printf
(
"Display does not support the XTest extension.
\n
"
);
exit
(
1
);
}
if
(
!
XShmQueryExtension
(
dpy
))
{
printf
(
"Display does not support XShm extension"
" (must be local).
\n
"
);
exit
(
1
);
}
/*
* Window managers will often grab the display during resize, etc.
* To avoid deadlock (our user resize input is not processed)
* we tell the server to process our requests during all grabs:
*/
XTestGrabControl
(
dpy
,
True
);
scr
=
DefaultScreen
(
dpy
);
window
=
RootWindow
(
dpy
,
scr
);
dpy_x
=
DisplayWidth
(
dpy
,
scr
);
dpy_y
=
DisplayHeight
(
dpy
,
scr
);
fb
=
XGetImage
(
dpy
,
window
,
0
,
0
,
dpy_x
,
dpy_y
,
AllPlanes
,
ZPixmap
);
printf
(
"Read initial data from display into framebuffer.
\n
"
);
if
(
fb
->
bits_per_pixel
==
24
)
{
printf
(
"warning: 24 bpp may have poor performance.
\n
"
);
}
/*
* n.b. we do not have to X_LOCK X11 calls until watch_loop()
* is called since we are single-threaded until then.
*/
initialize_screen
(
&
argc2
,
argv2
,
fb
);
initialize_tiles
();
initialize_shm
();
printf
(
"screen setup finished.
\n
"
);
watch_loop
();
return
(
0
);
}
zippy.c
→
contrib/
zippy.c
View file @
4d871894
File moved
httpd.c
View file @
4d871894
...
@@ -266,7 +266,7 @@ httpProcessInput(rfbScreenInfoPtr rfbScreen)
...
@@ -266,7 +266,7 @@ httpProcessInput(rfbScreenInfoPtr rfbScreen)
httpCloseSock
(
rfbScreen
);
httpCloseSock
(
rfbScreen
);
return
;
return
;
}
}
/
/ proxy connection
/
* proxy connection */
rfbLog
(
"httpd: client asked for CONNECT
\n
"
);
rfbLog
(
"httpd: client asked for CONNECT
\n
"
);
WriteExact
(
&
cl
,
PROXY_OK_STR
,
strlen
(
PROXY_OK_STR
));
WriteExact
(
&
cl
,
PROXY_OK_STR
,
strlen
(
PROXY_OK_STR
));
rfbNewClientConnection
(
rfbScreen
,
rfbScreen
->
httpSock
);
rfbNewClientConnection
(
rfbScreen
,
rfbScreen
->
httpSock
);
...
@@ -274,7 +274,7 @@ httpProcessInput(rfbScreenInfoPtr rfbScreen)
...
@@ -274,7 +274,7 @@ httpProcessInput(rfbScreenInfoPtr rfbScreen)
return
;
return
;
}
}
if
(
!
strncmp
(
buf
,
"GET "
,
4
)
&&
!
strncmp
(
strchr
(
buf
,
'/'
),
"/proxied.connection HTTP/1."
,
27
))
{
if
(
!
strncmp
(
buf
,
"GET "
,
4
)
&&
!
strncmp
(
strchr
(
buf
,
'/'
),
"/proxied.connection HTTP/1."
,
27
))
{
/
/ proxy connection
/
* proxy connection */
rfbLog
(
"httpd: client asked for /proxied.connection
\n
"
);
rfbLog
(
"httpd: client asked for /proxied.connection
\n
"
);
WriteExact
(
&
cl
,
PROXY_OK_STR
,
strlen
(
PROXY_OK_STR
));
WriteExact
(
&
cl
,
PROXY_OK_STR
,
strlen
(
PROXY_OK_STR
));
rfbNewClientConnection
(
rfbScreen
,
rfbScreen
->
httpSock
);
rfbNewClientConnection
(
rfbScreen
,
rfbScreen
->
httpSock
);
...
...
main.c
View file @
4d871894
...
@@ -128,7 +128,7 @@ void rfbScheduleCopyRegion(rfbScreenInfoPtr rfbScreen,sraRegionPtr copyRegion,in
...
@@ -128,7 +128,7 @@ void rfbScheduleCopyRegion(rfbScreenInfoPtr rfbScreen,sraRegionPtr copyRegion,in
sraRgnDestroy
(
modifiedRegionBackup
);
sraRgnDestroy
(
modifiedRegionBackup
);
#if 0
#if 0
//TODO: is this needed? Or does it mess up deferring?
/* TODO: is this needed? Or does it mess up deferring? */
/* while(!sraRgnEmpty(cl->copyRegion)) */ {
/* while(!sraRgnEmpty(cl->copyRegion)) */ {
#ifdef HAVE_PTHREADS
#ifdef HAVE_PTHREADS
if(!cl->screen->backgroundLoop)
if(!cl->screen->backgroundLoop)
...
...
rfb.h
View file @
4d871894
...
@@ -164,9 +164,17 @@ typedef int socklen_t;
...
@@ -164,9 +164,17 @@ typedef int socklen_t;
the library and your application (at least the parts including rfb.h)
the library and your application (at least the parts including rfb.h)
with the same support for pthreads. */
with the same support for pthreads. */
#ifdef HAVE_PTHREADS
#ifdef HAVE_PTHREADS
#define rfbInitServer rfbInitServerWithPthreads
#ifdef HAVE_ZRLE
#define rfbInitServer rfbInitServerWithPthreadsAndZRLE
#else
#define rfbInitServer rfbInitServerWithPthreadsButWithoutZRLE
#endif
#else
#ifdef HAVE_ZRLE
#define rfbInitServer rfbInitServerWithoutPthreadsButWithZRLE
#else
#else
#define rfbInitServer rfbInitServerWithoutPthreads
#define rfbInitServer rfbInitServerWithoutPthreadsAndZRLE
#endif
#endif
#endif
#define MAX_ENCODINGS 10
#define MAX_ENCODINGS 10
...
@@ -409,9 +417,6 @@ typedef struct _rfbClientRec {
...
@@ -409,9 +417,6 @@ typedef struct _rfbClientRec {
Bool
useCopyRect
;
Bool
useCopyRect
;
int
preferredEncoding
;
int
preferredEncoding
;
int
correMaxWidth
,
correMaxHeight
;
int
correMaxWidth
,
correMaxHeight
;
#ifdef HAVE_ZRLE
void
*
zrleData
;
#endif
/* The following member is only used during VNC authentication */
/* The following member is only used during VNC authentication */
CARD8
authChallenge
[
CHALLENGESIZE
];
CARD8
authChallenge
[
CHALLENGESIZE
];
...
@@ -538,6 +543,10 @@ typedef struct _rfbClientRec {
...
@@ -538,6 +543,10 @@ typedef struct _rfbClientRec {
COND
(
updateCond
);
COND
(
updateCond
);
#endif
#endif
#ifdef HAVE_ZRLE
void
*
zrleData
;
#endif
}
rfbClientRec
,
*
rfbClientPtr
;
}
rfbClientRec
,
*
rfbClientPtr
;
/*
/*
...
@@ -725,9 +734,10 @@ extern void rfbSetCursor(rfbScreenInfoPtr rfbScreen,rfbCursorPtr c,Bool freeOld)
...
@@ -725,9 +734,10 @@ extern void rfbSetCursor(rfbScreenInfoPtr rfbScreen,rfbCursorPtr c,Bool freeOld)
extern
void
defaultPtrAddEvent
(
int
buttonMask
,
int
x
,
int
y
,
rfbClientPtr
cl
);
extern
void
defaultPtrAddEvent
(
int
buttonMask
,
int
x
,
int
y
,
rfbClientPtr
cl
);
/* zrle.c */
/* zrle.c */
#ifdef HAVE_ZRLE
extern
Bool
rfbSendRectEncodingZRLE
(
rfbClientPtr
cl
,
int
x
,
int
y
,
int
w
,
int
h
);
extern
Bool
rfbSendRectEncodingZRLE
(
rfbClientPtr
cl
,
int
x
,
int
y
,
int
w
,
int
h
);
extern
void
FreeZrleData
(
rfbClientPtr
cl
);
extern
void
FreeZrleData
(
rfbClientPtr
cl
);
#endif
/* stats.c */
/* stats.c */
...
...
x11vnc.c
deleted
100644 → 0
View file @
d60fda11
/* This file (x11vnc.c) is part of LibVNCServer.
It is a small clone of x0rfbserver by HexoNet, demonstrating the
capabilities of LibVNCServer.
*/
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
#include <X11/extensions/XTest.h>
#ifndef NO_SHM
#include <X11/extensions/XShm.h>
#include <sys/shm.h>
#endif
#define KEYSYM_H
#undef Bool
#define KeySym RFBKeySym
#include "rfb.h"
Display
*
dpy
=
0
;
int
window
;
int
c
=
0
,
blockLength
=
32
;
int
tileX
=
0
,
tileY
=
0
,
tileWidth
=
32
,
tileHeight
=
32
*
2
,
dontTile
=
TRUE
;
Bool
gotInput
=
FALSE
;
Bool
viewOnly
=
FALSE
;
Bool
sharedMode
=
FALSE
;
Bool
disconnectAfterFirstClient
=
TRUE
;
/* keyboard handling */
#define KBDDEBUG
char
modifiers
[
0x100
];
KeyCode
keycodes
[
0x100
],
leftShiftCode
,
rightShiftCode
,
altGrCode
;
void
init_keycodes
()
{
KeySym
key
,
*
keymap
;
int
i
,
j
,
minkey
,
maxkey
,
syms_per_keycode
;
memset
(
modifiers
,
-
1
,
sizeof
(
modifiers
));
XDisplayKeycodes
(
dpy
,
&
minkey
,
&
maxkey
);
keymap
=
XGetKeyboardMapping
(
dpy
,
minkey
,(
maxkey
-
minkey
+
1
),
&
syms_per_keycode
);
#ifdef KBDDEBUG
fprintf
(
stderr
,
"minkey=%d, maxkey=%d, syms_per_keycode=%d
\n
"
,
minkey
,
maxkey
,
syms_per_keycode
);
#endif
for
(
i
=
minkey
;
i
<=
maxkey
;
i
++
)
for
(
j
=
0
;
j
<
syms_per_keycode
;
j
++
)
{
key
=
keymap
[(
i
-
minkey
)
*
syms_per_keycode
+
j
];
#ifdef KBDDEBUG
fprintf
(
stderr
,
"keymap(i=0x%x,j=%d)==0x%lx
\n
"
,
i
,
j
,
key
);
#endif
if
(
key
>=
' '
&&
key
<
0x100
&&
i
==
XKeysymToKeycode
(
dpy
,
key
))
{
keycodes
[
key
]
=
i
;
modifiers
[
key
]
=
j
;
#ifdef KBDDEBUG
fprintf
(
stderr
,
"key 0x%lx (%c): keycode=0x%x, modifier=%d
\n
"
,
key
,(
char
)
key
,
i
,
j
);
#endif
}
}
leftShiftCode
=
XKeysymToKeycode
(
dpy
,
XK_Shift_L
);
rightShiftCode
=
XKeysymToKeycode
(
dpy
,
XK_Shift_R
);
altGrCode
=
XKeysymToKeycode
(
dpy
,
XK_Mode_switch
);
#ifdef KBDDEBUG
fprintf
(
stderr
,
"leftShift=0x%x, rightShift=0x%x, altGr=0x%x
\n
"
,
leftShiftCode
,
rightShiftCode
,
altGrCode
);
#endif
XFree
((
char
*
)
keymap
);
}
static
Bool
shutDownServer
=
0
;
/* the hooks */
void
clientGone
(
rfbClientPtr
cl
)
{
shutDownServer
=-
1
;
}
enum
rfbNewClientAction
newClient
(
rfbClientPtr
cl
)
{
if
(
disconnectAfterFirstClient
)
cl
->
clientGoneHook
=
clientGone
;
if
(
viewOnly
)
cl
->
clientData
=
(
void
*
)
-
1
;
else
cl
->
clientData
=
(
void
*
)
0
;
return
(
RFB_CLIENT_ACCEPT
);
}
#define LEFTSHIFT 1
#define RIGHTSHIFT 2
#define ALTGR 4
char
ModifierState
=
0
;
/* this function adjusts the modifiers according to mod (as from modifiers) and ModifierState */
void
tweakModifiers
(
signed
char
mod
,
Bool
down
)
{
Bool
isShift
=
ModifierState
&
(
LEFTSHIFT
|
RIGHTSHIFT
);
#ifdef KBDDEBUG
fprintf
(
stderr
,
"tweakModifiers: 0x%x %s
\n
"
,
mod
,
down
?
"down"
:
"up"
);
#endif
if
(
mod
<
0
)
return
;
if
(
isShift
&&
mod
!=
1
)
{
if
(
ModifierState
&
LEFTSHIFT
)
XTestFakeKeyEvent
(
dpy
,
leftShiftCode
,
!
down
,
CurrentTime
);
if
(
ModifierState
&
RIGHTSHIFT
)
XTestFakeKeyEvent
(
dpy
,
rightShiftCode
,
!
down
,
CurrentTime
);
}
if
(
!
isShift
&&
mod
==
1
)
XTestFakeKeyEvent
(
dpy
,
leftShiftCode
,
down
,
CurrentTime
);
if
(
ModifierState
&
ALTGR
&&
mod
!=
2
)
XTestFakeKeyEvent
(
dpy
,
altGrCode
,
!
down
,
CurrentTime
);
if
(
!
(
ModifierState
&
ALTGR
)
&&
mod
==
2
)
XTestFakeKeyEvent
(
dpy
,
altGrCode
,
down
,
CurrentTime
);
}
void
keyboard
(
Bool
down
,
KeySym
keySym
,
rfbClientPtr
cl
)
{
if
(((
int
)
cl
->
clientData
)
==-
1
)
return
;
/* viewOnly */
#define ADJUSTMOD(sym,state) \
if(keySym==sym) { if(down) ModifierState|=state; else ModifierState&=~state; }
ADJUSTMOD
(
XK_Shift_L
,
LEFTSHIFT
)
ADJUSTMOD
(
XK_Shift_R
,
RIGHTSHIFT
)
ADJUSTMOD
(
XK_Mode_switch
,
ALTGR
)
#ifdef KBDDEBUG
fprintf
(
stderr
,
"keyboard: down=%s, keySym=0x%lx (%s), ModState=0x%x
\n
"
,
down
?
"down"
:
"up"
,
keySym
,
XKeysymToString
(
keySym
),
ModifierState
);
#endif
if
(
keySym
>=
' '
&&
keySym
<
0x100
)
{
KeyCode
k
;
if
(
down
)
tweakModifiers
(
modifiers
[
keySym
],
True
);
//tweakModifiers(modifiers[keySym],down);
//k = XKeysymToKeycode( dpy,keySym );
k
=
keycodes
[
keySym
];
if
(
k
!=
NoSymbol
)
{
XTestFakeKeyEvent
(
dpy
,
k
,
down
,
CurrentTime
);
gotInput
=
TRUE
;
}
if
(
down
)
tweakModifiers
(
modifiers
[
keySym
],
False
);
gotInput
=
TRUE
;
}
else
{
KeyCode
k
=
XKeysymToKeycode
(
dpy
,
keySym
);
if
(
k
!=
NoSymbol
)
{
XTestFakeKeyEvent
(
dpy
,
k
,
down
,
CurrentTime
);
gotInput
=
TRUE
;
}
}
}
int
oldButtonMask
=
0
;
void
mouse
(
int
buttonMask
,
int
x
,
int
y
,
rfbClientPtr
cl
)
{
int
i
=
0
;
if
(((
int
)
cl
->
clientData
)
==-
1
)
return
;
/* viewOnly */
XTestFakeMotionEvent
(
dpy
,
0
,
x
,
y
,
CurrentTime
);
while
(
i
<
5
)
{
if
((
oldButtonMask
&
(
1
<<
i
))
!=
(
buttonMask
&
(
1
<<
i
)))
XTestFakeButtonEvent
(
dpy
,
i
+
1
,(
buttonMask
&
(
1
<<
i
))
?
True
:
False
,
CurrentTime
);
i
++
;
}
oldButtonMask
=
buttonMask
;
//fprintf(stderr,"-");
gotInput
=
TRUE
;
}
/* the X11 interaction */
#ifndef NO_SHM
Bool
useSHM
=
TRUE
;
XShmSegmentInfo
shminfo
;
#else
Bool
useSHM
=
FALSE
;
#endif
void
getImage
(
int
bpp
,
Display
*
dpy
,
int
xscreen
,
XImage
**
i
,
int
x
,
int
y
,
int
width
,
int
height
)
{
if
(
width
<=
0
)
width
=
DisplayWidth
(
dpy
,
xscreen
);
if
(
height
<=
0
)
height
=
DisplayHeight
(
dpy
,
xscreen
);
if
(
useSHM
&&
bpp
>
0
)
{
static
Bool
firstTime
=
TRUE
;
if
(
firstTime
)
{
firstTime
=
FALSE
;
*
i
=
XShmCreateImage
(
dpy
,
DefaultVisual
(
dpy
,
xscreen
),
bpp
,
ZPixmap
,
NULL
,
&
shminfo
,
width
,
height
);
if
(
*
i
==
0
)
{
useSHM
=
FALSE
;
getImage
(
bpp
,
dpy
,
xscreen
,
i
,
x
,
y
,
width
,
height
);
return
;
}
shminfo
.
shmid
=
shmget
(
IPC_PRIVATE
,
(
*
i
)
->
bytes_per_line
*
(
*
i
)
->
height
,
IPC_CREAT
|
0777
);
shminfo
.
shmaddr
=
(
*
i
)
->
data
=
(
char
*
)
shmat
(
shminfo
.
shmid
,
0
,
0
);
shminfo
.
readOnly
=
False
;
XShmAttach
(
dpy
,
&
shminfo
);
}
if
(
x
==
0
&&
y
==
0
&&
width
==
DisplayWidth
(
dpy
,
xscreen
)
&&
height
==
DisplayHeight
(
dpy
,
xscreen
))
XShmGetImage
(
dpy
,
window
,
*
i
,
0
,
0
,
AllPlanes
);
else
XGetSubImage
(
dpy
,
window
,
x
,
y
,
width
,
height
,
AllPlanes
,
ZPixmap
,
*
i
,
0
,
0
);
}
else
{
*
i
=
XGetImage
(
dpy
,
window
,
x
,
y
,
width
,
height
,
AllPlanes
,
ZPixmap
);
}
}
void
checkForImageUpdates
(
rfbScreenInfoPtr
s
,
char
*
b
,
int
rowstride
,
int
x
,
int
y
,
int
width
,
int
height
)
{
Bool
changed
;
int
i
,
j
,
k
,
l1
,
l2
,
x1
,
y1
;
int
bpp
=
s
->
bitsPerPixel
/
8
;
for
(
j
=
0
;
j
<
height
;
j
+=
blockLength
)
for
(
i
=
0
;
i
<
width
;
i
+=
blockLength
)
{
y1
=
j
+
blockLength
;
if
(
y1
>
height
)
y1
=
height
;
x1
=
i
+
blockLength
;
if
(
x1
>
width
)
x1
=
width
;
y1
*=
rowstride
;
x1
*=
bpp
;
changed
=
FALSE
;
for
(
l1
=
j
*
rowstride
,
l2
=
(
j
+
y
)
*
s
->
paddedWidthInBytes
+
x
*
bpp
;
l1
<
y1
;
l1
+=
rowstride
,
l2
+=
s
->
paddedWidthInBytes
)
for
(
k
=
i
*
bpp
;
k
<
x1
;
k
++
)
if
(
s
->
frameBuffer
[
l2
+
k
]
!=
b
[
l1
+
k
])
{
// fprintf(stderr,"changed: %d, %d\n",k,l);
changed
=
TRUE
;
goto
changed_p
;
}
if
(
changed
)
{
changed_p:
for
(
l1
+=
i
*
bpp
,
l2
+=
i
*
bpp
;
l1
<
y1
;
l1
+=
rowstride
,
l2
+=
s
->
paddedWidthInBytes
)
memcpy
(
/*b+l,*/
s
->
frameBuffer
+
l2
,
b
+
l1
,
x1
-
i
*
bpp
);
rfbMarkRectAsModified
(
s
,
x
+
i
,
y
+
j
,
x
+
i
+
blockLength
,
y
+
j
+
blockLength
);
}
}
}
int
probeX
=
0
,
probeY
=
0
;
void
probeScreen
(
rfbScreenInfoPtr
s
,
int
xscreen
)
{
int
i
,
j
,
/*pixel,i1,*/
j1
,
bpp
=
s
->
rfbServerFormat
.
bitsPerPixel
/
8
,
/*mask=(1<<bpp)-1,*/
rstride
=
s
->
paddedWidthInBytes
;
XImage
*
im
;
//fprintf(stderr,"/%d,%d",probeX,probeY);
#if 0
probeX++;
if(probeX>=tileWidth) {
probeX=0;
probeY++;
if(probeY>=tileHeight)
probeY=0;
}
#else
probeX
=
(
rand
()
%
tileWidth
);
probeY
=
(
rand
()
%
tileHeight
);
#endif
for
(
j
=
probeY
;
j
<
s
->
height
;
j
+=
tileHeight
)
for
(
i
=
0
/*probeX*/
;
i
<
s
->
width
;
i
+=
tileWidth
)
{
im
=
XGetImage
(
dpy
,
window
,
i
,
j
,
tileWidth
/*1*/
,
1
,
AllPlanes
,
ZPixmap
);
/* for(i1=0;i1<bpp && im->data[i1]==(s->frameBuffer+i*bpp+j*rstride)[i1];i1++);
if(i1<bpp) { */
if
(
memcmp
(
im
->
data
,
s
->
frameBuffer
+
i
*
bpp
+
j
*
rstride
,
tileWidth
*
bpp
))
{
/* do update */
int
x
=
i
/*-probeX*/
,
w
=
(
x
+
tileWidth
>
s
->
width
)
?
s
->
width
-
x
:
tileWidth
,
y
=
j
-
probeY
,
h
=
(
y
+
tileHeight
>
s
->
height
)
?
s
->
height
-
y
:
tileHeight
;
XDestroyImage
(
im
);
//getImage(bpp,dpy,xscreen,&im,x,y,w,h);
//fprintf(stderr,"GetImage(%d,%d,%d,%d)",x,y,w,h);
im
=
XGetImage
(
dpy
,
window
,
x
,
y
,
w
,
h
,
AllPlanes
,
ZPixmap
);
for
(
j1
=
0
;
j1
<
h
;
j1
++
)
memcpy
(
s
->
frameBuffer
+
x
*
bpp
+
(
y
+
j1
)
*
rstride
,
im
->
data
+
j1
*
im
->
bytes_per_line
,
bpp
*
w
);
//checkForImageUpdates(s,im->data,rstride,x,y,w,h);
//if(0 && !useSHM)
XDestroyImage
(
im
);
//memcpy(s->frameBuffer+i*bpp+j*rstride,&pixel,bpp);
rfbMarkRectAsModified
(
s
,
x
,
y
,
x
+
w
,
y
+
h
);
//fprintf(stderr,"%d:%d:%x\n",i,j,pixel);
//fprintf(stderr,"*");
}
else
XDestroyImage
(
im
);
}
}
#define LOCAL_CONTROL
#ifdef LOCAL_CONTROL
#include "1instance.c"
#endif
/* the main program */
int
main
(
int
argc
,
char
**
argv
)
{
//Screen *sc;
//Colormap cm;
XImage
*
framebufferImage
;
char
*
backupImage
;
int
xscreen
,
i
;
rfbScreenInfoPtr
screen
;
int
maxMsecsToConnect
=
5000
;
/* a maximum of 5 seconds to connect */
int
updateCounter
;
/* about every 50 ms a screen update should be made. */
#ifdef LOCAL_CONTROL
char
message
[
1024
];
single_instance_struct
single_instance
=
{
"/tmp/x11vnc_control"
};
open_control_file
(
&
single_instance
);
#endif
for
(
i
=
argc
-
1
;
i
>
0
;
i
--
)
#ifdef LOCAL_CONTROL
if
(
i
<
argc
-
1
&&
!
strcmp
(
argv
[
i
],
"-toggleviewonly"
))
{
if
(
strlen
(
argv
[
i
+
1
])
>
1022
)
argv
[
i
+
1
][
1022
]
=
0
;
sprintf
(
message
,
"t%s"
,
argv
[
i
+
1
]);
send_message
(
&
single_instance
,
message
);
exit
(
0
);
}
else
if
(
!
strcmp
(
argv
[
i
],
"-listclients"
))
{
fprintf
(
stderr
,
"list clients
\n
"
);
send_message
(
&
single_instance
,
"l"
);
exit
(
0
);
}
else
#ifdef BACKCHANNEL
if
(
i
<
argc
-
1
&&
!
strcmp
(
argv
[
i
],
"-backchannel"
))
{
if
(
strlen
(
argv
[
i
+
1
])
>
1022
)
argv
[
i
+
1
][
1022
]
=
0
;
sprintf
(
message
,
"b%s"
,
argv
[
i
+
1
]);
send_message
(
&
single_instance
,
message
);
exit
(
0
);
}
else
#endif
#endif
if
(
i
<
argc
-
1
&&
strcmp
(
argv
[
i
],
"-display"
)
==
0
)
{
fprintf
(
stderr
,
"Using display %s
\n
"
,
argv
[
i
+
1
]);
dpy
=
XOpenDisplay
(
argv
[
i
+
1
]);
if
(
dpy
==
0
)
{
fprintf
(
stderr
,
"Couldn't connect to display
\"
%s
\"
.
\n
"
,
argv
[
i
+
1
]);
exit
(
1
);
}
}
else
if
(
i
<
argc
-
1
&&
strcmp
(
argv
[
i
],
"-wait4client"
)
==
0
)
{
maxMsecsToConnect
=
atoi
(
argv
[
i
+
1
]);
}
else
if
(
i
<
argc
-
1
&&
strcmp
(
argv
[
i
],
"-update"
)
==
0
)
{
updateCounter
=
atoi
(
argv
[
i
+
1
]);
}
else
if
(
strcmp
(
argv
[
i
],
"-noshm"
)
==
0
)
{
useSHM
=
FALSE
;
}
else
if
(
strcmp
(
argv
[
i
],
"-runforever"
)
==
0
)
{
disconnectAfterFirstClient
=
FALSE
;
}
else
if
(
strcmp
(
argv
[
i
],
"-tile"
)
==
0
)
{
dontTile
=
FALSE
;
}
else
if
(
strcmp
(
argv
[
i
],
"-viewonly"
)
==
0
)
{
viewOnly
=
TRUE
;
}
else
if
(
strcmp
(
argv
[
i
],
"-shared"
)
==
0
)
{
sharedMode
=
TRUE
;
}
updateCounter
=
dontTile
?
20
:
1
;
if
(
dpy
==
0
)
dpy
=
XOpenDisplay
(
""
);
if
(
dpy
==
0
)
{
fprintf
(
stderr
,
"Couldn't open display!
\n
"
);
exit
(
2
);
}
xscreen
=
DefaultScreen
(
dpy
);
window
=
RootWindow
(
dpy
,
xscreen
);
//XTestGrabControl(dpy,True);
init_keycodes
();
getImage
(
0
,
dpy
,
xscreen
,
&
framebufferImage
,
0
,
0
,
-
1
,
-
1
);
screen
=
rfbGetScreen
(
&
argc
,
argv
,
framebufferImage
->
width
,
framebufferImage
->
height
,
framebufferImage
->
bits_per_pixel
,
8
,
framebufferImage
->
bits_per_pixel
/
8
);
screen
->
paddedWidthInBytes
=
framebufferImage
->
bytes_per_line
;
screen
->
rfbServerFormat
.
bitsPerPixel
=
framebufferImage
->
bits_per_pixel
;
screen
->
rfbServerFormat
.
depth
=
framebufferImage
->
depth
;
//rfbEndianTest = framebufferImage->bitmap_bit_order != MSBFirst;
screen
->
rfbServerFormat
.
trueColour
=
TRUE
;
if
(
screen
->
rfbServerFormat
.
bitsPerPixel
==
8
)
{
if
(
CellsOfScreen
(
ScreenOfDisplay
(
dpy
,
xscreen
)))
{
XColor
color
[
256
];
int
i
;
screen
->
colourMap
.
count
=
256
;
screen
->
rfbServerFormat
.
trueColour
=
FALSE
;
screen
->
colourMap
.
is16
=
TRUE
;
for
(
i
=
0
;
i
<
256
;
i
++
)
color
[
i
].
pixel
=
i
;
XQueryColors
(
dpy
,
DefaultColormap
(
dpy
,
xscreen
),
color
,
256
);
screen
->
colourMap
.
data
.
shorts
=
(
unsigned
short
*
)
malloc
(
3
*
sizeof
(
short
)
*
screen
->
colourMap
.
count
);
for
(
i
=
0
;
i
<
screen
->
colourMap
.
count
;
i
++
)
{
screen
->
colourMap
.
data
.
shorts
[
i
*
3
+
0
]
=
color
[
i
].
red
;
screen
->
colourMap
.
data
.
shorts
[
i
*
3
+
1
]
=
color
[
i
].
green
;
screen
->
colourMap
.
data
.
shorts
[
i
*
3
+
2
]
=
color
[
i
].
blue
;
}
}
else
{
screen
->
rfbServerFormat
.
redShift
=
0
;
screen
->
rfbServerFormat
.
greenShift
=
2
;
screen
->
rfbServerFormat
.
blueShift
=
5
;
screen
->
rfbServerFormat
.
redMax
=
3
;
screen
->
rfbServerFormat
.
greenMax
=
7
;
screen
->
rfbServerFormat
.
blueMax
=
3
;
}
}
else
{
screen
->
rfbServerFormat
.
redShift
=
0
;
if
(
framebufferImage
->
red_mask
)
while
(
!
(
framebufferImage
->
red_mask
&
(
1
<<
screen
->
rfbServerFormat
.
redShift
)
)
)
screen
->
rfbServerFormat
.
redShift
++
;
screen
->
rfbServerFormat
.
greenShift
=
0
;
if
(
framebufferImage
->
green_mask
)
while
(
!
(
framebufferImage
->
green_mask
&
(
1
<<
screen
->
rfbServerFormat
.
greenShift
)
)
)
screen
->
rfbServerFormat
.
greenShift
++
;
screen
->
rfbServerFormat
.
blueShift
=
0
;
if
(
framebufferImage
->
blue_mask
)
while
(
!
(
framebufferImage
->
blue_mask
&
(
1
<<
screen
->
rfbServerFormat
.
blueShift
)
)
)
screen
->
rfbServerFormat
.
blueShift
++
;
screen
->
rfbServerFormat
.
redMax
=
framebufferImage
->
red_mask
>>
screen
->
rfbServerFormat
.
redShift
;
screen
->
rfbServerFormat
.
greenMax
=
framebufferImage
->
green_mask
>>
screen
->
rfbServerFormat
.
greenShift
;
screen
->
rfbServerFormat
.
blueMax
=
framebufferImage
->
blue_mask
>>
screen
->
rfbServerFormat
.
blueShift
;
}
backupImage
=
malloc
(
screen
->
height
*
screen
->
paddedWidthInBytes
);
memcpy
(
backupImage
,
framebufferImage
->
data
,
screen
->
height
*
screen
->
paddedWidthInBytes
);
screen
->
frameBuffer
=
backupImage
;
screen
->
cursor
=
0
;
screen
->
newClientHook
=
newClient
;
screen
->
kbdAddEvent
=
keyboard
;
screen
->
ptrAddEvent
=
mouse
;
if
(
sharedMode
)
{
screen
->
rfbAlwaysShared
=
TRUE
;
}
screen
->
rfbDeferUpdateTime
=
1
;
updateCounter
/=
screen
->
rfbDeferUpdateTime
;
rfbInitServer
(
screen
);
c
=
0
;
while
(
1
)
{
if
(
screen
->
rfbClientHead
)
maxMsecsToConnect
=
1
<<
16
;
else
{
maxMsecsToConnect
-=
screen
->
rfbDeferUpdateTime
;
if
(
maxMsecsToConnect
<
0
)
{
fprintf
(
stderr
,
"Maximum time to connect reached. Exiting.
\n
"
);
XTestDiscard
(
dpy
);
exit
(
2
);
}
}
#ifdef LOCAL_CONTROL
if
(
get_next_message
(
message
,
1024
,
&
single_instance
,
50
))
{
if
(
message
[
0
]
==
'l'
&&
message
[
1
]
==
0
)
{
rfbClientPtr
cl
;
int
i
;
for
(
i
=
0
,
cl
=
screen
->
rfbClientHead
;
cl
;
cl
=
cl
->
next
,
i
++
)
fprintf
(
stderr
,
"%02d: %s
\n
"
,
i
,
cl
->
host
);
}
else
if
(
message
[
0
]
==
't'
)
{
rfbClientPtr
cl
;
for
(
cl
=
screen
->
rfbClientHead
;
cl
;
cl
=
cl
->
next
)
if
(
!
strcmp
(
message
+
1
,
cl
->
host
))
{
cl
->
clientData
=
(
void
*
)((
cl
->
clientData
==
0
)
?-
1
:
0
);
break
;
}
}
#ifdef BACKCHANNEL
else
if
(
message
[
0
]
==
'b'
)
rfbSendBackChannel
(
screen
,
message
+
1
,
strlen
(
message
+
1
));
#endif
}
#endif
rfbProcessEvents
(
screen
,
-
1
);
if
(
shutDownServer
)
{
free
(
backupImage
);
rfbScreenCleanup
(
screen
);
XFree
(
dpy
);
#ifndef NO_SHM
XShmDetach
(
dpy
,
&
shminfo
);
#endif
exit
(
0
);
}
if
(
dontTile
)
{
if
(
gotInput
)
{
gotInput
=
FALSE
;
c
=
updateCounter
;
}
else
if
(
screen
->
rfbClientHead
&&
c
++>
updateCounter
)
{
c
=
0
;
//fprintf(stderr,"*");
if
(
!
useSHM
)
framebufferImage
->
f
.
destroy_image
(
framebufferImage
);
if
(
dontTile
)
{
getImage
(
screen
->
rfbServerFormat
.
bitsPerPixel
,
dpy
,
xscreen
,
&
framebufferImage
,
0
,
0
,
screen
->
width
,
screen
->
height
);
checkForImageUpdates
(
screen
,
framebufferImage
->
data
,
framebufferImage
->
bytes_per_line
,
0
,
0
,
screen
->
width
,
screen
->
height
);
}
else
{
/* old tile code. Eventually to be removed (TODO) */
char
isRightEdge
=
tileX
+
tileWidth
>=
screen
->
width
;
char
isLowerEdge
=
tileY
+
tileHeight
>=
screen
->
height
;
getImage
(
screen
->
rfbServerFormat
.
bitsPerPixel
,
dpy
,
xscreen
,
&
framebufferImage
,
tileX
,
tileY
,
isRightEdge
?
screen
->
width
-
tileX
:
tileWidth
,
isLowerEdge
?
screen
->
height
-
tileY
:
tileHeight
);
checkForImageUpdates
(
screen
,
framebufferImage
->
data
,
framebufferImage
->
bytes_per_line
,
tileX
,
tileY
,
isRightEdge
?
screen
->
width
-
tileX
:
tileWidth
,
isLowerEdge
?
screen
->
height
-
tileY
:
tileHeight
);
if
(
isRightEdge
)
{
tileX
=
0
;
if
(
isLowerEdge
)
tileY
=
0
;
else
tileY
+=
tileHeight
;
}
else
tileX
+=
tileWidth
;
}
}
}
else
if
(
c
++>
updateCounter
)
{
c
=
0
;
probeScreen
(
screen
,
xscreen
);
}
#ifdef WRITE_SNAPS
{
int
i
,
j
,
r
,
g
,
b
;
FILE
*
f
=
fopen
(
"test.pnm"
,
"wb"
);
fprintf
(
f
,
"P6
\n
%d %d
\n
255
\n
"
,
screen
->
width
,
screen
->
height
);
for
(
j
=
0
;
j
<
screen
->
height
;
j
++
)
for
(
i
=
0
;
i
<
screen
->
width
;
i
++
)
{
//r=screen->frameBuffer[j*screen->paddedWidthInBytes+i*2];
r
=
framebufferImage
->
data
[
j
*
screen
->
paddedWidthInBytes
+
i
*
2
];
fputc
(((
r
>>
screen
->
rfbServerFormat
.
redShift
)
&
screen
->
rfbServerFormat
.
redMax
)
*
255
/
screen
->
rfbServerFormat
.
redMax
,
f
);
fputc
(((
r
>>
screen
->
rfbServerFormat
.
greenShift
)
&
screen
->
rfbServerFormat
.
greenMax
)
*
255
/
screen
->
rfbServerFormat
.
greenMax
,
f
);
fputc
(((
r
>>
screen
->
rfbServerFormat
.
blueShift
)
&
screen
->
rfbServerFormat
.
blueMax
)
*
255
/
screen
->
rfbServerFormat
.
blueMax
,
f
);
}
fclose
(
f
);
}
#endif
}
#ifndef NO_SHM
//XShmDetach(dpy,framebufferImage);
#endif
return
(
0
);
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment