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
c984f2b1
Commit
c984f2b1
authored
Apr 03, 2003
by
dscho
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
new version from Karl!
parent
c4d44f98
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
1187 additions
and
265 deletions
+1187
-265
x11vnc.c
contrib/x11vnc.c
+1187
-265
No files found.
contrib/x11vnc.c
View file @
c984f2b1
/*
* x11vnc.c: a VNC server for X displays.
*
* Copyright (c) 2002 Karl J. Runge <runge@karlrunge.com> All rights reserved.
* Copyright (c) 2002-2003 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
...
...
@@ -39,15 +40,57 @@
* applied (currently there are a bit too many of these...)
*
* To build:
*
* Obtain the libvncserver package (http://libvncserver.sourceforge.net).
* As of 12/2002 this version of x11vnc.c is contained in the libvncserver
* CVS tree. Parameters in the Makefile should be adjusted to the build
* system and then "make x11vnc" should create it. For earlier releases
* (say libvncserver-0.4) this file may be inserted in place of the
* original x11vnc.c file.
* CVS tree and released in version 0.5. For earlier releases (say
* libvncserver-0.4) this file may be inserted in place of the original
* x11vnc.c file.
*
* gcc should be used on all platforms. To build a threaded version put
* "-D_REENTRANT -DX11VNC_THREADED" in the environment variable CFLAGS
* or CPPFLAGS (e.g. before running configure). The threaded mode is a
* bit more responsive, but can be unstable.
*
* Known shortcomings:
*
* The screen updates are good, but of course not perfect since the X
* display must be continuously polled and read for changes (as opposed to
* receiving a change callback from the X server, if that were generally
* possible...). So, e.g., opaque moves and similar window activity
* can be very painful; one has to modify one's behavior a bit.
*
* It currently cannot capture XBell beeps (impossible?) And, of course,
* general audio at the remote display is lost as well unless one separately
* sets up some audio side-channel.
*
* Windows using visuals other than the default X visual may have their
* colors messed up. When using 8bpp indexed color, the colormap may
* become out of date (as the colormap is added to) or incorrect.
*
* It does not appear possible to query the X server for the current
* cursor shape. We can use XTest to compare cursor to current window's
* cursor, but we cannot extract what the cursor is...
*
* Nevertheless, the current *position* of the remote X mouse pointer
* is shown with the -mouse option. Further, if -mouseX or -X is used, a
* trick is done to at least show the root window cursor vs non-root cursor.
* (perhaps some heuristic can be done to further distinguish cases...)
*
* With -mouse there are occasionally some repainting errors involving
* big areas near the cursor. The mouse painting is in general a bit
* ragged and not very pleasant.
*
* Occasionally, a few tile updates can be missed leaving a patch of
* color that needs to be refreshed.
*
* There seems to be a serious bug with simultaneous clients when
* threaded, currently the only workaround in this case is -nothreads.
*
*/
#include <unistd.h>
#include <signal.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <X11/Xlib.h>
...
...
@@ -76,12 +119,17 @@ typedef KeySym X_KeySym;
#include <rfb/rfb.h>
/* X and rfb framebuffer */
Display
*
dpy
=
0
;
Visual
*
visual
;
Window
window
,
rootwin
;
int
subwin
=
0
;
int
scr
;
int
dpy_x
,
dpy_y
;
int
bpp
;
int
window
;
int
button_mask
=
0
;
int
dpy_x
,
dpy_y
;
int
off_x
,
off_y
;
int
indexed_colour
=
0
;
XImage
*
tile
;
XImage
*
scanline
;
...
...
@@ -102,13 +150,14 @@ int tile_y = 32;
int
ntiles
,
ntiles_x
,
ntiles_y
;
/* arrays that indicate changed or checked tiles. */
char
*
tile_has_diff
,
*
tile_tried
;
unsigned
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
;
/* start and end lines, along y, of the changed area inside a tile. */
unsigned
short
first_line
,
last_line
;
/* info about differences along edges. */
unsigned
short
left_diff
,
right_diff
;
unsigned
short
top_diff
,
bot_diff
;
}
region_t
;
/* array to hold the tiles region_t-s. */
...
...
@@ -123,90 +172,176 @@ typedef struct hint {
/* 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. */
/* various command line options */
int
shared
=
0
;
/* share vnc display. */
int
view_only
=
0
;
/* clients can only watch. */
int
connect_once
=
1
;
/* disconnect after first connection session. */
int
flash_cmap
=
0
;
/* follow installed colormaps */
int
use_modifier_tweak
=
0
;
/* use the altgr_keyboard modifier tweak */
int
local_cursor
=
1
;
/* whether the viewer draws a local cursor */
int
show_mouse
=
0
;
/* display a cursor for the real mouse */
int
show_root_cursor
=
0
;
/* show X when on root background */
/*
* waitms is the msec to wait between screen polls. Not too old h/w shows
* poll times of 1
5-35ms, so maybe this value cuts the rest
load by 2 or so.
* poll times of 1
0-35ms, so maybe this value cuts the idle
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 */
int
screen_blank
=
60
;
/* number of seconds of no activity to throttle */
/* down the screen polls. zero to disable. */
int
take_naps
=
0
;
int
naptile
=
3
;
/* tile change threshold per poll to take a nap */
int
napfac
=
4
;
/* time = napfac*waitms, cut load with extra waits */
int
napmax
=
1500
;
/* longest nap in ms. */
int
nap_ok
=
0
,
nap_diff_count
=
0
;
time_t
last_event
,
last_input
;
/* tile heuristics: */
double
fs_frac
=
0
.
6
;
/* threshold tile fraction to do fullscreen updates. */
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
.
6
;
/* threshold tile fraction to do fullscreen updates. */
/* scan pattern jitter from x0rfbserver */
#define NSCAN 32
int
scanlines
[
NSCAN
]
=
{
/* scan pattern jitter from x0rfbserver */
int
scanlines
[
NSCAN
]
=
{
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
count
=
0
;
/* indicates which scan pattern we are on */
int
got_user_input
;
int
coun
t
=
0
;
int
cursor_x
,
cursor_y
;
/* x and y from the viewer(s) */
int
got_user_inpu
t
=
0
;
int
shut_down
=
0
;
#if defined(HAVE_LIBPTHREAD) && defined(X11VNC_THREADED)
int
use_threads
=
1
;
#else
int
use_threads
=
0
;
#endif
/* XXX usleep(3) is not thread safe on some older systems... */
struct
timeval
_mysleep
;
#define usleep2(x) \
_mysleep.tv_sec = (x) / 1000000; \
_mysleep.tv_usec = (x) % 1000000; \
select(0, NULL, NULL, NULL, &_mysleep);
#if !defined(X11VNC_USLEEP)
#undef usleep
#define usleep usleep2
#endif
/*
* 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?
* avoid XIO crashes.
*/
MUTEX
(
x11Mutex
);
#define X_LOCK LOCK(x11Mutex);
#define X_UNLOCK UNLOCK(x11Mutex);
void
mark_hint
(
hint_t
);
void
clean_up_exit
(
void
)
{
#define X_LOCK LOCK(x11Mutex)
#define X_UNLOCK UNLOCK(x11Mutex)
#define X_INIT INIT_MUTEX(x11Mutex)
X_LOCK
/*
* Exiting and error handling:
*/
void
shm_clean
(
XShmSegmentInfo
*
,
XImage
*
);
void
shm_delete
(
XShmSegmentInfo
*
);
XTestDiscard
(
dpy
);
int
exit_flag
=
0
;
void
clean_up_exit
(
int
ret
)
{
exit_flag
=
1
;
/* remove the shm areas: */
shm_clean
(
&
tile_shm
,
tile
);
shm_clean
(
&
scanline_shm
,
scanline
);
shm_clean
(
&
fullscreen_shm
,
fullscreen
);
XShmDetach
(
dpy
,
&
tile_shm
);
XDestroyImage
(
tile
);
shmdt
(
tile_shm
.
shmaddr
);
shmctl
(
tile_shm
.
shmid
,
IPC_RMID
,
0
);
X_LOCK
;
XTestDiscard
(
dpy
);
X_UNLOCK
;
XShmDetach
(
dpy
,
&
scanline_shm
);
XDestroyImage
(
scanline
);
shmdt
(
scanline_shm
.
shmaddr
);
shmctl
(
scanline_shm
.
shmid
,
IPC_RMID
,
0
);
exit
(
ret
);
}
XShmDetach
(
dpy
,
&
fullscreen_shm
);
XDestroyImage
(
fullscreen
);
shmdt
(
fullscreen_shm
.
shmaddr
);
shmctl
(
fullscreen_shm
.
shmid
,
IPC_RMID
,
0
);
void
interrupted
(
int
sig
)
{
if
(
exit_flag
)
{
if
(
use_threads
)
{
usleep2
(
250
*
1000
);
}
exit
(
4
);
}
exit_flag
++
;
if
(
sig
==
0
)
{
printf
(
"caught X11 error:
\n
"
);
}
else
{
printf
(
"caught signal: %d
\n
"
,
sig
);
}
/*
* to avoid deadlock, etc, just delete the shm areas and
* leave the X stuff hanging.
*/
shm_delete
(
&
tile_shm
);
shm_delete
(
&
scanline_shm
);
shm_delete
(
&
fullscreen_shm
);
if
(
sig
)
{
exit
(
2
);
}
}
/* more cleanup? */
XErrorHandler
Xerror_def
;
XIOErrorHandler
XIOerr_def
;
int
Xerror
(
Display
*
d
,
XErrorEvent
*
error
)
{
interrupted
(
0
);
return
(
*
Xerror_def
)(
d
,
error
);
}
int
XIOerr
(
Display
*
d
)
{
interrupted
(
0
);
return
(
*
XIOerr_def
)(
d
);
}
X_UNLOCK
exit
(
0
);
void
set_signals
(
void
)
{
signal
(
SIGHUP
,
interrupted
);
signal
(
SIGINT
,
interrupted
);
signal
(
SIGQUIT
,
interrupted
);
signal
(
SIGABRT
,
interrupted
);
signal
(
SIGTERM
,
interrupted
);
signal
(
SIGBUS
,
interrupted
);
signal
(
SIGSEGV
,
interrupted
);
signal
(
SIGFPE
,
interrupted
);
X_LOCK
;
Xerror_def
=
XSetErrorHandler
(
Xerror
);
XIOerr_def
=
XSetIOErrorHandler
(
XIOerr
);
X_UNLOCK
;
}
void
client_gone
(
rfbClientPtr
client
)
{
if
(
connect_once
)
{
printf
(
"
only one connection allow
ed.
\n
"
);
clean_up_exit
();
printf
(
"
viewer exit
ed.
\n
"
);
clean_up_exit
(
0
);
}
}
enum
rfbNewClientAction
new_client
(
rfbClientPtr
client
)
{
static
client_count
=
0
;
last_event
=
last_input
=
time
(
0
);
if
(
connect_once
)
{
if
(
screen
->
rfbDontDisconnect
&&
screen
->
rfbNeverShared
)
{
if
(
!
shared
&&
client_count
)
{
printf
(
"denying additional client: %s
\n
"
,
client
->
host
);
return
(
RFB_CLIENT_REFUSE
);
}
}
client
->
clientGoneHook
=
client_gone
;
}
if
(
view_only
)
{
...
...
@@ -214,11 +349,13 @@ enum rfbNewClientAction new_client(rfbClientPtr client) {
}
else
{
client
->
clientData
=
(
void
*
)
0
;
}
client_count
++
;
return
(
RFB_CLIENT_ACCEPT
);
}
/* For tweaking modifiers wrt the Alt-Graph key */
/*
* For tweaking modifiers wrt the Alt-Graph key, etc.
*/
#define LEFTSHIFT 1
#define RIGHTSHIFT 2
#define ALTGR 4
...
...
@@ -277,9 +414,10 @@ void initialize_keycodes() {
void
DebugXTestFakeKeyEvent
(
Display
*
dpy
,
KeyCode
keysym
,
Bool
down
,
time_t
cur_time
)
{
fprintf
(
stderr
,
"XTestFakeKeyEvent(dpy,%s(0x%x),%s,CurrentTime)
\n
"
,
XKeysymToString
(
XKeycodeToKeysym
(
dpy
,
keysym
,
0
)),
keysym
,
down
?
"down"
:
"up"
);
XTestFakeKeyEvent
(
dpy
,
keysym
,
down
,
cur_time
);
fprintf
(
stderr
,
"XTestFakeKeyEvent(dpy,%s(0x%x),%s,CurrentTime)
\n
"
,
XKeysymToString
(
XKeycodeToKeysym
(
dpy
,
keysym
,
0
)),
keysym
,
down
?
"down"
:
"up"
);
XTestFakeKeyEvent
(
dpy
,
keysym
,
down
,
cur_time
);
}
/* #define XTestFakeKeyEvent DebugXTestFakeKeyEvent */
...
...
@@ -292,7 +430,7 @@ void tweak_mod(signed char mod, Bool down) {
return
;
}
X_LOCK
X_LOCK
;
if
(
is_shift
&&
mod
!=
1
)
{
if
(
mod_state
&
LEFTSHIFT
)
{
XTestFakeKeyEvent
(
dpy
,
left_shift_code
,
!
dn
,
CurrentTime
);
...
...
@@ -310,7 +448,7 @@ void tweak_mod(signed char mod, Bool down) {
if
(
altgr_code
&&
!
(
mod_state
&
ALTGR
)
&&
mod
==
2
)
{
XTestFakeKeyEvent
(
dpy
,
altgr_code
,
dn
,
CurrentTime
);
}
X_UNLOCK
X_UNLOCK
;
}
static
void
modifier_tweak_keyboard
(
Bool
down
,
KeySym
keysym
,
rfbClientPtr
client
)
{
...
...
@@ -339,14 +477,14 @@ static void modifier_tweak_keyboard(Bool down, KeySym keysym, rfbClientPtr clien
tweak_mod
(
modifiers
[
keysym
],
True
);
k
=
keycodes
[
keysym
];
}
else
{
X_LOCK
X_LOCK
;
k
=
XKeysymToKeycode
(
dpy
,
(
X_KeySym
)
keysym
);
X_UNLOCK
X_UNLOCK
;
}
if
(
k
!=
NoSymbol
)
{
X_LOCK
X_LOCK
;
XTestFakeKeyEvent
(
dpy
,
k
,
(
X_Bool
)
down
,
CurrentTime
);
X_UNLOCK
X_UNLOCK
;
}
if
(
tweak
)
{
...
...
@@ -354,12 +492,18 @@ static void modifier_tweak_keyboard(Bool down, KeySym keysym, rfbClientPtr clien
}
}
/* key event handler */
/*
* key event handler
*/
static
void
keyboard
(
Bool
down
,
KeySym
keysym
,
rfbClientPtr
client
)
{
KeyCode
k
;
/* fprintf(stderr,"keyboard(%s,%s(0x%x),client)\n",
down?"down":"up",XKeysymToString(keysym),(int)keysym); */
if
(
0
)
{
X_LOCK
;
fprintf
(
stderr
,
"keyboard(%s,%s(0x%x),client)
\n
"
,
down
?
"down"
:
"up"
,
XKeysymToString
(
keysym
),(
int
)
keysym
);
X_UNLOCK
;
}
if
(
view_only
)
{
return
;
...
...
@@ -370,7 +514,7 @@ static void keyboard(Bool down, KeySym keysym, rfbClientPtr client) {
return
;
}
X_LOCK
X_LOCK
;
k
=
XKeysymToKeycode
(
dpy
,
(
X_KeySym
)
keysym
);
...
...
@@ -378,13 +522,16 @@ static void keyboard(Bool down, KeySym keysym, rfbClientPtr client) {
XTestFakeKeyEvent
(
dpy
,
k
,
(
X_Bool
)
down
,
CurrentTime
);
XFlush
(
dpy
);
last_event
=
last_input
=
time
(
0
);
got_user_input
++
;
}
X_UNLOCK
X_UNLOCK
;
}
/* mouse event handler */
/*
* pointer event handler
*/
static
void
pointer
(
int
mask
,
int
x
,
int
y
,
rfbClientPtr
client
)
{
int
i
;
...
...
@@ -392,10 +539,14 @@ static void pointer(int mask, int x, int y, rfbClientPtr client) {
return
;
}
X_LOCK
X_LOCK
;
XTestFakeMotionEvent
(
dpy
,
scr
,
x
+
off_x
,
y
+
off_y
,
CurrentTime
);
XTestFakeMotionEvent
(
dpy
,
0
,
x
,
y
,
CurrentTime
);
cursor_x
=
x
;
cursor_y
=
y
;
last_event
=
last_input
=
time
(
0
);
got_user_input
++
;
for
(
i
=
0
;
i
<
5
;
i
++
)
{
...
...
@@ -404,35 +555,30 @@ static void pointer(int mask, int x, int y, rfbClientPtr client) {
(
mask
&
(
1
<<
i
))
?
True
:
False
,
CurrentTime
);
}
}
X_UNLOCK
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 "
" "
" "
;
void
mark_hint
(
hint_t
);
static
char
*
cur_mask
=
/*
* here begins a bit of a mess to experiment with multiple cursors ...
*/
typedef
struct
cursor_info
{
char
*
data
;
/* data and mask pointers */
char
*
mask
;
int
wx
,
wy
;
/* size of cursor */
int
sx
,
sy
;
/* shift to its centering point */
int
reverse
;
/* swap black and white */
}
cursor_info_t
;
/* main cursor */
static
char
*
cur_data
=
" "
" x "
" xx "
" xxx "
" xxxx "
...
...
@@ -440,19 +586,430 @@ static char* cur_mask =
" xxxxxx "
" xxxxxxx "
" xxxxxxxx "
" xxxxxxxxx "
" xxxxxxxxxx "
" xxxxxxxxxx "
" xxxxxxx "
" xxx xxxx "
" xx xxxx "
" xxxx "
" xxxx "
" xx "
" xxxxx "
" xx xx "
" x xx "
" xx "
" xx "
" xx "
" "
" "
" "
;
int
cursor_x
=
18
;
int
cursor_y
=
18
;
static
char
*
cur_mask
=
"xx "
"xxx "
"xxxx "
"xxxxx "
"xxxxxx "
"xxxxxxx "
"xxxxxxxx "
"xxxxxxxxx "
"xxxxxxxxxx "
"xxxxxxxxxx "
"xxxxxxx "
"xxx xxxx "
"xx xxxx "
" xxxx "
" xxxx "
" xx "
" "
" "
;
#define CUR_SIZE 18
#define CUR_DATA cur_data
#define CUR_MASK cur_mask
cursor_info_t
cur0
=
{
NULL
,
NULL
,
CUR_SIZE
,
CUR_SIZE
,
0
,
0
,
0
};
/*
* It turns out we can at least detect mouse is on the root window so
* show it (under -mouseX or -X) with this familiar cursor...
*/
static
char
*
root_data
=
" "
" "
" xxx xxx "
" xxxx xxxx "
" xxxxx xxxxx "
" xxxxx xxxxx "
" xxxxxxxxxx "
" xxxxxxxx "
" xxxxxx "
" xxxxxx "
" xxxxxxxx "
" xxxxxxxxxx "
" xxxxx xxxxx "
" xxxxx xxxxx "
" xxxx xxxx "
" xxx xxx "
" "
" "
;
static
char
*
root_mask
=
" "
" xxxx xxxx "
" xxxxx xxxxx "
" xxxxxx xxxxxx "
" xxxxxxx xxxxxxx "
" xxxxxxxxxxxxxx "
" xxxxxxxxxxxx "
" xxxxxxxxxx "
" xxxxxxxx "
" xxxxxxxx "
" xxxxxxxxxx "
" xxxxxxxxxxxx "
" xxxxxxxxxxxxxx "
" xxxxxxx xxxxxxx "
" xxxxxx xxxxxx "
" xxxxx xxxxx "
" xxxx xxxx "
" "
;
cursor_info_t
cur1
=
{
NULL
,
NULL
,
18
,
18
,
8
,
8
,
1
};
cursor_info_t
*
cursors
[
2
];
void
setup_cursors
(
void
)
{
/* TODO clean this up if we ever do more cursors... */
cur0
.
data
=
cur_data
;
cur0
.
mask
=
cur_mask
;
cur1
.
data
=
root_data
;
cur1
.
mask
=
root_mask
;
cursors
[
0
]
=
&
cur0
;
cursors
[
1
]
=
&
cur1
;
}
/*
* data and functions for -mouse real pointer position updates
*/
char
cur_save
[(
4
*
CUR_SIZE
*
CUR_SIZE
)];
int
cur_save_x
,
cur_save_y
,
cur_save_w
,
cur_save_h
;
int
cur_save_cx
,
cur_save_cy
,
cur_save_which
,
cur_saved
=
0
;
/*
* save current cursor info and the patch of data it covers
*/
void
save_mouse_patch
(
int
x
,
int
y
,
int
w
,
int
h
,
int
cx
,
int
cy
,
int
which
)
{
int
pixelsize
=
bpp
>>
3
;
char
*
rfb_fb
=
screen
->
frameBuffer
;
int
ly
,
i
=
0
;
for
(
ly
=
y
;
ly
<
y
+
h
;
ly
++
)
{
memcpy
(
cur_save
+
i
,
rfb_fb
+
ly
*
bytes_per_line
+
x
*
pixelsize
,
w
*
pixelsize
);
i
+=
w
*
pixelsize
;
}
cur_save_x
=
x
;
/* patch geometry */
cur_save_y
=
y
;
cur_save_w
=
w
;
cur_save_h
=
h
;
cur_save_which
=
which
;
/* which cursor and its position */
cur_save_cx
=
cx
;
cur_save_cy
=
cy
;
cur_saved
=
1
;
}
/*
* put the non-cursor patch back in the rfb fb
*/
void
restore_mouse_patch
()
{
int
pixelsize
=
bpp
>>
3
;
char
*
rfb_fb
=
screen
->
frameBuffer
;
int
ly
,
i
=
0
;
if
(
!
cur_saved
)
{
return
;
/* not yet saved */
}
for
(
ly
=
cur_save_y
;
ly
<
cur_save_y
+
cur_save_h
;
ly
++
)
{
memcpy
(
rfb_fb
+
ly
*
bytes_per_line
+
cur_save_x
*
pixelsize
,
cur_save
+
i
,
cur_save_w
*
pixelsize
);
i
+=
cur_save_w
*
pixelsize
;
}
}
/*
* Descends windows at pointer until the window cursor matches the current
* cursor. So far only used to detect if mouse is on root background or not.
* (returns 0 in that case, 1 otherwise).
*
* It seems impossible to do, but if the actual cursor could ever be
* determined we might want to hash that info on window ID or something...
*/
int
tree_depth_cursor
(
void
)
{
Window
r
,
c
;
int
rx
,
ry
,
wx
,
wy
;
unsigned
int
mask
;
int
depth
=
0
,
tries
=
0
,
maxtries
=
1
;
X_LOCK
;
c
=
window
;
while
(
c
)
{
if
(
++
tries
>
maxtries
)
{
depth
=
maxtries
;
break
;
}
if
(
XTestCompareCurrentCursorWithWindow
(
dpy
,
c
)
)
{
break
;
}
XQueryPointer
(
dpy
,
c
,
&
r
,
&
c
,
&
rx
,
&
ry
,
&
wx
,
&
wy
,
&
mask
);
depth
++
;
}
X_UNLOCK
;
return
depth
;
}
/*
* draw one of the mouse cursors into the rfb fb
*/
void
draw_mouse
(
int
x
,
int
y
,
int
which
,
int
update
)
{
int
px
,
py
,
i
,
offset
;
int
pixelsize
=
bpp
>>
3
;
char
*
rfb_fb
=
screen
->
frameBuffer
;
char
cdata
,
cmask
;
char
*
data
,
*
mask
;
int
white
=
255
,
black
=
0
,
shade
;
int
x0
,
x1
,
x2
,
y0
,
y1
,
y2
;
int
cur_x
,
cur_y
,
cur_sx
,
cur_sy
,
reverse
;
static
int
first
=
1
;
if
(
first
)
{
first
=
0
;
setup_cursors
();
}
data
=
cursors
[
which
]
->
data
;
/* pattern data */
mask
=
cursors
[
which
]
->
mask
;
cur_x
=
cursors
[
which
]
->
wx
;
/* widths */
cur_y
=
cursors
[
which
]
->
wy
;
cur_sx
=
cursors
[
which
]
->
sx
;
/* shifts */
cur_sy
=
cursors
[
which
]
->
sy
;
reverse
=
cursors
[
which
]
->
reverse
;
/* reverse video */
if
(
reverse
)
{
black
=
white
;
white
=
0
;
}
/*
* notation:
* x0, y0: position after cursor shift (no edge corrections)
* x1, y1: corrected for lower boundary < 0
* x2, y2: position + cursor width and corrected for upper boundary
*/
x0
=
x1
=
x
-
cur_sx
;
/* apply shift */
if
(
x1
<
0
)
x1
=
0
;
y0
=
y1
=
y
-
cur_sy
;
if
(
y1
<
0
)
y1
=
0
;
x2
=
x0
+
cur_x
;
/* apply width for upper endpoints */
if
(
x2
>=
dpy_x
)
x2
=
dpy_x
-
1
;
y2
=
y0
+
cur_y
;
if
(
y2
>=
dpy_y
)
y2
=
dpy_y
-
1
;
/* save the patch and info about which cursor will overwrite it */
save_mouse_patch
(
x1
,
y1
,
x2
-
x1
,
y2
-
y1
,
x
,
y
,
which
);
for
(
py
=
0
;
py
<
cur_y
;
py
++
)
{
if
(
y0
+
py
<
0
||
y0
+
py
>=
dpy_y
)
{
continue
;
/* off screen */
}
for
(
px
=
0
;
px
<
cur_x
;
px
++
)
{
if
(
x0
+
px
<
0
||
x0
+
px
>=
dpy_x
){
continue
;
/* off screen */
}
cdata
=
data
[
px
+
py
*
cur_x
];
cmask
=
mask
[
px
+
py
*
cur_x
];
if
(
cmask
!=
'x'
)
{
continue
;
/* transparent */
}
shade
=
white
;
if
(
cdata
!=
cmask
)
{
shade
=
black
;
}
offset
=
(
y0
+
py
)
*
bytes_per_line
+
(
x0
+
px
)
*
pixelsize
;
/* fill in each color byte in the fb */
for
(
i
=
0
;
i
<
pixelsize
;
i
++
)
{
rfb_fb
[
offset
+
i
]
=
(
char
)
shade
;
}
}
}
if
(
update
)
{
/* x and y of the real (X server) mouse */
static
int
mouse_x
=
-
1
;
static
int
mouse_y
=
-
1
;
if
(
x
!=
mouse_x
||
y
!=
mouse_y
)
{
hint_t
hint
;
hint
.
x
=
x1
;
hint
.
y
=
y2
;
hint
.
w
=
x2
-
x1
;
hint
.
h
=
y2
-
y1
;
mark_hint
(
hint
);
if
(
mouse_x
<
0
)
{
mouse_x
=
0
;
}
if
(
mouse_y
<
0
)
{
mouse_y
=
0
;
}
/* XXX this ignores change of shift... */
x1
=
mouse_x
-
cur_sx
;
if
(
x1
<
0
)
x1
=
0
;
y1
=
mouse_y
-
cur_sy
;
if
(
y1
<
0
)
y1
=
0
;
x2
=
mouse_x
-
cur_sx
+
cur_x
;
if
(
x2
>=
dpy_x
)
x2
=
dpy_x
-
1
;
y2
=
mouse_y
-
cur_sy
+
cur_y
;
if
(
y2
>=
dpy_y
)
y2
=
dpy_y
-
1
;
hint
.
x
=
x1
;
hint
.
y
=
y2
;
hint
.
w
=
x2
-
x1
;
hint
.
h
=
y2
-
y1
;
mark_hint
(
hint
);
mouse_x
=
x
;
mouse_y
=
y
;
}
}
}
void
redraw_mouse
(
void
)
{
if
(
cur_saved
)
{
/* redraw saved mouse from info (save_mouse_patch) */
draw_mouse
(
cur_save_cx
,
cur_save_cy
,
cur_save_which
,
0
);
}
}
void
update_mouse
(
void
)
{
Window
root_w
,
child_w
;
Bool
ret
;
int
root_x
,
root_y
,
win_x
,
win_y
,
which
=
0
;
unsigned
int
mask
;
X_LOCK
;
ret
=
XQueryPointer
(
dpy
,
rootwin
,
&
root_w
,
&
child_w
,
&
root_x
,
&
root_y
,
&
win_x
,
&
win_y
,
&
mask
);
X_UNLOCK
;
if
(
!
ret
)
{
return
;
}
if
(
show_root_cursor
)
{
int
depth
;
if
(
(
depth
=
tree_depth_cursor
())
)
{
which
=
0
;
}
else
{
which
=
1
;
}
}
draw_mouse
(
root_x
-
off_x
,
root_y
-
off_y
,
which
,
1
);
}
void
set_offset
(
void
)
{
Window
w
;
if
(
!
subwin
)
{
return
;
}
X_LOCK
;
XTranslateCoordinates
(
dpy
,
window
,
rootwin
,
0
,
0
,
&
off_x
,
&
off_y
,
&
w
);
X_UNLOCK
;
}
#define NCOLOR 256
void
set_colormap
(
void
)
{
static
int
first
=
1
;
static
XColor
color
[
NCOLOR
],
prev
[
NCOLOR
];
Colormap
cmap
;
int
i
,
diffs
=
0
;
if
(
first
)
{
screen
->
colourMap
.
count
=
NCOLOR
;
screen
->
rfbServerFormat
.
trueColour
=
FALSE
;
screen
->
colourMap
.
is16
=
TRUE
;
screen
->
colourMap
.
data
.
shorts
=
(
unsigned
short
*
)
malloc
(
3
*
sizeof
(
short
)
*
NCOLOR
);
}
for
(
i
=
0
;
i
<
NCOLOR
;
i
++
)
{
color
[
i
].
pixel
=
i
;
prev
[
i
].
red
=
color
[
i
].
red
;
prev
[
i
].
green
=
color
[
i
].
green
;
prev
[
i
].
blue
=
color
[
i
].
blue
;
}
X_LOCK
;
cmap
=
DefaultColormap
(
dpy
,
scr
);
if
(
flash_cmap
&&
!
first
)
{
XWindowAttributes
attr
;
Window
r
,
c
;
int
rx
,
ry
,
wx
,
wy
,
tries
=
0
;
unsigned
int
m
;
c
=
window
;
while
(
c
&&
tries
++
<
16
)
{
/* XXX this is a hack, XQueryTree probably better. */
XQueryPointer
(
dpy
,
c
,
&
r
,
&
c
,
&
rx
,
&
ry
,
&
wx
,
&
wy
,
&
m
);
if
(
c
&&
XGetWindowAttributes
(
dpy
,
c
,
&
attr
))
{
if
(
attr
.
colormap
&&
attr
.
map_installed
)
{
cmap
=
attr
.
colormap
;
break
;
}
}
else
{
break
;
}
}
}
XQueryColors
(
dpy
,
cmap
,
color
,
NCOLOR
);
X_UNLOCK
;
for
(
i
=
0
;
i
<
NCOLOR
;
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
;
if
(
prev
[
i
].
red
!=
color
[
i
].
red
||
prev
[
i
].
green
!=
color
[
i
].
green
||
prev
[
i
].
blue
!=
color
[
i
].
blue
)
{
diffs
++
;
}
}
if
(
diffs
&&
!
first
)
{
rfbSetClientColourMaps
(
screen
,
0
,
NCOLOR
);
}
first
=
0
;
}
/*
* initialize the rfb framebuffer/screen
*/
void
initialize_screen
(
int
*
argc
,
char
**
argv
,
XImage
*
fb
)
{
screen
=
rfbGetScreen
(
argc
,
argv
,
fb
->
width
,
fb
->
height
,
...
...
@@ -463,35 +1020,18 @@ void initialize_screen(int *argc, char **argv, XImage *fb) {
screen
->
rfbServerFormat
.
depth
=
fb
->
depth
;
screen
->
rfbServerFormat
.
trueColour
=
(
uint8_t
)
TRUE
;
if
(
screen
->
rfbServerFormat
.
bitsPerPixel
==
8
)
{
/* 8 bpp */
if
(
CellsOfScreen
(
ScreenOfDisplay
(
dpy
,
scr
)))
{
/* indexed colour */
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
,
scr
),
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
{
/* true colour */
screen
->
rfbServerFormat
.
redShift
=
0
;
screen
->
rfbServerFormat
.
greenShift
=
2
;
screen
->
rfbServerFormat
.
blueShift
=
5
;
screen
->
rfbServerFormat
.
redMax
=
3
;
screen
->
rfbServerFormat
.
greenMax
=
7
;
screen
->
rfbServerFormat
.
blueMax
=
3
;
}
if
(
screen
->
rfbServerFormat
.
bitsPerPixel
==
8
&&
CellsOfScreen
(
ScreenOfDisplay
(
dpy
,
scr
))
)
{
/* indexed colour */
printf
(
"using 8bpp indexed colour
\n
"
);
indexed_colour
=
1
;
set_colormap
();
}
else
{
/* general case ... */
printf
(
"using %dbpp depth=%d true colour
\n
"
,
fb
->
bits_per_pixel
,
fb
->
depth
);
/* convert masks to bit shifts and max # colors */
screen
->
rfbServerFormat
.
redShift
=
0
;
if
(
fb
->
red_mask
)
{
while
(
!
(
fb
->
red_mask
...
...
@@ -530,8 +1070,13 @@ void initialize_screen(int *argc, char **argv, XImage *fb) {
if
(
screen
->
rfbDeferUpdateTime
==
5
)
{
screen
->
rfbDeferUpdateTime
=
defer_update
;
}
if
(
shared
&&
!
screen
->
rfbNeverShared
)
{
screen
->
rfbAlwaysShared
=
TRUE
;
if
(
!
screen
->
rfbNeverShared
&&
!
screen
->
rfbAlwaysShared
)
{
if
(
shared
)
{
screen
->
rfbAlwaysShared
=
TRUE
;
}
else
{
screen
->
rfbDontDisconnect
=
TRUE
;
screen
->
rfbNeverShared
=
TRUE
;
}
}
/* event callbacks: */
...
...
@@ -539,8 +1084,12 @@ void initialize_screen(int *argc, char **argv, XImage *fb) {
screen
->
kbdAddEvent
=
keyboard
;
screen
->
ptrAddEvent
=
pointer
;
cursor
=
rfbMakeXCursor
(
cursor_x
,
cursor_y
,
cur_data
,
cur_mask
);
screen
->
cursor
=
cursor
;
if
(
local_cursor
)
{
cursor
=
rfbMakeXCursor
(
CUR_SIZE
,
CUR_SIZE
,
CUR_DATA
,
CUR_MASK
);
screen
->
cursor
=
cursor
;
}
else
{
screen
->
cursor
=
NULL
;
}
rfbInitServer
(
screen
);
...
...
@@ -557,8 +1106,10 @@ void initialize_tiles() {
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_has_diff
=
(
unsigned
char
*
)
malloc
((
size_t
)
(
ntiles
*
sizeof
(
unsigned
char
)));
tile_tried
=
(
unsigned
char
*
)
malloc
((
size_t
)
(
ntiles
*
sizeof
(
unsigned
char
)));
tile_region
=
(
region_t
*
)
malloc
((
size_t
)
(
ntiles
*
sizeof
(
region_t
)));
/* there will never be more hints than tiles: */
...
...
@@ -589,35 +1140,75 @@ void set_fs_factor(int max) {
}
}
void
initialize_shm
()
{
/*
* set up an XShm image
*/
void
shm_create
(
XShmSegmentInfo
*
shm
,
XImage
**
ximg_ptr
,
int
w
,
int
h
,
char
*
name
)
{
/* the tile (e.g. 32x32) shared memory area image: */
XImage
*
xim
;
tile
=
XShmCreateImage
(
dpy
,
DefaultVisual
(
dpy
,
0
),
bpp
,
ZPixmap
,
NULL
,
&
tile_shm
,
tile_x
,
tile_y
);
X_LOCK
;
tile_shm
.
shmid
=
shmget
(
IPC_PRIVATE
,
tile
->
bytes_per_line
*
tile
->
height
,
IPC_CREAT
|
0777
);
xim
=
XShmCreateImage
(
dpy
,
visual
,
bpp
,
ZPixmap
,
NULL
,
shm
,
w
,
h
);
tile_shm
.
shmaddr
=
tile
->
data
=
(
char
*
)
shmat
(
tile_shm
.
shmid
,
0
,
0
);
tile_shm
.
readOnly
=
False
;
if
(
xim
==
NULL
)
{
fprintf
(
stderr
,
"XShmCreateImage(%s) failed.
\n
"
,
name
);
exit
(
1
);
}
XShmAttach
(
dpy
,
&
tile_shm
)
;
*
ximg_ptr
=
xim
;
shm
->
shmid
=
shmget
(
IPC_PRIVATE
,
xim
->
bytes_per_line
*
xim
->
height
,
IPC_CREAT
|
0777
);
/* the scanline (e.g. 1280x1) shared memory area image: */
if
(
shm
->
shmid
==
-
1
)
{
fprintf
(
stderr
,
"shmget(%s) failed.
\n
"
,
name
);
perror
(
"shmget"
);
exit
(
1
);
}
scanline
=
XShmCreateImage
(
dpy
,
DefaultVisual
(
dpy
,
0
),
bpp
,
ZPixmap
,
NULL
,
&
scanline_shm
,
dpy_x
,
1
);
shm
->
shmaddr
=
xim
->
data
=
(
char
*
)
shmat
(
shm
->
shmid
,
0
,
0
);
scanline_shm
.
shmid
=
shmget
(
IPC_PRIVATE
,
scanline
->
bytes_per_line
*
scanline
->
height
,
IPC_CREAT
|
0777
);
if
(
shm
->
shmaddr
==
(
char
*
)
-
1
)
{
fprintf
(
stderr
,
"shmat(%s) failed.
\n
"
,
name
);
perror
(
"shmat"
);
exit
(
1
);
}
scanline_shm
.
shmaddr
=
scanline
->
data
=
(
char
*
)
shmat
(
scanline_shm
.
shmid
,
0
,
0
);
scanline_shm
.
readOnly
=
False
;
shm
->
readOnly
=
False
;
if
(
!
XShmAttach
(
dpy
,
shm
))
{
fprintf
(
stderr
,
"XShmAttach(%s) failed.
\n
"
,
name
);
exit
(
1
);
}
XShmAttach
(
dpy
,
&
scanline_shm
);
X_UNLOCK
;
}
void
shm_delete
(
XShmSegmentInfo
*
shm
)
{
shmdt
(
shm
->
shmaddr
);
shmctl
(
shm
->
shmid
,
IPC_RMID
,
0
);
}
void
shm_clean
(
XShmSegmentInfo
*
shm
,
XImage
*
xim
)
{
X_LOCK
;
XShmDetach
(
dpy
,
shm
);
XDestroyImage
(
xim
);
X_UNLOCK
;
shm_delete
(
shm
);
}
void
initialize_shm
()
{
/* the tile (e.g. 32x32) shared memory area image: */
shm_create
(
&
tile_shm
,
&
tile
,
tile_x
,
tile_y
,
"tile"
);
/* the scanline (e.g. 1280x1) shared memory area image: */
shm_create
(
&
scanline_shm
,
&
scanline
,
dpy_x
,
1
,
"scanline"
);
/*
* the fullscreen (e.g. 1280x1024/fs_factor) shared memory area image:
...
...
@@ -630,19 +1221,12 @@ void initialize_shm() {
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
;
shm_create
(
&
fullscreen_shm
,
&
fullscreen
,
dpy_x
,
dpy_y
/
fs_factor
,
"fullscreen"
);
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
...
...
@@ -694,9 +1278,7 @@ void extend_tile_hint(int x, int y, int th, hint_t *hint) {
}
void
save_hint
(
hint_t
hint
,
int
loc
)
{
/* copy it to the global array: */
hint_list
[
loc
].
x
=
hint
.
x
;
hint_list
[
loc
].
x
=
hint
.
x
;
/* copy to the global array */
hint_list
[
loc
].
y
=
hint
.
y
;
hint_list
[
loc
].
w
=
hint
.
w
;
hint_list
[
loc
].
h
=
hint
.
h
;
...
...
@@ -804,17 +1386,20 @@ void tile_updates() {
* 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
* image difference to the
rfb
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
;
unsigned
short
l_diff
=
0
,
r_diff
=
0
;
int
restored_patch
=
0
;
/* for show_mouse */
char
*
src
,
*
dst
,
*
s_src
,
*
s_dst
,
*
m_src
,
*
m_dst
;
char
*
h_src
,
*
h_dst
;
...
...
@@ -823,16 +1408,14 @@ void copy_tile(int tx, int ty) {
y
=
ty
*
tile_y
;
size_x
=
dpy_x
-
x
;
if
(
size_x
>
tile_x
)
{
size_x
=
tile_x
;
}
if
(
size_x
>
tile_x
)
size_x
=
tile_x
;
size_y
=
dpy_y
-
y
;
if
(
size_y
>
tile_y
)
{
size_y
=
tile_y
;
}
if
(
size_y
>
tile_y
)
size_y
=
tile_y
;
n
=
tx
+
ty
*
ntiles_x
;
/* number of the tile */
X_LOCK
X_LOCK
;
if
(
size_x
==
tile_x
&&
size_y
==
tile_y
)
{
/* general case: */
XShmGetImage
(
dpy
,
window
,
tile
,
x
,
y
,
AllPlanes
);
...
...
@@ -844,7 +1427,25 @@ void copy_tile(int tx, int ty) {
XGetSubImage
(
dpy
,
window
,
x
,
y
,
size_x
,
size_y
,
AllPlanes
,
ZPixmap
,
tile
,
0
,
0
);
}
X_UNLOCK
X_UNLOCK
;
/*
* Some awkwardness wrt the little remote mouse patch we display.
* When threaded we want to have as small a window of time
* as possible when the mouse image is not in the fb, otherwise
* a libvncserver thread may send the uncorrected patch to the
* clients.
*/
if
(
show_mouse
&&
use_threads
&&
cur_saved
)
{
/* check for overlap */
if
(
cur_save_x
+
cur_save_w
>
x
&&
x
+
size_x
>
cur_save_x
&&
cur_save_y
+
cur_save_h
>
y
&&
y
+
size_y
>
cur_save_y
)
{
/* restore the real data to the rfb fb */
restore_mouse_patch
();
restored_patch
=
1
;
}
}
src
=
tile
->
data
;
dst
=
screen
->
frameBuffer
+
y
*
bytes_per_line
+
x
*
pixelsize
;
...
...
@@ -868,6 +1469,9 @@ void copy_tile(int tx, int ty) {
if
(
first_line
==
-
1
)
{
/* tile has no difference, note it and get out: */
tile_has_diff
[
n
]
=
0
;
if
(
restored_patch
)
{
redraw_mouse
();
}
return
;
}
else
{
/*
...
...
@@ -911,13 +1515,17 @@ void copy_tile(int tx, int ty) {
h_dst
+=
bytes_per_line
;
}
/* now copy the difference to the
vnc
framebuffer: */
/* now copy the difference to the
rfb
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
;
}
if
(
restored_patch
)
{
redraw_mouse
();
}
/* 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
;
...
...
@@ -936,7 +1544,7 @@ void copy_tile(int tx, int ty) {
/*
* The copy_tile() call in the loop below copies the changed tile into
* the
vnc
framebuffer. Note that copy_tile() sets the tile_region
* the
rfb
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).
*
...
...
@@ -947,8 +1555,9 @@ void copy_tile(int tx, int ty) {
* See copy_tiles_backward_pass() for analogous checking upward and
* left tiles.
*/
void
copy_all_tiles
()
{
int
copy_all_tiles
()
{
int
x
,
y
,
n
,
m
;
int
diffs
=
0
;
for
(
y
=
0
;
y
<
ntiles_y
;
y
++
)
{
for
(
x
=
0
;
x
<
ntiles_x
;
x
++
)
{
...
...
@@ -964,38 +1573,40 @@ void copy_all_tiles() {
*/
continue
;
}
diffs
++
;
/* 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
;
tile_has_diff
[
m
]
=
2
;
}
}
/* 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
;
tile_has_diff
[
m
]
=
2
;
}
}
}
}
return
diffs
;
}
/*
* 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
copy_tiles_backward_pass
()
{
int
x
,
y
,
n
,
m
;
int
diffs
=
0
;
for
(
y
=
ntiles_y
-
1
;
y
>=
0
;
y
--
)
{
for
(
x
=
ntiles_x
-
1
;
x
>=
0
;
x
--
)
{
...
...
@@ -1009,6 +1620,7 @@ void copy_tiles_backward_pass() {
if
(
y
>=
1
&&
!
tile_has_diff
[
m
]
&&
tile_region
[
n
].
top_diff
)
{
if
(
!
tile_tried
[
m
])
{
tile_has_diff
[
m
]
=
2
;
copy_tile
(
x
,
y
-
1
);
}
}
...
...
@@ -1017,11 +1629,18 @@ void copy_tiles_backward_pass() {
if
(
x
>=
1
&&
!
tile_has_diff
[
m
]
&&
tile_region
[
n
].
left_diff
)
{
if
(
!
tile_tried
[
m
])
{
tile_has_diff
[
m
]
=
2
;
copy_tile
(
x
-
1
,
y
);
}
}
}
}
for
(
n
=
0
;
n
<
ntiles
;
n
++
)
{
if
(
tile_has_diff
[
n
])
{
diffs
++
;
}
}
return
diffs
;
}
void
gap_try
(
int
x
,
int
y
,
int
*
run
,
int
*
saw
,
int
along_x
)
{
...
...
@@ -1067,10 +1686,11 @@ void gap_try(int x, int y, int *run, int *saw, int along_x) {
* 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.
*
BTW
, grow_islands() is actually pretty successful at doing this too.
*/
void
fill_tile_gaps
()
{
int
fill_tile_gaps
()
{
int
x
,
y
,
run
,
saw
;
int
n
,
diffs
=
0
;
/* horizontal: */
for
(
y
=
0
;
y
<
ntiles_y
;
y
++
)
{
...
...
@@ -1089,6 +1709,13 @@ void fill_tile_gaps() {
gap_try
(
x
,
y
,
&
run
,
&
saw
,
0
);
}
}
for
(
n
=
0
;
n
<
ntiles
;
n
++
)
{
if
(
tile_has_diff
[
n
])
{
diffs
++
;
}
}
return
diffs
;
}
void
island_try
(
int
x
,
int
y
,
int
u
,
int
v
,
int
*
run
)
{
...
...
@@ -1104,7 +1731,7 @@ void island_try(int x, int y, int u, int v, int *run) {
}
if
(
tile_has_diff
[
n
]
&&
!
tile_has_diff
[
m
])
{
/* found discontinuity */
/* found
a
discontinuity */
if
(
tile_tried
[
m
])
{
return
;
...
...
@@ -1121,8 +1748,9 @@ void island_try(int x, int y, int u, int v, int *run) {
* 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
;
int
grow_islands
()
{
int
x
,
y
,
n
,
run
;
int
diffs
=
0
;
/*
* n.b. the way we scan here should keep an extension going,
...
...
@@ -1143,35 +1771,134 @@ void grow_islands() {
island_try
(
x
,
y
,
x
-
1
,
y
,
&
run
);
}
}
for
(
n
=
0
;
n
<
ntiles
;
n
++
)
{
if
(
tile_has_diff
[
n
])
{
diffs
++
;
}
}
return
diffs
;
}
/*
* copy the whole X screen to the
vnc
framebuffer. For a large enough
* copy the whole X screen to the
rfb
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.
* the info from the X server. Bandwidth to client
and compression time
*
are other issues...
use -fs 1.0 to disable.
*/
void
copy_screen
()
{
int
pixelsize
=
bpp
>>
3
;
char
*
vnc
_fb
;
char
*
rfb
_fb
;
int
i
,
y
,
block_size
,
xi
;
block_size
=
(
dpy_x
*
(
dpy_y
/
fs_factor
)
*
pixelsize
);
vnc
_fb
=
screen
->
frameBuffer
;
rfb
_fb
=
screen
->
frameBuffer
;
y
=
0
;
X_LOCK
;
for
(
i
=
0
;
i
<
fs_factor
;
i
++
)
{
xi
=
XShmGetImage
(
dpy
,
window
,
fullscreen
,
0
,
y
,
AllPlanes
);
memcpy
(
vnc
_fb
,
fullscreen
->
data
,
(
size_t
)
block_size
);
memcpy
(
rfb
_fb
,
fullscreen
->
data
,
(
size_t
)
block_size
);
y
+=
dpy_y
/
fs_factor
;
vnc
_fb
+=
block_size
;
rfb
_fb
+=
block_size
;
}
X_UNLOCK
;
rfbMarkRectAsModified
(
screen
,
0
,
0
,
dpy_x
,
dpy_y
);
}
/*
* Utilities for managing the "naps" to cut down on amount of polling
*/
void
nap_set
(
int
tile_cnt
)
{
if
(
count
==
0
)
{
/* roll up check for all NSCAN scans */
nap_ok
=
0
;
if
(
naptile
&&
nap_diff_count
<
2
*
NSCAN
*
naptile
)
{
/* "2" is a fudge to permit a bit of bg drawing */
nap_ok
=
1
;
}
nap_diff_count
=
0
;
}
if
(
show_mouse
)
{
/* kludge for the up to 4 tiles the mouse patch could occupy */
if
(
tile_cnt
>
4
)
{
last_event
=
time
(
0
);
}
}
else
if
(
tile_cnt
!=
0
)
{
last_event
=
time
(
0
);
}
}
void
nap_sleep
(
int
ms
,
int
split
)
{
int
i
,
input
=
got_user_input
;
/* split it up to improve the wakeup time */
for
(
i
=
0
;
i
<
split
;
i
++
)
{
usleep
(
ms
*
1000
/
split
);
if
(
!
use_threads
&&
i
!=
split
-
1
)
{
rfbProcessEvents
(
screen
,
-
1
);
}
if
(
input
!=
got_user_input
)
{
break
;
}
}
}
void
nap_check
(
int
tile_cnt
)
{
time_t
now
;
nap_diff_count
+=
tile_cnt
;
if
(
!
take_naps
)
{
return
;
}
now
=
time
(
0
);
if
(
screen_blank
>
0
)
{
int
dt
=
(
int
)
(
now
-
last_event
);
int
ms
=
1500
;
/* if no activity, pause here for a second or so. */
if
(
dt
>
screen_blank
)
{
nap_sleep
(
ms
,
8
);
return
;
}
}
if
(
naptile
&&
nap_ok
&&
tile_cnt
<
naptile
)
{
int
ms
=
napfac
*
waitms
;
ms
=
ms
>
napmax
?
napmax
:
ms
;
if
(
now
-
last_input
<=
2
)
{
nap_ok
=
0
;
}
else
{
nap_sleep
(
ms
,
1
);
}
}
}
void
ping_clients
(
int
tile_cnt
)
{
static
time_t
last_send
=
0
;
time_t
now
=
time
(
0
);
if
(
rfbMaxClientWait
<=
3000
)
{
rfbMaxClientWait
=
3000
;
printf
(
"reset rfbMaxClientWait to %d ms.
\n
"
,
rfbMaxClientWait
);
}
if
(
tile_cnt
)
{
last_send
=
now
;
}
else
if
(
now
-
last_send
>
1
)
{
/* Send small heartbeat to client */
rfbMarkRectAsModified
(
screen
,
0
,
0
,
1
,
1
);
last_send
=
now
;
}
}
/*
* Loop over 1-pixel tall horizontal scanlines looking for changes.
* Record the changes in tile_has_diff[]. Scanlines in the loop are
...
...
@@ -1179,28 +1906,45 @@ void copy_screen() {
* starting offset ystart ( < NSCAN ) from scanlines[].
*/
int
scan_display
(
int
ystart
,
int
rescan
)
{
char
*
src
,
*
dst
;
int
pixelsize
=
bpp
>>
3
;
int
x
,
y
,
w
,
n
;
int
tile_count
=
0
;
int
pixelsize
=
bpp
>>
3
;
char
*
src
,
*
dst
;
int
whole_line
=
1
,
nodiffs
;
y
=
ystart
;
while
(
y
<
dpy_y
)
{
/* grab the horizontal scanline from the display: */
X_LOCK
X_LOCK
;
XShmGetImage
(
dpy
,
window
,
scanline
,
0
,
y
,
AllPlanes
);
X_UNLOCK
X_UNLOCK
;
/* for better memory i/o try the whole line at once */
src
=
scanline
->
data
;
dst
=
screen
->
frameBuffer
+
y
*
bytes_per_line
;
nodiffs
=
0
;
if
(
whole_line
&&
!
memcmp
(
dst
,
src
,
bytes_per_line
))
{
/* no changes anywhere in scan line */
nodiffs
=
1
;
if
(
!
rescan
)
{
y
+=
NSCAN
;
continue
;
}
}
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
;
if
(
rescan
)
{
if
(
nodiffs
||
tile_has_diff
[
n
])
{
tile_count
+=
tile_has_diff
[
n
];
x
+=
NSCAN
;
continue
;
}
}
/* set ptrs to correspond to the x offset: */
...
...
@@ -1209,13 +1953,13 @@ int scan_display(int ystart, int rescan) {
+
x
*
pixelsize
;
/* compute the width of data to be compared: */
if
(
x
+
NSCAN
>
dpy_x
)
{
if
(
x
+
NSCAN
>
dpy_x
)
{
w
=
dpy_x
-
x
;
}
else
{
w
=
NSCAN
;
}
if
(
memcmp
(
dst
,
src
,
w
*
pixelsize
)
)
{
if
(
memcmp
(
dst
,
src
,
w
*
pixelsize
))
{
/* found a difference, record it: */
tile_has_diff
[
n
]
=
1
;
tile_count
++
;
...
...
@@ -1231,7 +1975,7 @@ int scan_display(int ystart, int rescan) {
* toplevel for the scanning, rescanning, and applying the heuristics.
*/
void
scan_for_updates
()
{
int
i
,
tile_count
;
int
i
,
tile_count
,
tile_diffs
;
double
frac1
=
0
.
1
;
/* tweak parameter to try a 2nd scan_display() */
for
(
i
=
0
;
i
<
ntiles
;
i
++
)
{
...
...
@@ -1247,9 +1991,25 @@ void scan_for_updates() {
count
++
;
count
%=
NSCAN
;
if
(
count
%
(
NSCAN
/
4
)
==
0
)
{
if
(
subwin
)
{
set_offset
();
/* follow the subwindow */
}
if
(
indexed_colour
)
{
/* check for changed colormap */
set_colormap
();
}
}
if
(
show_mouse
&&
!
use_threads
)
{
/* single-thread is safe to do it here for all scanning */
restore_mouse_patch
();
}
/* scan with the initial y to the jitter value from scanlines: */
tile_count
=
scan_display
(
scanlines
[
count
],
0
);
nap_set
(
tile_count
);
if
(
fs_factor
&&
frac1
>=
fs_frac
)
{
/* make frac1 < fs_frac if fullscreen updates are enabled */
frac1
=
fs_frac
/
2
.
0
;
...
...
@@ -1274,35 +2034,45 @@ void scan_for_updates() {
/*
* 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.
* where m is number of tiles, r1 is the copy_tile()
* time, 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,
* compression time etc...
*
* 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.
* Use -fs 1.0 to disable on slow links.
*/
if
(
fs_factor
&&
tile_count
>
fs_frac
*
ntiles
)
{
copy_screen
();
if
(
show_mouse
)
{
if
(
!
use_threads
)
{
redraw_mouse
();
}
update_mouse
();
}
nap_check
(
tile_count
);
return
;
}
}
/* copy all tiles with differences from display to
vnc
framebuffer: */
copy_all_tiles
();
/* copy all tiles with differences from display to
rfb
framebuffer: */
tile_diffs
=
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
();
tile_diffs
=
copy_tiles_backward_pass
();
if
(
grow_fill
)
{
grow_islands
();
if
(
grow_fill
&&
tile_diffs
>
4
)
{
tile_diffs
=
grow_islands
();
}
if
(
gaps_fill
)
{
fill_tile_gaps
();
if
(
gaps_fill
&&
tile_diffs
>
4
)
{
tile_diffs
=
fill_tile_gaps
();
}
if
(
use_hints
)
{
...
...
@@ -1310,15 +2080,26 @@ void scan_for_updates() {
}
else
{
tile_updates
();
/* send each tile change individually */
}
/* Work around threaded rfbProcessClientMessage() calls timeouts */
if
(
use_threads
)
{
ping_clients
(
tile_diffs
);
}
/* Handle the remote mouse pointer */
if
(
show_mouse
)
{
if
(
!
use_threads
)
{
redraw_mouse
();
}
update_mouse
();
}
nap_check
(
tile_diffs
);
}
void
watch_loop
(
void
)
{
int
cnt
=
0
;
#if !defined(HAVE_PTHREADS)
use_threads
=
0
;
#endif
if
(
use_threads
)
{
rfbRunEventLoop
(
screen
,
-
1
,
TRUE
);
}
...
...
@@ -1337,7 +2118,7 @@ void watch_loop(void) {
}
if
(
shut_down
)
{
clean_up_exit
();
clean_up_exit
(
0
);
}
if
(
!
screen
->
rfbClientHead
)
{
/* waiting for a client */
...
...
@@ -1346,6 +2127,7 @@ void watch_loop(void) {
}
rfbUndrawCursor
(
screen
);
scan_for_updates
();
usleep
(
waitms
*
1000
);
...
...
@@ -1356,92 +2138,188 @@ void watch_loop(void) {
void
print_help
()
{
char
help
[]
=
"
\n
"
"x11vnc options:
\n
"
"
\n
"
"-display disp X11 server display to connect to, the X server process
\n
"
" must be running on same machine and support MIT-SHM.
\n
"
"-id windowid show the window corresponding to <windowid> not the
\n
"
" entire display. Warning: bugs! new toplevels missed!...
\n
"
"-flashcmap in 8bpp indexed color, let the installed colormap flash
\n
"
" as the pointer moves from window to window (slow).
\n
"
"
\n
"
"-viewonly clients can only watch (default %s).
\n
"
"-shared VNC display is shared (default %s).
\n
"
"-many keep listening for more connections rather than exiting
\n
"
" as soon as the first clients disconnect.
\n
"
"
\n
"
"-modtweak handle AltGr/Shift modifiers for differing languages
\n
"
" between client and host (default %s).
\n
"
"-nomodtweak send the keysym directly to the X server.
\n
"
"
\n
"
"-nocursor do not have the viewer show a local cursor.
\n
"
"-mouse draw a 2nd cursor at the current X pointer position.
\n
"
"-mouseX as -mouse, but also draw an X on root background.
\n
"
"-X shorthand for -mouseX -nocursor.
\n
"
"
\n
"
"-defer time time in ms to wait for updates before sending to
\n
"
" client [rfbDeferUpdateTime] (default %d)
\n
"
" client [rfbDeferUpdateTime] (default %d)
.
\n
"
"-wait time time in ms to pause between screen polls. used
\n
"
" to cut down on load (default %d)
\n
"
" to cut down on load (default %d).
\n
"
"-nap monitor activity and if low take longer naps between
\n
"
" polls to really cut down load when idle (default %s).
\n
"
#ifdef HAVE_LIBPTHREAD
"-threads whether or not to use the threaded libvncserver
\n
"
"-nothreads algorithm [rfbRunEventLoop] (default %s).
\n
"
#endif
"
\n
"
"-fs f if the fraction of changed tiles in a poll is greater
\n
"
" than f, the whole screen is updated (default %.2f).
\n
"
"-gaps n heuristic to fill in gaps in rows or cols of n or less
\n
"
" tiles. used to improve text paging (default %d).
\n
"
"-grow n heuristic to grow islands of changed tiles n or wider
\n
"
" by checking the tile near the boundary (default %d).
\n
"
"-fs f if the fraction of changed tiles in a poll is greater
\n
"
" than f, the whole screen is updated (default %.2f)
\n
"
"-fuzz n tolerance in pixels to mark a tiles edges as changed.
\n
"
"-fuzz n tolerance in pixels to mark a tiles edges as changed
\n
"
" (default %d).
\n
"
"-hints use krfb/x0rfbserver hints (glue changed adjacent
\n
"
" horizontal tiles into one big rectangle) (default %s).
\n
"
"-nohints do not use hints; send each tile separately.
\n
"
"
\n
"
"-modtweak handle AltGr/Shift modifiers for differing languages
\n
"
" between client and host (default %d).
\n
"
"-nomodtweak send the keysym directly to the X server.
\n
"
"-threads use threaded algorithm [rfbRunEventLoop] if compiled
\n
"
" with threads (default %s).
\n
"
"-nothreads do not use [rfbRunEventLoop].
\n
"
"-viewonly clients can only watch (default %s).
\n
"
"-shared VNC display is shared (default %s)
\n
"
"%s
\n
"
"
\n
"
"These options are passed to libvncserver:
\n
"
"
\n
"
;
fprintf
(
stderr
,
help
,
defer_update
,
waitms
,
gaps_fill
,
grow_fill
,
fs_frac
,
tile_fuzz
,
use_hints
?
"on"
:
"off"
,
use_modifier_tweak
?
"on"
:
"off"
,
use_threads
?
"on"
:
"off"
,
view_only
?
"on"
:
"off"
,
shared
?
"on"
:
"off"
);
fprintf
(
stderr
,
help
,
view_only
?
"on"
:
"off"
,
shared
?
"on"
:
"off"
,
use_modifier_tweak
?
"on"
:
"off"
,
defer_update
,
waitms
,
take_naps
?
"on"
:
"off"
,
#ifdef HAVE_LIBPTHREAD
use_threads
?
"on"
:
"off"
,
#endif
fs_frac
,
gaps_fill
,
grow_fill
,
tile_fuzz
,
use_hints
?
"on"
:
"off"
,
""
);
rfbUsage
();
exit
(
1
);
}
/*
* choose a desktop name
*/
#define MAXN 256
char
*
choose_title
(
char
*
display
)
{
static
char
title
[(
MAXN
+
10
)];
strcpy
(
title
,
"x11vnc"
);
if
(
display
==
NULL
)
{
display
=
getenv
(
"DISPLAY"
);
}
if
(
display
==
NULL
)
{
return
title
;
}
title
[
0
]
=
'\0'
;
if
(
display
[
0
]
==
':'
)
{
char
host
[
MAXN
];
if
(
gethostname
(
host
,
MAXN
)
==
0
)
{
strncpy
(
title
,
host
,
MAXN
-
strlen
(
title
));
}
}
strncat
(
title
,
display
,
MAXN
-
strlen
(
title
));
if
(
subwin
)
{
char
*
name
;
if
(
XFetchName
(
dpy
,
window
,
&
name
))
{
strncat
(
title
,
" "
,
MAXN
-
strlen
(
title
));
strncat
(
title
,
name
,
MAXN
-
strlen
(
title
));
}
}
return
title
;
}
int
main
(
int
argc
,
char
**
argv
)
{
XImage
*
fb
;
int
i
,
ev
,
er
,
maj
,
min
;
char
*
use_dpy
=
NULL
;
int
dt
=
0
;
/* 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
],
"-id"
))
{
/* expt to just show one window. XXX not finished. */
if
(
sscanf
(
argv
[
++
i
],
"0x%x"
,
&
subwin
)
!=
1
)
{
if
(
sscanf
(
argv
[
i
],
"%d"
,
&
subwin
)
!=
1
)
{
printf
(
"bad -id arg: %s
\n
"
,
argv
[
i
]);
exit
(
1
);
}
}
}
else
if
(
!
strcmp
(
argv
[
i
],
"-flashcmap"
))
{
flash_cmap
=
1
;
}
else
if
(
!
strcmp
(
argv
[
i
],
"-viewonly"
))
{
view_only
=
1
;
}
else
if
(
!
strcmp
(
argv
[
i
],
"-shared"
))
{
shared
=
1
;
}
else
if
(
!
strcmp
(
argv
[
i
],
"-many"
))
{
connect_once
=
0
;
}
else
if
(
!
strcmp
(
argv
[
i
],
"-modtweak"
))
{
use_modifier_tweak
=
1
;
}
else
if
(
!
strcmp
(
argv
[
i
],
"-nomodtweak"
))
{
use_modifier_tweak
=
0
;
}
else
if
(
!
strcmp
(
argv
[
i
],
"-nocursor"
))
{
local_cursor
=
0
;
}
else
if
(
!
strcmp
(
argv
[
i
],
"-mouse"
))
{
show_mouse
=
1
;
}
else
if
(
!
strcmp
(
argv
[
i
],
"-mouseX"
))
{
show_mouse
=
1
;
show_root_cursor
=
1
;
}
else
if
(
!
strcmp
(
argv
[
i
],
"-X"
))
{
show_mouse
=
1
;
show_root_cursor
=
1
;
local_cursor
=
0
;
}
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
],
"-nap"
))
{
take_naps
=
1
;
#ifdef HAVE_LIBPTHREAD
}
else
if
(
!
strcmp
(
argv
[
i
],
"-threads"
))
{
use_threads
=
1
;
}
else
if
(
!
strcmp
(
argv
[
i
],
"-nothreads"
))
{
use_threads
=
0
;
#endif
}
else
if
(
!
strcmp
(
argv
[
i
],
"-fs"
))
{
fs_frac
=
atof
(
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
],
"-modtweak"
))
{
use_modifier_tweak
=
1
;
}
else
if
(
!
strcmp
(
argv
[
i
],
"-nomodtweak"
))
{
use_modifier_tweak
=
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
{
if
(
!
strcmp
(
argv
[
i
],
"-desktop"
))
{
dt
=
1
;
}
/* otherwise copy it for use below. */
printf
(
"passing arg to libvncserver: %s
\n
"
,
argv
[
i
]);
if
(
argc2
<
100
)
{
...
...
@@ -1449,22 +2327,31 @@ int main(int argc, char** argv) {
}
}
}
if
(
tile_fuzz
<
1
)
{
tile_fuzz
=
1
;
}
if
(
waitms
<
0
)
{
waitms
=
0
;
}
printf
(
"viewonly: %d
\n
"
,
view_only
);
printf
(
"shared: %d
\n
"
,
shared
);
printf
(
"conn_once: %d
\n
"
,
connect_once
);
printf
(
"mod_tweak: %d
\n
"
,
use_modifier_tweak
);
printf
(
"loc_curs: %d
\n
"
,
local_cursor
);
printf
(
"mouse: %d
\n
"
,
show_mouse
);
printf
(
"root_curs: %d
\n
"
,
show_root_cursor
);
printf
(
"defer: %d
\n
"
,
defer_update
);
printf
(
"waitms: %d
\n
"
,
waitms
);
printf
(
"tile_fuzz: %d
\n
"
,
tile_fuzz
);
printf
(
"take_naps: %d
\n
"
,
take_naps
);
printf
(
"threads: %d
\n
"
,
use_threads
);
printf
(
"fs_frac: %.2f
\n
"
,
fs_frac
);
printf
(
"gaps_fill: %d
\n
"
,
gaps_fill
);
printf
(
"grow_fill: %d
\n
"
,
grow_fill
);
printf
(
"
fs_frac: %.2f
\n
"
,
fs_frac
);
printf
(
"
tile_fuzz: %d
\n
"
,
tile_fuzz
);
printf
(
"use_hints: %d
\n
"
,
use_hints
);
printf
(
"viewonly: %d
\n
"
,
view_only
);
printf
(
"shared: %d
\n
"
,
shared
);
X_INIT
;
if
(
use_dpy
)
{
dpy
=
XOpenDisplay
(
use_dpy
);
}
else
if
(
(
use_dpy
=
getenv
(
"DISPLAY"
))
)
{
...
...
@@ -1472,6 +2359,7 @@ int main(int argc, char** argv) {
}
else
{
dpy
=
XOpenDisplay
(
""
);
}
if
(
!
dpy
)
{
printf
(
"XOpenDisplay failed (%s)
\n
"
,
use_dpy
);
exit
(
1
);
...
...
@@ -1499,10 +2387,36 @@ int main(int argc, char** argv) {
XTestGrabControl
(
dpy
,
True
);
scr
=
DefaultScreen
(
dpy
);
window
=
RootWindow
(
dpy
,
scr
);
rootwin
=
RootWindow
(
dpy
,
scr
);
if
(
!
subwin
)
{
window
=
rootwin
;
dpy_x
=
DisplayWidth
(
dpy
,
scr
);
dpy_y
=
DisplayHeight
(
dpy
,
scr
);
off_x
=
0
;
off_y
=
0
;
visual
=
DefaultVisual
(
dpy
,
scr
);
}
else
{
/* experiment to share just one window */
XWindowAttributes
attr
;
window
=
(
Window
)
subwin
;
if
(
!
XGetWindowAttributes
(
dpy
,
window
,
&
attr
)
)
{
printf
(
"bad window: 0x%x
\n
"
,
window
);
exit
(
1
);
}
dpy_x
=
attr
.
width
;
dpy_y
=
attr
.
height
;
visual
=
attr
.
visual
;
/* show_mouse has some segv crashes as well */
if
(
show_root_cursor
)
{
show_root_cursor
=
0
;
printf
(
"disabling root cursor drawing for subwindow
\n
"
);
}
dpy_x
=
DisplayWidth
(
dpy
,
scr
);
dpy_y
=
DisplayHeight
(
dpy
,
scr
);
set_offset
(
);
}
fb
=
XGetImage
(
dpy
,
window
,
0
,
0
,
dpy_x
,
dpy_y
,
AllPlanes
,
ZPixmap
);
printf
(
"Read initial data from display into framebuffer.
\n
"
);
...
...
@@ -1511,8 +2425,14 @@ int main(int argc, char** argv) {
printf
(
"warning: 24 bpp may have poor performance.
\n
"
);
}
if
(
!
dt
)
{
static
char
str
[]
=
"-desktop"
;
argv2
[
argc2
++
]
=
str
;
argv2
[
argc2
++
]
=
choose_title
(
use_dpy
);
}
/*
* n.b. we do not have to X_LOCK X11 calls until watch_loop()
* n.b. we do not have to X_LOCK
any
X11 calls until watch_loop()
* is called since we are single-threaded until then.
*/
...
...
@@ -1522,6 +2442,8 @@ int main(int argc, char** argv) {
initialize_shm
();
set_signals
();
if
(
use_modifier_tweak
)
{
initialize_keycodes
();
}
...
...
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