updated to new automake and refactored server stuff. the server

now speaks to the primary screen and secondary screens almost
everywhere the same way through an IClient interface;  only
special primary screen calls are accessed through a different
interface, the CPrimaryClient interface.  this simplifies the
server since it no longer needs to test whether the active screen
is the primary or a secondary in most cases.

the server no longer speaks directly to the primary screen;  all
that goes through the CPrimaryClient, which often just forwards
the call.  the primary screen no longer speaks directly to the
server either, again going through the CPrimaryClient via a
IPrimaryReceiver interface.

CServerProtocol classes have been replaced by CClientProxy
classes which are very similar.  the name makes more sense
though.
This commit is contained in:
crs 2002-07-09 21:22:31 +00:00
parent bdfdc8e816
commit 64232c7854
28 changed files with 2415 additions and 1390 deletions

411
config/depcomp Executable file
View File

@ -0,0 +1,411 @@
#! /bin/sh
# depcomp - compile a program generating dependencies as side-effects
# Copyright 1999, 2000 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
# 02111-1307, USA.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
if test -z "$depmode" || test -z "$source" || test -z "$object"; then
echo "depcomp: Variables source, object and depmode must be set" 1>&2
exit 1
fi
# `libtool' can also be set to `yes' or `no'.
depfile=${depfile-`echo "$object" | sed 's,\([^/]*\)$,.deps/\1,;s/\.\([^.]*\)$/.P\1/'`}
tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
rm -f "$tmpdepfile"
# Some modes work just like other modes, but use different flags. We
# parameterize here, but still list the modes in the big case below,
# to make depend.m4 easier to write. Note that we *cannot* use a case
# here, because this file can only contain one case statement.
if test "$depmode" = hp; then
# HP compiler uses -M and no extra arg.
gccflag=-M
depmode=gcc
fi
if test "$depmode" = dashXmstdout; then
# This is just like dashmstdout with a different argument.
dashmflag=-xM
depmode=dashmstdout
fi
case "$depmode" in
gcc3)
## gcc 3 implements dependency tracking that does exactly what
## we want. Yay! Note: for some reason libtool 1.4 doesn't like
## it if -MD -MP comes after the -MF stuff. Hmm.
"$@" -MT "$object" -MD -MP -MF "$tmpdepfile"
stat=$?
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile"
exit $stat
fi
mv "$tmpdepfile" "$depfile"
;;
gcc)
## There are various ways to get dependency output from gcc. Here's
## why we pick this rather obscure method:
## - Don't want to use -MD because we'd like the dependencies to end
## up in a subdir. Having to rename by hand is ugly.
## (We might end up doing this anyway to support other compilers.)
## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
## -MM, not -M (despite what the docs say).
## - Using -M directly means running the compiler twice (even worse
## than renaming).
if test -z "$gccflag"; then
gccflag=-MD,
fi
"$@" -Wp,"$gccflag$tmpdepfile"
stat=$?
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
echo "$object : \\" > "$depfile"
alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
## The second -e expression handles DOS-style file names with drive letters.
sed -e 's/^[^:]*: / /' \
-e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
## This next piece of magic avoids the `deleted header file' problem.
## The problem is that when a header file which appears in a .P file
## is deleted, the dependency causes make to die (because there is
## typically no way to rebuild the header). We avoid this by adding
## dummy dependencies for each header file. Too bad gcc doesn't do
## this for us directly.
tr ' ' '
' < "$tmpdepfile" |
## Some versions of gcc put a space before the `:'. On the theory
## that the space means something, we add a space to the output as
## well.
## Some versions of the HPUX 10.20 sed can't process this invocation
## correctly. Breaking it into two sed invocations is a workaround.
sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
hp)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
sgi)
if test "$libtool" = yes; then
"$@" "-Wp,-MDupdate,$tmpdepfile"
else
"$@" -MDupdate "$tmpdepfile"
fi
stat=$?
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
echo "$object : \\" > "$depfile"
# Clip off the initial element (the dependent). Don't try to be
# clever and replace this with sed code, as IRIX sed won't handle
# lines with more than a fixed number of characters (4096 in
# IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
# the IRIX cc adds comments like `#:fec' to the end of the
# dependency line.
tr ' ' '
' < "$tmpdepfile" \
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \
tr '
' ' ' >> $depfile
echo >> $depfile
# The second pass generates a dummy entry for each header file.
tr ' ' '
' < "$tmpdepfile" \
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
>> $depfile
else
# The sourcefile does not contain any dependencies, so just
# store a dummy comment line, to avoid errors with the Makefile
# "include basename.Plo" scheme.
echo "#dummy" > "$depfile"
fi
rm -f "$tmpdepfile"
;;
aix)
# The C for AIX Compiler uses -M and outputs the dependencies
# in a .u file. This file always lives in the current directory.
# Also, the AIX compiler puts `$object:' at the start of each line;
# $object doesn't have directory information.
stripped=`echo "$object" | sed -e 's,^.*/,,' -e 's/\(.*\)\..*$/\1/'`
tmpdepfile="$stripped.u"
outname="$stripped.o"
if test "$libtool" = yes; then
"$@" -Wc,-M
else
"$@" -M
fi
stat=$?
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile"
exit $stat
fi
if test -f "$tmpdepfile"; then
# Each line is of the form `foo.o: dependent.h'.
# Do two passes, one to just change these to
# `$object: dependent.h' and one to simply `dependent.h:'.
sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile"
sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile"
else
# The sourcefile does not contain any dependencies, so just
# store a dummy comment line, to avoid errors with the Makefile
# "include basename.Plo" scheme.
echo "#dummy" > "$depfile"
fi
rm -f "$tmpdepfile"
;;
tru64)
# The Tru64 AIX compiler uses -MD to generate dependencies as a side
# effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'.
# At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
# dependencies in `foo.d' instead, so we check for that too.
# Subdirectories are respected.
tmpdepfile1="$object.d"
tmpdepfile2=`echo "$object" | sed -e 's/.o$/.d/'`
if test "$libtool" = yes; then
"$@" -Wc,-MD
else
"$@" -MD
fi
stat=$?
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile1" "$tmpdepfile2"
exit $stat
fi
if test -f "$tmpdepfile1"; then
tmpdepfile="$tmpdepfile1"
else
tmpdepfile="$tmpdepfile2"
fi
if test -f "$tmpdepfile"; then
sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
# That's a space and a tab in the [].
sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
else
echo "#dummy" > "$depfile"
fi
rm -f "$tmpdepfile"
;;
#nosideeffect)
# This comment above is used by automake to tell side-effect
# dependency tracking mechanisms from slower ones.
dashmstdout)
# Important note: in order to support this mode, a compiler *must*
# always write the proprocessed file to stdout, regardless of -o,
# because we must use -o when running libtool.
test -z "$dashmflag" && dashmflag=-M
( IFS=" "
case " $* " in
*" --mode=compile "*) # this is libtool, let us make it quiet
for arg
do # cycle over the arguments
case "$arg" in
"--mode=compile")
# insert --quiet before "--mode=compile"
set fnord "$@" --quiet
shift # fnord
;;
esac
set fnord "$@" "$arg"
shift # fnord
shift # "$arg"
done
;;
esac
"$@" $dashmflag | sed 's:^[^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile"
) &
proc=$!
"$@"
stat=$?
wait "$proc"
if test "$stat" != 0; then exit $stat; fi
rm -f "$depfile"
cat < "$tmpdepfile" > "$depfile"
tr ' ' '
' < "$tmpdepfile" | \
## Some versions of the HPUX 10.20 sed can't process this invocation
## correctly. Breaking it into two sed invocations is a workaround.
sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
dashXmstdout)
# This case only exists to satisfy depend.m4. It is never actually
# run, as this mode is specially recognized in the preamble.
exit 1
;;
makedepend)
# X makedepend
(
shift
cleared=no
for arg in "$@"; do
case $cleared in no)
set ""; shift
cleared=yes
esac
case "$arg" in
-D*|-I*)
set fnord "$@" "$arg"; shift;;
-*)
;;
*)
set fnord "$@" "$arg"; shift;;
esac
done
obj_suffix="`echo $object | sed 's/^.*\././'`"
touch "$tmpdepfile"
${MAKEDEPEND-makedepend} 2>/dev/null -o"$obj_suffix" -f"$tmpdepfile" "$@"
) &
proc=$!
"$@"
stat=$?
wait "$proc"
if test "$stat" != 0; then exit $stat; fi
rm -f "$depfile"
cat < "$tmpdepfile" > "$depfile"
tail +3 "$tmpdepfile" | tr ' ' '
' | \
## Some versions of the HPUX 10.20 sed can't process this invocation
## correctly. Breaking it into two sed invocations is a workaround.
sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile" "$tmpdepfile".bak
;;
cpp)
# Important note: in order to support this mode, a compiler *must*
# always write the proprocessed file to stdout, regardless of -o,
# because we must use -o when running libtool.
( IFS=" "
case " $* " in
*" --mode=compile "*)
for arg
do # cycle over the arguments
case $arg in
"--mode=compile")
# insert --quiet before "--mode=compile"
set fnord "$@" --quiet
shift # fnord
;;
esac
set fnord "$@" "$arg"
shift # fnord
shift # "$arg"
done
;;
esac
"$@" -E |
sed -n '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' |
sed '$ s: \\$::' > "$tmpdepfile"
) &
proc=$!
"$@"
stat=$?
wait "$proc"
if test "$stat" != 0; then exit $stat; fi
rm -f "$depfile"
echo "$object : \\" > "$depfile"
cat < "$tmpdepfile" >> "$depfile"
sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
msvisualcpp)
# Important note: in order to support this mode, a compiler *must*
# always write the proprocessed file to stdout, regardless of -o,
# because we must use -o when running libtool.
( IFS=" "
case " $* " in
*" --mode=compile "*)
for arg
do # cycle over the arguments
case $arg in
"--mode=compile")
# insert --quiet before "--mode=compile"
set fnord "$@" --quiet
shift # fnord
;;
esac
set fnord "$@" "$arg"
shift # fnord
shift # "$arg"
done
;;
esac
"$@" -E |
sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile"
) &
proc=$!
"$@"
stat=$?
wait "$proc"
if test "$stat" != 0; then exit $stat; fi
rm -f "$depfile"
echo "$object : \\" > "$depfile"
. "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile"
echo " " >> "$depfile"
. "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile"
rm -f "$tmpdepfile"
;;
none)
exec "$@"
;;
*)
echo "Unknown depmode $depmode" 1>&2
exit 1
;;
esac
exit 0

View File

@ -1,7 +1,7 @@
#! /bin/sh
# Common stub for a few missing GNU programs while installing.
# Copyright (C) 1996, 1997 Free Software Foundation, Inc.
# Franc,ois Pinard <pinard@iro.umontreal.ca>, 1996.
# Copyright 1996, 1997, 1999, 2000 Free Software Foundation, Inc.
# Originally by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -18,11 +18,37 @@
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
# 02111-1307, USA.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
if test $# -eq 0; then
echo 1>&2 "Try \`$0 --help' for more information"
exit 1
fi
run=:
# In the cases where this matters, `missing' is being run in the
# srcdir already.
if test -f configure.ac; then
configure_ac=configure.ac
else
configure_ac=configure.in
fi
case "$1" in
--run)
# Try to run requested program, and just exit if it succeeds.
run=
shift
"$@" && exit 0
;;
esac
# If it does not exist, or fails to run (possibly an outdated version),
# try to emulate it.
case "$1" in
-h|--h|--he|--hel|--help)
@ -35,6 +61,7 @@ error status if there is no known handling for PROGRAM.
Options:
-h, --help display this help and exit
-v, --version output version information and exit
--run try to run the given command, and emulate it if it fails
Supported PROGRAM values:
aclocal touch file \`aclocal.m4'
@ -43,13 +70,15 @@ Supported PROGRAM values:
automake touch all \`Makefile.in' files
bison create \`y.tab.[ch]', if possible, from existing .[ch]
flex create \`lex.yy.c', if possible, from existing .c
help2man touch the output file
lex create \`lex.yy.c', if possible, from existing .c
makeinfo touch the output file
tar try tar, gnutar, gtar, then tar without non-portable flags
yacc create \`y.tab.[ch]', if possible, from existing .[ch]"
;;
-v|--v|--ve|--ver|--vers|--versi|--versio|--version)
echo "missing - GNU libit 0.0"
echo "missing 0.3 - GNU automake"
;;
-*)
@ -61,7 +90,7 @@ Supported PROGRAM values:
aclocal)
echo 1>&2 "\
WARNING: \`$1' is missing on your system. You should only need it if
you modified \`acinclude.m4' or \`configure.in'. You might want
you modified \`acinclude.m4' or \`${configure_ac}'. You might want
to install the \`Automake' and \`Perl' packages. Grab them from
any GNU archive site."
touch aclocal.m4
@ -70,7 +99,7 @@ WARNING: \`$1' is missing on your system. You should only need it if
autoconf)
echo 1>&2 "\
WARNING: \`$1' is missing on your system. You should only need it if
you modified \`configure.in'. You might want to install the
you modified \`${configure_ac}'. You might want to install the
\`Autoconf' and \`GNU m4' packages. Grab them from any GNU
archive site."
touch configure
@ -79,10 +108,10 @@ WARNING: \`$1' is missing on your system. You should only need it if
autoheader)
echo 1>&2 "\
WARNING: \`$1' is missing on your system. You should only need it if
you modified \`acconfig.h' or \`configure.in'. You might want
you modified \`acconfig.h' or \`${configure_ac}'. You might want
to install the \`Autoconf' and \`GNU m4' packages. Grab them
from any GNU archive site."
files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' configure.in`
files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}`
test -z "$files" && files="config.h"
touch_files=
for f in $files; do
@ -98,7 +127,7 @@ WARNING: \`$1' is missing on your system. You should only need it if
automake)
echo 1>&2 "\
WARNING: \`$1' is missing on your system. You should only need it if
you modified \`Makefile.am', \`acinclude.m4' or \`configure.in'.
you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'.
You might want to install the \`Automake' and \`Perl' packages.
Grab them from any GNU archive site."
find . -type f -name Makefile.am -print |
@ -159,7 +188,32 @@ WARNING: \`$1' is missing on your system. You should only need it if
fi
;;
help2man)
echo 1>&2 "\
WARNING: \`$1' is missing on your system. You should only need it if
you modified a dependency of a manual page. You may need the
\`Help2man' package in order for those modifications to take
effect. You can get \`Help2man' from any GNU archive site."
file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
if test -z "$file"; then
file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'`
fi
if [ -f "$file" ]; then
touch $file
else
test -z "$file" || exec >$file
echo ".ab help2man is required to generate this page"
exit 1
fi
;;
makeinfo)
if test -z "$run" && (makeinfo --version) > /dev/null 2>&1; then
# We have makeinfo, but it failed.
exit 1
fi
echo 1>&2 "\
WARNING: \`$1' is missing on your system. You should only need it if
you modified a \`.texi' or \`.texinfo' file, or any other file
@ -175,6 +229,45 @@ WARNING: \`$1' is missing on your system. You should only need it if
touch $file
;;
tar)
shift
if test -n "$run"; then
echo 1>&2 "ERROR: \`tar' requires --run"
exit 1
fi
# We have already tried tar in the generic part.
# Look for gnutar/gtar before invocation to avoid ugly error
# messages.
if (gnutar --version > /dev/null 2>&1); then
gnutar ${1+"$@"} && exit 0
fi
if (gtar --version > /dev/null 2>&1); then
gtar ${1+"$@"} && exit 0
fi
firstarg="$1"
if shift; then
case "$firstarg" in
*o*)
firstarg=`echo "$firstarg" | sed s/o//`
tar "$firstarg" ${1+"$@"} && exit 0
;;
esac
case "$firstarg" in
*h*)
firstarg=`echo "$firstarg" | sed s/h//`
tar "$firstarg" ${1+"$@"} && exit 0
;;
esac
fi
echo 1>&2 "\
WARNING: I can't seem to be able to run \`tar' with the given arguments.
You may want to install GNU tar or Free paxutils, or check the
command line arguments."
exit 1
;;
*)
echo 1>&2 "\
WARNING: \`$1' is needed, and you do not seem to have it handy on your

View File

@ -127,8 +127,7 @@ CThread::getResult() const
void*
CThread::getUserData()
{
CThreadPtr currentRep(CThreadRep::getCurrentThreadRep());
return currentRep->getUserData();
return m_rep->getUserData();
}
bool

View File

@ -88,15 +88,14 @@ public:
// return a thread object representing the calling thread
static CThread getCurrentThread();
// get the user data passed to the constructor for the current
// thread.
static void* getUserData();
// testCancel() does nothing but is a cancellation point. call
// this to make a function itself a cancellation point.
// (cancellation point)
static void testCancel();
// get the user data passed to the constructor for this thread.
void* getUserData();
// waits for the thread to terminate (by exit() or cancel() or
// by returning from the thread job). returns immediately if
// the thread has already terminated. returns immediately with

109
notes
View File

@ -7,16 +7,27 @@ hangup if invalid
query info -->
<-- info (size)
---
nedit doesn't seem to be playing nice with the motif clipboard lock
it's not releasing it
may need to learn more about how the motif clipboard lock works
not sure if this a new problem with synergy or a problem with new nedit
---
enable heartbeat disconnection or remove heartbeat sending in client
should either ship with it fully enabled or fully disabled
possibly make it part of startup negotiation
---
sometimes jumping too far into secondary screen
probably bogus delta (adding in center pixel coords into delta?)
this is with an X primary and secondary
don't know which matters but probably X primary
getting a stuttering when leaving win32 server screen
---
merge platform dependent code into platform independent where possible
also try to simplify where possible
---
IServer and IPrimaryReceiver are really similar
can we merge them into one?
---
use automake
@ -33,20 +44,59 @@ HTTP stuff
handy for debugging at least
---
make generic input devices?
replace mouse and keyboard with button and valuator devices?
could fairly easily add new devices then
valuators would have to come in groups that change together
mouse position would be two ganged valuators
key events are not simply button presses though
they have a non-boolean character, shift state, and repeat count
maybe another device type: {data, state, repeat}
negotiation:
use a generic negotiation message (name/value pair) or specific
messages (name/values)? later allows more parsing to be done by
CProtocolUtil but how can we skip unknown messages? would have
to have a method on CInputPacketStream to discard to end of
message and we'd need to know the stream is a CInputPacketStream.
must handle on-the-fly addition/removal of devices
USB allows hotplugging and we should support, say, an added joystick
how does negotiation proceed?
could have sequence of queries and replies:
server -> client -> server ... end
client -> server -> client ... end
or a sequence of messages:
server -> client ... end
client -> server ... end
probably go with latter because it's more efficient but make it
3-way:
client -> server ... end
server -> client ... end
client -> server ... end
first messages from client must be version and name. the server
can create the appropriate protocol object right away then.
must have device negotiation
at very least it negotiates mouse/keyboard at start
example: clipboard formats:
# CNEG = negotiation command CNEG%s%s
# CNGE = end of negotiation command
# cbfa = clipboard, format, add (permitted format)
# cbia = clipboard, id, add (clipboard with id exists)
client -> server: CNEG "vers" "1.0"
client -> server: CNEG "name" "foobar"
client -> server: CNGE
server -> client: CNEG "cbfa" "text/plain/LF"
server -> client: CNEG "cbfa" "image/BMP"
server -> client: CNGE
client -> server: CNEG "cbia" "0"
client -> server: CNGE
server should just ask CProtocol (renamed from CServerProtocol) to
return a protocol. CProtocol should do negotiation, create the
appropriate protocol object, finish negotiation, and return the
new protocol object. unless connection is registered with server,
though, we can't save any screen info. perhaps CProtocol should
also return a screen info object or that should be part of the
protocol object (currently the protocol is part of the screen info).
if screen info is available to CProtocol then it should finish with
requesting the screen info, waiting for and then handling the reply.
the server can then just ask CProtocol for the protocol object then
add it to the connections.
maybe call the protocol types CClientProxy since that's how the
server uses it: as a stand-in for the client object. the interface
should closely reflect the CClient interface. do the reverse for
a server proxy for the client. maybe even have interface classes
for the client and server methods.
---
should add clipboard data type format negotiation
@ -72,6 +122,28 @@ allows compatibility with versions that are identical except for
the support clipboard formats, obviating bumping up the protocol
version number.
maybe config file can list format shared libraries to load. user
can then pick formats to support. but why would you ever want
fewer formats?
should the major burden of translation be on client or server?
probably client since it knows the formats preferred by the
platform and may be able to use platform utilities to convert.
server would then just support formats that minimize loss of
information.
desired formats to support:
text (LF)
text with character set
unicode (LF)
rich text (or some kind of formatting)
bitmap (BMP, PNG?)
sound (WAV)
note that formats should be added to the win32 clipboard in the
order of most descriptive to least because they're kept in order
and apps will generally use the first suitable match.
---
hot keys
should have keyboard shortcuts to jump to screens
@ -130,6 +202,7 @@ xscreensaver won't start if pointer on secondary screen
unless using MIT or SGI screen saver extensions
otherwise it cannot know when to stop the screen saver
cos it can't grab mouse and keyboard
---
all screensavers hidden when showing win32 screensaver lock window
win32 kills the screen saver and shows the lock window
@ -396,6 +469,10 @@ gspencer:
code, since if you have a key down you aren't supposed to be able to
cross over...
gspencer:
bouncy mouse at edge of screen (win32 server). almost certainly
related to changes that fixed mouse delta calculation.
== fixed? ===
dragging windows is too slow

View File

@ -525,6 +525,7 @@ CXWindowsClipboard::motifLockClipboard() const
// fail if anybody owns the lock (even us, so this is non-recursive)
Window lockOwner = XGetSelectionOwner(m_display, m_atomMotifClipLock);
if (lockOwner != None) {
log((CLOG_DEBUG1 "motif lock owner 0x%08x", lockOwner));
return false;
}
@ -536,6 +537,7 @@ CXWindowsClipboard::motifLockClipboard() const
XSetSelectionOwner(m_display, m_atomMotifClipLock, m_window, time);
lockOwner = XGetSelectionOwner(m_display, m_atomMotifClipLock);
if (lockOwner != m_window) {
log((CLOG_DEBUG1 "motif lock owner 0x%08x", lockOwner));
return false;
}

47
server/CClientProxy.cpp Normal file
View File

@ -0,0 +1,47 @@
#include "CClientProxy.h"
#include "IInputStream.h"
#include "IOutputStream.h"
//
// CClientProxy
//
CClientProxy::CClientProxy(IServer* server, const CString& name,
IInputStream* input, IOutputStream* output) :
m_server(server),
m_name(name),
m_input(input),
m_output(output)
{
// do nothing
}
CClientProxy::~CClientProxy()
{
delete m_output;
delete m_input;
}
IServer*
CClientProxy::getServer() const
{
return m_server;
}
IInputStream*
CClientProxy::getInputStream() const
{
return m_input;
}
IOutputStream*
CClientProxy::getOutputStream() const
{
return m_output;
}
CString
CClientProxy::getName() const
{
return m_name;
}

61
server/CClientProxy.h Normal file
View File

@ -0,0 +1,61 @@
#ifndef CCLIENTPROXY_H
#define CCLIENTPROXY_H
#include "IClient.h"
#include "CString.h"
class IInputStream;
class IOutputStream;
class IServer;
class CClientProxy : public IClient {
public:
CClientProxy(IServer* server, const CString& name,
IInputStream* adoptedInput,
IOutputStream* adoptedOutput);
~CClientProxy();
// manipulators
// accessors
// get the server
IServer* getServer() const;
// get the input and output streams for the client
IInputStream* getInputStream() const;
IOutputStream* getOutputStream() const;
// IClient overrides
virtual void open() = 0;
virtual void run() = 0;
virtual void close() = 0;
virtual void enter(SInt32 xAbs, SInt32 yAbs,
UInt32 seqNum, KeyModifierMask mask,
bool screenSaver) = 0;
virtual bool leave() = 0;
virtual void setClipboard(ClipboardID, const CString&) = 0;
virtual void grabClipboard(ClipboardID) = 0;
virtual void setClipboardDirty(ClipboardID, bool) = 0;
virtual void keyDown(KeyID, KeyModifierMask) = 0;
virtual void keyRepeat(KeyID, KeyModifierMask, SInt32 count) = 0;
virtual void keyUp(KeyID, KeyModifierMask) = 0;
virtual void mouseDown(ButtonID) = 0;
virtual void mouseUp(ButtonID) = 0;
virtual void mouseMove(SInt32 xAbs, SInt32 yAbs) = 0;
virtual void mouseWheel(SInt32 delta) = 0;
virtual void screenSaver(bool activate) = 0;
virtual CString getName() const;
virtual void getShape(SInt32& x, SInt32& y,
SInt32& width, SInt32& height) const = 0;
virtual void getCenter(SInt32& x, SInt32& y) const = 0;
virtual SInt32 getJumpZoneSize() const = 0;
private:
IServer* m_server;
CString m_name;
IInputStream* m_input;
IOutputStream* m_output;
};
#endif

337
server/CClientProxy1_0.cpp Normal file
View File

@ -0,0 +1,337 @@
#include "CClientProxy1_0.h"
#include "CServer.h"
#include "CClipboard.h"
#include "CProtocolUtil.h"
#include "ProtocolTypes.h"
#include "XSynergy.h"
#include "IInputStream.h"
#include "IOutputStream.h"
#include "CLock.h"
#include "CThread.h"
#include "CLog.h"
#include "CStopwatch.h"
#include <cstring>
//
// CClientProxy1_0
//
CClientProxy1_0::CClientProxy1_0(IServer* server, const CString& name,
IInputStream* input, IOutputStream* output) :
CClientProxy(server, name, input, output)
{
for (UInt32 i = 0; i < kClipboardEnd; ++i) {
m_clipboardDirty[i] = true;
}
}
CClientProxy1_0::~CClientProxy1_0()
{
// do nothing
}
void
CClientProxy1_0::open()
{
// send request
log((CLOG_DEBUG1 "querying client \"%s\" info", getName().c_str()));
CProtocolUtil::writef(getOutputStream(), kMsgQInfo);
getOutputStream()->flush();
// wait for and verify reply
UInt8 code[4];
for (;;) {
UInt32 n = getInputStream()->read(code, 4, -1.0);
if (n == 4) {
if (memcmp(code, kMsgCNoop, 4) == 0) {
// discard heartbeats
continue;
}
if (memcmp(code, kMsgDInfo, 4) == 0) {
break;
}
}
throw XBadClient();
}
// handle reply
recvInfo(false);
}
void
CClientProxy1_0::run()
{
// handle messages until the client hangs up or stops sending heartbeats
CStopwatch heartTimer;
for (;;) {
CThread::testCancel();
// wait for a message
UInt8 code[4];
UInt32 n = getInputStream()->read(code, 4, kHeartRate);
CThread::testCancel();
// check if client hungup
if (n == 0) {
log((CLOG_NOTE "client \"%s\" disconnected", getName().c_str()));
return;
}
// check if client has stopped sending heartbeats
if (n == (UInt32)-1) {
/* FIXME -- disabled to avoid masking bugs
if (heartTimer.getTime() > kHeartDeath) {
log((CLOG_NOTE "client \"%s\" is dead", getName().c_str()));
return;
}
*/
continue;
}
// got a message so reset heartbeat monitor
heartTimer.reset();
// verify we got an entire code
if (n != 4) {
log((CLOG_ERR "incomplete message from \"%s\": %d bytes", getName().c_str(), n));
// client sent an incomplete message
throw XBadClient();
}
// parse message
log((CLOG_DEBUG2 "msg from \"%s\": %c%c%c%c", getName().c_str(), code[0], code[1], code[2], code[3]));
if (memcmp(code, kMsgDInfo, 4) == 0) {
recvInfo(true);
}
else if (memcmp(code, kMsgCNoop, 4) == 0) {
// discard no-ops
continue;
}
else if (memcmp(code, kMsgCClipboard, 4) == 0) {
recvGrabClipboard();
}
else if (memcmp(code, kMsgDClipboard, 4) == 0) {
recvClipboard();
}
// note -- more message handlers go here
else {
log((CLOG_ERR "invalid message from client \"%s\"", getName().c_str()));
// unknown message
throw XBadClient();
}
}
}
void
CClientProxy1_0::close()
{
log((CLOG_DEBUG1 "send close to \"%s\"", getName().c_str()));
CProtocolUtil::writef(getOutputStream(), kMsgCClose);
// force the close to be sent before we return
getOutputStream()->flush();
}
void
CClientProxy1_0::enter(SInt32 xAbs, SInt32 yAbs,
UInt32 seqNum, KeyModifierMask mask, bool)
{
log((CLOG_DEBUG1 "send enter to \"%s\", %d,%d %d %04x", getName().c_str(), xAbs, yAbs, seqNum, mask));
CProtocolUtil::writef(getOutputStream(), kMsgCEnter,
xAbs, yAbs, seqNum, mask);
}
bool
CClientProxy1_0::leave()
{
log((CLOG_DEBUG1 "send leave to \"%s\"", getName().c_str()));
CProtocolUtil::writef(getOutputStream(), kMsgCLeave);
// we can never prevent the user from leaving
return true;
}
void
CClientProxy1_0::setClipboard(ClipboardID id, const CString& data)
{
// ignore if this clipboard is already clean
CLock lock(&m_mutex);
if (m_clipboardDirty[id]) {
// this clipboard is now clean
m_clipboardDirty[id] = false;
log((CLOG_DEBUG "send clipboard %d to \"%s\" size=%d", id, getName().c_str(), data.size()));
CProtocolUtil::writef(getOutputStream(), kMsgDClipboard, id, 0, &data);
}
}
void
CClientProxy1_0::grabClipboard(ClipboardID id)
{
log((CLOG_DEBUG "send grab clipboard %d to \"%s\"", id, getName().c_str()));
CProtocolUtil::writef(getOutputStream(), kMsgCClipboard, id, 0);
// this clipboard is now dirty
CLock lock(&m_mutex);
m_clipboardDirty[id] = true;
}
void
CClientProxy1_0::setClipboardDirty(ClipboardID id, bool dirty)
{
CLock lock(&m_mutex);
m_clipboardDirty[id] = dirty;
}
void
CClientProxy1_0::keyDown(KeyID key, KeyModifierMask mask)
{
log((CLOG_DEBUG1 "send key down to \"%s\" id=%d, mask=0x%04x", getName().c_str(), key, mask));
CProtocolUtil::writef(getOutputStream(), kMsgDKeyDown, key, mask);
}
void
CClientProxy1_0::keyRepeat(KeyID key, KeyModifierMask mask, SInt32 count)
{
log((CLOG_DEBUG1 "send key repeat to \"%s\" id=%d, mask=0x%04x, count=%d", getName().c_str(), key, mask, count));
CProtocolUtil::writef(getOutputStream(), kMsgDKeyRepeat, key, mask, count);
}
void
CClientProxy1_0::keyUp(KeyID key, KeyModifierMask mask)
{
log((CLOG_DEBUG1 "send key up to \"%s\" id=%d, mask=0x%04x", getName().c_str(), key, mask));
CProtocolUtil::writef(getOutputStream(), kMsgDKeyUp, key, mask);
}
void
CClientProxy1_0::mouseDown(ButtonID button)
{
log((CLOG_DEBUG1 "send mouse down to \"%s\" id=%d", getName().c_str(), button));
CProtocolUtil::writef(getOutputStream(), kMsgDMouseDown, button);
}
void
CClientProxy1_0::mouseUp(ButtonID button)
{
log((CLOG_DEBUG1 "send mouse up to \"%s\" id=%d", getName().c_str(), button));
CProtocolUtil::writef(getOutputStream(), kMsgDMouseUp, button);
}
void
CClientProxy1_0::mouseMove(SInt32 xAbs, SInt32 yAbs)
{
log((CLOG_DEBUG2 "send mouse move to \"%s\" %d,%d", getName().c_str(), xAbs, yAbs));
CProtocolUtil::writef(getOutputStream(), kMsgDMouseMove, xAbs, yAbs);
}
void
CClientProxy1_0::mouseWheel(SInt32 delta)
{
log((CLOG_DEBUG2 "send mouse wheel to \"%s\" %+d", getName().c_str(), delta));
CProtocolUtil::writef(getOutputStream(), kMsgDMouseWheel, delta);
}
void
CClientProxy1_0::screenSaver(bool on)
{
log((CLOG_DEBUG1 "send screen saver to \"%s\" on=%d", getName().c_str(), on ? 1 : 0));
CProtocolUtil::writef(getOutputStream(), kMsgCScreenSaver, on ? 1 : 0);
}
void
CClientProxy1_0::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const
{
CLock lock(&m_mutex);
x = m_x;
y = m_y;
w = m_w;
h = m_h;
}
void
CClientProxy1_0::getCenter(SInt32& x, SInt32& y) const
{
CLock lock(&m_mutex);
x = m_cx;
y = m_cy;
}
SInt32
CClientProxy1_0::getJumpZoneSize() const
{
CLock lock(&m_mutex);
return m_zoneSize;
}
void
CClientProxy1_0::recvInfo(bool notify)
{
{
CLock lock(&m_mutex);
// parse the message
CProtocolUtil::readf(getInputStream(), kMsgDInfo + 4,
&m_x, &m_y, &m_w, &m_h,
&m_zoneSize, &m_cx, &m_cy);
log((CLOG_DEBUG "received client \"%s\" info shape=%d,%d %dx%d, zone=%d, pos=%d,%d", getName().c_str(), m_x, m_y, m_w, m_h, m_zoneSize, m_cx, m_cy));
// validate
if (m_w <= 0 || m_h <= 0 || m_zoneSize < 0) {
throw XBadClient();
}
if (m_cx < m_x || m_cy < m_y || m_cx >= m_x + m_w || m_cy >= m_y + m_h) {
throw XBadClient();
}
}
// tell server of change
if (notify) {
getServer()->onInfoChanged(getName());
}
// acknowledge receipt
log((CLOG_DEBUG1 "send info ack to \"%s\"", getName().c_str()));
CProtocolUtil::writef(getOutputStream(), kMsgCInfoAck);
}
void
CClientProxy1_0::recvClipboard()
{
// parse message
ClipboardID id;
UInt32 seqNum;
CString data;
CProtocolUtil::readf(getInputStream(), kMsgDClipboard + 4, &id, &seqNum, &data);
log((CLOG_DEBUG "received client \"%s\" clipboard %d seqnum=%d, size=%d", getName().c_str(), id, seqNum, data.size()));
// validate
if (id >= kClipboardEnd) {
throw XBadClient();
}
// send update. this calls us back to reset our clipboard dirty flag
// so don't hold a lock during the call.
getServer()->onClipboardChanged(id, seqNum, data);
}
void
CClientProxy1_0::recvGrabClipboard()
{
// parse message
ClipboardID id;
UInt32 seqNum;
CProtocolUtil::readf(getInputStream(), kMsgCClipboard + 4, &id, &seqNum);
log((CLOG_DEBUG "received client \"%s\" grabbed clipboard %d seqnum=%d", getName().c_str(), id, seqNum));
// validate
if (id >= kClipboardEnd) {
throw XBadClient();
}
// send update. this calls us back to reset our clipboard dirty flag
// so don't hold a lock during the call.
getServer()->onGrabClipboard(id, seqNum, getName());
}

52
server/CClientProxy1_0.h Normal file
View File

@ -0,0 +1,52 @@
#ifndef CCLIENTPROXY1_0_H
#define CCLIENTPROXY1_0_H
#include "CClientProxy.h"
#include "CMutex.h"
class CClientProxy1_0 : public CClientProxy {
public:
CClientProxy1_0(IServer* server, const CString& name,
IInputStream* adoptedInput,
IOutputStream* adoptedOutput);
~CClientProxy1_0();
// IClient overrides
virtual void open();
virtual void run();
virtual void close();
virtual void enter(SInt32 xAbs, SInt32 yAbs,
UInt32 seqNum, KeyModifierMask mask,
bool screenSaver);
virtual bool leave();
virtual void setClipboard(ClipboardID, const CString&);
virtual void grabClipboard(ClipboardID);
virtual void setClipboardDirty(ClipboardID, bool);
virtual void keyDown(KeyID, KeyModifierMask);
virtual void keyRepeat(KeyID, KeyModifierMask, SInt32 count);
virtual void keyUp(KeyID, KeyModifierMask);
virtual void mouseDown(ButtonID);
virtual void mouseUp(ButtonID);
virtual void mouseMove(SInt32 xAbs, SInt32 yAbs);
virtual void mouseWheel(SInt32 delta);
virtual void screenSaver(bool activate);
virtual void getShape(SInt32& x, SInt32& y,
SInt32& width, SInt32& height) const;
virtual void getCenter(SInt32& x, SInt32& y) const;
virtual SInt32 getJumpZoneSize() const;
private:
void recvInfo(bool notify);
void recvClipboard();
void recvGrabClipboard();
private:
CMutex m_mutex;
SInt16 m_x, m_y;
SInt16 m_w, m_h;
SInt16 m_zoneSize;
SInt16 m_cx, m_cy;
bool m_clipboardDirty[kClipboardEnd];
};
#endif

308
server/CPrimaryClient.cpp Normal file
View File

@ -0,0 +1,308 @@
#include "CPrimaryClient.h"
#include "IServer.h"
#include "IPrimaryScreen.h"
#include "CClipboard.h"
#include "CLog.h"
// FIXME -- use factory to create screen
#if WINDOWS_LIKE
#include "CMSWindowsPrimaryScreen.h"
#elif UNIX_LIKE
#include "CXWindowsPrimaryScreen.h"
#endif
//
// CPrimaryClient
//
CPrimaryClient::CPrimaryClient(IServer* server, const CString& name) :
m_server(server),
m_name(name),
m_seqNum(0)
{
assert(m_server != NULL);
// create screen
log((CLOG_DEBUG1 "creating primary screen"));
#if WINDOWS_LIKE
m_screen = new CMSWindowsPrimaryScreen(this);
#elif UNIX_LIKE
m_screen = new CXWindowsPrimaryScreen(this);
#endif
}
CPrimaryClient::~CPrimaryClient()
{
delete m_screen;
}
void
CPrimaryClient::stop()
{
m_screen->stop();
}
void
CPrimaryClient::reconfigure()
{
m_screen->reconfigure();
}
void
CPrimaryClient::getClipboard(ClipboardID id, CString& data) const
{
CClipboard clipboard;
m_screen->getClipboard(id, &clipboard);
data = clipboard.marshall();
}
bool
CPrimaryClient::isLockedToScreen() const
{
return m_screen->isLockedToScreen();
}
KeyModifierMask
CPrimaryClient::getToggleMask() const
{
return m_screen->getToggleMask();
}
void
CPrimaryClient::onError()
{
m_server->onError();
}
void
CPrimaryClient::onInfoChanged(SInt32 x, SInt32 y, SInt32 w, SInt32 h,
SInt32 zoneSize, SInt32 cx, SInt32 cy)
{
m_x = x;
m_y = y;
m_w = w;
m_h = h;
m_zoneSize = zoneSize;
m_cx = cx;
m_cy = cy;
m_server->onInfoChanged(getName());
}
bool
CPrimaryClient::onGrabClipboard(ClipboardID id)
{
m_clipboardOwner[id] = m_server->onGrabClipboard(id, m_seqNum, getName());
}
bool
CPrimaryClient::onClipboardChanged(ClipboardID id, const CString& data)
{
m_server->onClipboardChanged(id, m_seqNum, data);
}
void
CPrimaryClient::onKeyDown(KeyID id, KeyModifierMask mask)
{
m_server->onKeyDown(id, mask);
}
void
CPrimaryClient::onKeyUp(KeyID id, KeyModifierMask mask)
{
m_server->onKeyUp(id, mask);
}
void
CPrimaryClient::onKeyRepeat(KeyID id, KeyModifierMask mask, SInt32 count)
{
m_server->onKeyRepeat(id, mask, count);
}
void
CPrimaryClient::onMouseDown(ButtonID id)
{
m_server->onMouseDown(id);
}
void
CPrimaryClient::onMouseUp(ButtonID id)
{
m_server->onMouseUp(id);
}
bool
CPrimaryClient::onMouseMovePrimary(SInt32 x, SInt32 y)
{
return m_server->onMouseMovePrimary(x, y);
}
void
CPrimaryClient::onMouseMoveSecondary(SInt32 dx, SInt32 dy)
{
m_server->onMouseMoveSecondary(dx, dy);
}
void
CPrimaryClient::onMouseWheel(SInt32 delta)
{
m_server->onMouseWheel(delta);
}
void
CPrimaryClient::onScreenSaver(bool activated)
{
m_server->onScreenSaver(activated);
}
void
CPrimaryClient::open()
{
// all clipboards are clean and owned by us
for (UInt32 i = 0; i < kClipboardEnd; ++i) {
m_clipboardOwner[i] = true;
m_clipboardDirty[i] = false;
}
// now open the screen
m_screen->open();
}
void
CPrimaryClient::run()
{
m_screen->run();
}
void
CPrimaryClient::close()
{
m_screen->close();
}
void
CPrimaryClient::enter(SInt32 xAbs, SInt32 yAbs,
UInt32 seqNum, KeyModifierMask, bool screensaver)
{
// note -- we must not call any server methods except onError().
m_seqNum = seqNum;
m_screen->enter(xAbs, yAbs, screensaver);
}
bool
CPrimaryClient::leave()
{
// note -- we must not call any server methods except onError().
return m_screen->leave();
}
void
CPrimaryClient::setClipboard(ClipboardID id, const CString& data)
{
// note -- we must not call any server methods except onError().
// ignore if this clipboard is already clean
if (m_clipboardDirty[id]) {
// this clipboard is now clean
m_clipboardDirty[id] = false;
// unmarshall data
CClipboard clipboard;
clipboard.unmarshall(data, 0);
// set clipboard
m_screen->setClipboard(id, &clipboard);
}
}
void
CPrimaryClient::grabClipboard(ClipboardID id)
{
// grab clipboard
m_screen->grabClipboard(id);
// clipboard is dirty (because someone else owns it now)
m_clipboardOwner[id] = false;
m_clipboardDirty[id] = true;
}
void
CPrimaryClient::setClipboardDirty(ClipboardID id, bool dirty)
{
m_clipboardDirty[id] = dirty;
}
void
CPrimaryClient::keyDown(KeyID, KeyModifierMask)
{
// ignore
}
void
CPrimaryClient::keyRepeat(KeyID, KeyModifierMask, SInt32)
{
// ignore
}
void
CPrimaryClient::keyUp(KeyID, KeyModifierMask)
{
// ignore
}
void
CPrimaryClient::mouseDown(ButtonID)
{
// ignore
}
void
CPrimaryClient::mouseUp(ButtonID)
{
// ignore
}
void
CPrimaryClient::mouseMove(SInt32 x, SInt32 y)
{
m_screen->warpCursor(x, y);
}
void
CPrimaryClient::mouseWheel(SInt32)
{
// ignore
}
void
CPrimaryClient::screenSaver(bool)
{
// ignore
}
CString
CPrimaryClient::getName() const
{
return m_name;
}
void
CPrimaryClient::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const
{
x = m_x;
y = m_y;
w = m_w;
h = m_h;
}
void
CPrimaryClient::getCenter(SInt32& x, SInt32& y) const
{
x = m_cx;
y = m_cy;
}
SInt32
CPrimaryClient::getJumpZoneSize() const
{
return m_zoneSize;
}

91
server/CPrimaryClient.h Normal file
View File

@ -0,0 +1,91 @@
#ifndef CPRIMARYCLIENT_H
#define CPRIMARYCLIENT_H
#include "IPrimaryReceiver.h"
#include "IClient.h"
class IClipboard;
class IPrimaryScreen;
class IServer;
class CPrimaryClient : public IPrimaryReceiver, public IClient {
public:
CPrimaryClient(IServer*, const CString& name);
~CPrimaryClient();
// manipulators
// cause run() to return
void stop();
// called by server when the configuration changes
void reconfigure();
// accessors
// return the contents of the given clipboard.
void getClipboard(ClipboardID, CString&) const;
// returns true iff the user is locked to the primary screen
bool isLockedToScreen() const;
// returns the state of the toggle keys on the primary screen
KeyModifierMask getToggleMask() const;
// IPrimaryReceiver overrides
virtual void onError();
virtual void onInfoChanged(SInt32 xScreen, SInt32 yScreen,
SInt32 wScreen, SInt32 hScreen,
SInt32 zoneSize,
SInt32 xMouse, SInt32 yMouse);
virtual bool onGrabClipboard(ClipboardID);
virtual bool onClipboardChanged(ClipboardID, const CString& data);
virtual void onKeyDown(KeyID, KeyModifierMask);
virtual void onKeyUp(KeyID, KeyModifierMask);
virtual void onKeyRepeat(KeyID, KeyModifierMask, SInt32 count);
virtual void onMouseDown(ButtonID);
virtual void onMouseUp(ButtonID);
virtual bool onMouseMovePrimary(SInt32 x, SInt32 y);
virtual void onMouseMoveSecondary(SInt32 dx, SInt32 dy);
virtual void onMouseWheel(SInt32 delta);
virtual void onScreenSaver(bool activated);
// IClient overrides
virtual void open();
virtual void run();
virtual void close();
virtual void enter(SInt32 xAbs, SInt32 yAbs,
UInt32 seqNum, KeyModifierMask mask,
bool screenSaver);
virtual bool leave();
virtual void setClipboard(ClipboardID, const CString&);
virtual void grabClipboard(ClipboardID);
virtual void setClipboardDirty(ClipboardID, bool);
virtual void keyDown(KeyID, KeyModifierMask);
virtual void keyRepeat(KeyID, KeyModifierMask, SInt32 count);
virtual void keyUp(KeyID, KeyModifierMask);
virtual void mouseDown(ButtonID);
virtual void mouseUp(ButtonID);
virtual void mouseMove(SInt32 xAbs, SInt32 yAbs);
virtual void mouseWheel(SInt32 delta);
virtual void screenSaver(bool activate);
virtual CString getName() const;
virtual void getShape(SInt32& x, SInt32& y,
SInt32& width, SInt32& height) const;
virtual void getCenter(SInt32& x, SInt32& y) const;
virtual SInt32 getJumpZoneSize() const;
private:
IServer* m_server;
IPrimaryScreen* m_screen;
CString m_name;
UInt32 m_seqNum;
SInt16 m_x, m_y;
SInt16 m_w, m_h;
SInt16 m_zoneSize;
SInt16 m_cx, m_cy;
bool m_clipboardOwner[kClipboardEnd];
bool m_clipboardDirty[kClipboardEnd];
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,7 @@
#ifndef CSERVER_H
#define CSERVER_H
#include "IServer.h"
#include "CConfig.h"
#include "CClipboard.h"
#include "ClipboardTypes.h"
@ -13,14 +14,17 @@
#include "stdlist.h"
#include "stdmap.h"
class CClientProxy;
class CHTTPServer;
class CPrimaryClient;
class CThread;
class IClient;
class IDataSocket;
class IServerProtocol;
class ISocketFactory;
class ISecurityFactory;
class IPrimaryScreen;
class CHTTPServer;
class CServer {
class CServer : public IServer {
public:
CServer(const CString& serverName);
~CServer();
@ -38,50 +42,12 @@ public:
// after a successful open().
void quit();
// tell the server to shutdown. this is called in an emergency
// when we need to tell the server that we cannot continue. the
// server will attempt to clean up.
void shutdown();
// update screen map. returns true iff the new configuration was
// accepted.
bool setConfig(const CConfig&);
// handle events on server's screen. onMouseMovePrimary() returns
// true iff the mouse enters a jump zone and jumps.
void onKeyDown(KeyID, KeyModifierMask);
void onKeyUp(KeyID, KeyModifierMask);
void onKeyRepeat(KeyID, KeyModifierMask, SInt32 count);
void onMouseDown(ButtonID);
void onMouseUp(ButtonID);
bool onMouseMovePrimary(SInt32 x, SInt32 y);
void onMouseMoveSecondary(SInt32 dx, SInt32 dy);
void onMouseWheel(SInt32 delta);
void grabClipboard(ClipboardID);
void onScreenSaver(bool activated);
// handle updates from primary
void setInfo(SInt32 xScreen, SInt32 yScreen,
SInt32 wScreen, SInt32 hScreen,
SInt32 zoneSize,
SInt32 xMouse, SInt32 yMouse);
// handle messages from clients
void setInfo(const CString& clientName,
SInt32 xScreen, SInt32 yScreen,
SInt32 wScreen, SInt32 hScreen,
SInt32 zoneSize,
SInt32 xMouse, SInt32 yMouse);
void grabClipboard(ClipboardID,
UInt32 seqNum, const CString& clientName);
void setClipboard(ClipboardID,
UInt32 seqNum, const CString& data);
// accessors
// returns true if the mouse should be locked to the current screen
bool isLockedToScreen() const;
// get the current screen map
void getConfig(CConfig*) const;
@ -91,64 +57,58 @@ public:
// get the sides of the primary screen that have neighbors
UInt32 getActivePrimarySides() const;
// IServer overrides
virtual void onError();
virtual void onInfoChanged(const CString& clientName);
virtual bool onGrabClipboard(ClipboardID,
UInt32 seqNum, const CString& clientName);
virtual void onClipboardChanged(ClipboardID,
UInt32 seqNum, const CString& data);
virtual void onKeyDown(KeyID, KeyModifierMask);
virtual void onKeyUp(KeyID, KeyModifierMask);
virtual void onKeyRepeat(KeyID, KeyModifierMask, SInt32 count);
virtual void onMouseDown(ButtonID);
virtual void onMouseUp(ButtonID);
virtual bool onMouseMovePrimary(SInt32 x, SInt32 y);
virtual void onMouseMoveSecondary(SInt32 dx, SInt32 dy);
virtual void onMouseWheel(SInt32 delta);
virtual void onGrabClipboard(ClipboardID);
virtual void onScreenSaver(bool activated);
protected:
bool onCommandKey(KeyID, KeyModifierMask, bool down);
private:
typedef std::list<CThread*> CThreadList;
class CScreenInfo {
public:
CScreenInfo(const CString& name, IServerProtocol*);
~CScreenInfo();
public:
// the thread handling this screen's connection. used when
// forcing a screen to disconnect.
CThread m_thread;
CString m_name;
IServerProtocol* m_protocol;
bool m_ready;
// screen shape and jump zone size
SInt32 m_x, m_y;
SInt32 m_w, m_h;
SInt32 m_zoneSize;
bool m_gotClipboard[kClipboardEnd];
};
typedef std::list<CThread> CThreadList;
// handle mouse motion
bool onMouseMovePrimaryNoLock(SInt32 x, SInt32 y);
void onMouseMoveSecondaryNoLock(SInt32 dx, SInt32 dy);
// update screen info
void setInfoNoLock(const CString& screenName,
SInt32 xScreen, SInt32 yScreen,
SInt32 wScreen, SInt32 hScreen,
SInt32 zoneSize,
SInt32 xMouse, SInt32 yMouse);
// grab the clipboard
void grabClipboardNoLock(ClipboardID,
bool grabClipboardNoLock(ClipboardID,
UInt32 seqNum, const CString& clientName);
// set the clipboard
void onClipboardChangedNoLock(ClipboardID,
UInt32 seqNum, const CString& data);
// returns true iff mouse should be locked to the current screen
bool isLockedToScreenNoLock() const;
// change the active screen
void switchScreen(CScreenInfo*,
void switchScreen(IClient*,
SInt32 x, SInt32 y, bool forScreenSaver);
// lookup neighboring screen
CScreenInfo* getNeighbor(CScreenInfo*, CConfig::EDirection) const;
IClient* getNeighbor(IClient*, CConfig::EDirection) const;
// lookup neighboring screen. given a position relative to the
// source screen, find the screen we should move onto and where.
// if the position is sufficiently far from the source then we
// cross multiple screens. if there is no suitable screen then
// return NULL and x,y are not modified.
CScreenInfo* getNeighbor(CScreenInfo*,
IClient* getNeighbor(IClient*,
CConfig::EDirection,
SInt32& x, SInt32& y) const;
@ -156,15 +116,13 @@ private:
void openPrimaryScreen();
void closePrimaryScreen();
// clear gotClipboard flags in all screens
void clearGotClipboard(ClipboardID);
// send clipboard to the active screen if it doesn't already have it
void sendClipboard(ClipboardID);
// update the clipboard if owned by the primary screen
void updatePrimaryClipboard(ClipboardID);
// close all clients that are *not* in config, not including the
// primary client.
void closeClients(const CConfig& config);
// start a thread, adding it to the list of threads
void startThread(IJob* adopted);
@ -180,8 +138,9 @@ private:
// thread method to accept incoming client connections
void acceptClients(void*);
// thread method to do startup handshake with client
void handshakeClient(void*);
// thread method to do client interaction
void runClient(void*);
CClientProxy* handshakeClient(IDataSocket*);
// thread method to accept incoming HTTP connections
void acceptHTTPClients(void*);
@ -190,11 +149,10 @@ private:
void processHTTPRequest(void*);
// connection list maintenance
CScreenInfo* addConnection(const CString& name, IServerProtocol*);
void addConnection(IClient*);
void removeConnection(const CString& name);
private:
typedef std::map<CString, CScreenInfo*> CScreenList;
class CClipboardInfo {
public:
CClipboardInfo();
@ -204,7 +162,6 @@ private:
CString m_clipboardData;
CString m_clipboardOwner;
UInt32 m_clipboardSeqNum;
bool m_clipboardReady;
};
CMutex m_mutex;
@ -212,6 +169,7 @@ private:
// the name of the primary screen
CString m_name;
// how long to wait to bind our socket until we give up
double m_bindTimeout;
ISocketFactory* m_socketFactory;
@ -221,10 +179,21 @@ private:
CThreadList m_threads;
// the screens
IPrimaryScreen* m_primary;
CScreenList m_screens;
CScreenInfo* m_active;
CScreenInfo* m_primaryInfo;
typedef std::map<CString, IClient*> CClientList;
typedef std::map<CString, CThread> CClientThreadList;
// all clients indexed by name
CClientList m_clients;
// run thread of all secondary screen clients. does not include the
// primary screen's run thread.
CClientThreadList m_clientThreads;
// the primary screen client
CPrimaryClient* m_primaryClient;
// the client with focus
IClient* m_active;
// the sequence number of enter messages
UInt32 m_seqNum;
@ -239,7 +208,7 @@ private:
CClipboardInfo m_clipboards[kClipboardEnd];
// state saved when screen saver activates
CScreenInfo* m_activeSaver;
IClient* m_activeSaver;
SInt32 m_xSaver, m_ySaver;
// HTTP request processing stuff

View File

@ -1,77 +0,0 @@
#include "CServerProtocol.h"
#include "CServerProtocol1_0.h"
#include "ProtocolTypes.h"
#include "XSynergy.h"
#include "IOutputStream.h"
#include <cstdio>
//
// CServerProtocol
//
CServerProtocol::CServerProtocol(CServer* server, const CString& client,
IInputStream* input, IOutputStream* output) :
m_server(server),
m_client(client),
m_input(input),
m_output(output)
{
assert(m_server != NULL);
assert(m_input != NULL);
assert(m_output != NULL);
}
CServerProtocol::~CServerProtocol()
{
// do nothing
}
CServer*
CServerProtocol::getServer() const
{
return m_server;
}
CString
CServerProtocol::getClient() const
{
return m_client;
}
IInputStream*
CServerProtocol::getInputStream() const
{
return m_input;
}
IOutputStream*
CServerProtocol::getOutputStream() const
{
return m_output;
}
IServerProtocol*
CServerProtocol::create(SInt32 major, SInt32 minor,
CServer* server, const CString& client,
IInputStream* input, IOutputStream* output)
{
// disallow invalid version numbers
if (major < 0 || minor < 0) {
throw XIncompatibleClient(major, minor);
}
// disallow connection from test versions to release versions
if (major == 0 && kProtocolMajorVersion != 0) {
throw XIncompatibleClient(major, minor);
}
// hangup (with error) if version isn't supported
if (major > kProtocolMajorVersion ||
(major == kProtocolMajorVersion && minor > kProtocolMinorVersion)) {
throw XIncompatibleClient(major, minor);
}
// create highest version protocol object not higher than the
// given version.
return new CServerProtocol1_0(server, client, input, output);
}

View File

@ -1,61 +0,0 @@
#ifndef CSERVERPROTOCOL_H
#define CSERVERPROTOCOL_H
#include "IServerProtocol.h"
class CServer;
class IInputStream;
class IOutputStream;
class CServerProtocol : public IServerProtocol {
public:
CServerProtocol(CServer*, const CString& clientName,
IInputStream*, IOutputStream*);
~CServerProtocol();
// manipulators
// accessors
virtual CServer* getServer() const;
virtual CString getClient() const;
virtual IInputStream* getInputStream() const;
virtual IOutputStream* getOutputStream() const;
static IServerProtocol* create(SInt32 major, SInt32 minor,
CServer*, const CString& clientName,
IInputStream*, IOutputStream*);
// IServerProtocol overrides
virtual void run() = 0;
virtual void queryInfo() = 0;
virtual void sendClose() = 0;
virtual void sendEnter(SInt32 xAbs, SInt32 yAbs,
UInt32 seqNum, KeyModifierMask mask) = 0;
virtual void sendLeave() = 0;
virtual void sendClipboard(ClipboardID, const CString&) = 0;
virtual void sendGrabClipboard(ClipboardID) = 0;
virtual void sendScreenSaver(bool on) = 0;
virtual void sendInfoAcknowledgment() = 0;
virtual void sendKeyDown(KeyID, KeyModifierMask) = 0;
virtual void sendKeyRepeat(KeyID, KeyModifierMask, SInt32 count) = 0;
virtual void sendKeyUp(KeyID, KeyModifierMask) = 0;
virtual void sendMouseDown(ButtonID) = 0;
virtual void sendMouseUp(ButtonID) = 0;
virtual void sendMouseMove(SInt32 xAbs, SInt32 yAbs) = 0;
virtual void sendMouseWheel(SInt32 delta) = 0;
protected:
//IServerProtocol overrides
virtual void recvInfo() = 0;
virtual void recvClipboard() = 0;
virtual void recvGrabClipboard() = 0;
private:
CServer* m_server;
CString m_client;
IInputStream* m_input;
IOutputStream* m_output;
};
#endif

View File

@ -1,283 +0,0 @@
#include "CServerProtocol1_0.h"
#include "CServer.h"
#include "CClipboard.h"
#include "CProtocolUtil.h"
#include "ProtocolTypes.h"
#include "XSynergy.h"
#include "IInputStream.h"
#include "IOutputStream.h"
#include "CThread.h"
#include "CLog.h"
#include "CStopwatch.h"
#include <cstring>
//
// CServerProtocol1_0
//
CServerProtocol1_0::CServerProtocol1_0(CServer* server, const CString& client,
IInputStream* input, IOutputStream* output) :
CServerProtocol(server, client, input, output)
{
// do nothing
}
CServerProtocol1_0::~CServerProtocol1_0()
{
// do nothing
}
void
CServerProtocol1_0::run()
{
// handle messages until the client hangs up or stops sending heartbeats
CStopwatch heartTimer;
for (;;) {
CThread::testCancel();
// wait for a message
UInt8 code[4];
UInt32 n = getInputStream()->read(code, 4, kHeartRate);
CThread::testCancel();
// check if client hungup
if (n == 0) {
log((CLOG_NOTE "client \"%s\" disconnected", getClient().c_str()));
return;
}
// check if client has stopped sending heartbeats
if (n == (UInt32)-1) {
/* FIXME -- disabled to avoid masking bugs
if (heartTimer.getTime() > kHeartDeath) {
log((CLOG_NOTE "client \"%s\" is dead", getClient().c_str()));
return;
}
*/
continue;
}
// got a message so reset heartbeat monitor
heartTimer.reset();
// verify we got an entire code
if (n != 4) {
log((CLOG_ERR "incomplete message from \"%s\": %d bytes", getClient().c_str(), n));
// client sent an incomplete message
throw XBadClient();
}
// parse message
log((CLOG_DEBUG2 "msg from \"%s\": %c%c%c%c", getClient().c_str(), code[0], code[1], code[2], code[3]));
if (memcmp(code, kMsgDInfo, 4) == 0) {
recvInfo();
}
else if (memcmp(code, kMsgCNoop, 4) == 0) {
// discard no-ops
continue;
}
else if (memcmp(code, kMsgCClipboard, 4) == 0) {
recvGrabClipboard();
}
else if (memcmp(code, kMsgDClipboard, 4) == 0) {
recvClipboard();
}
// FIXME -- more message here
else {
log((CLOG_ERR "invalid message from client \"%s\"", getClient().c_str()));
// unknown message
throw XBadClient();
}
}
}
void
CServerProtocol1_0::queryInfo()
{
log((CLOG_DEBUG1 "querying client \"%s\" info", getClient().c_str()));
// send request
CProtocolUtil::writef(getOutputStream(), kMsgQInfo);
// wait for and verify reply
UInt8 code[4];
for (;;) {
UInt32 n = getInputStream()->read(code, 4, -1.0);
if (n == 4) {
if (memcmp(code, kMsgCNoop, 4) == 0) {
// discard heartbeats
continue;
}
if (memcmp(code, kMsgDInfo, 4) == 0) {
break;
}
}
throw XBadClient();
}
// handle reply
recvInfo();
}
void
CServerProtocol1_0::sendClose()
{
log((CLOG_DEBUG1 "send close to \"%s\"", getClient().c_str()));
CProtocolUtil::writef(getOutputStream(), kMsgCClose);
// force the close to be sent before we return
getOutputStream()->flush();
}
void
CServerProtocol1_0::sendEnter(SInt32 xAbs, SInt32 yAbs,
UInt32 seqNum, KeyModifierMask mask)
{
log((CLOG_DEBUG1 "send enter to \"%s\", %d,%d %d %04x", getClient().c_str(), xAbs, yAbs, seqNum, mask));
CProtocolUtil::writef(getOutputStream(), kMsgCEnter,
xAbs, yAbs, seqNum, mask);
}
void
CServerProtocol1_0::sendLeave()
{
log((CLOG_DEBUG1 "send leave to \"%s\"", getClient().c_str()));
CProtocolUtil::writef(getOutputStream(), kMsgCLeave);
}
void
CServerProtocol1_0::sendClipboard(ClipboardID id, const CString& data)
{
log((CLOG_DEBUG "send clipboard %d to \"%s\" size=%d", id, getClient().c_str(), data.size()));
CProtocolUtil::writef(getOutputStream(), kMsgDClipboard, id, 0, &data);
}
void
CServerProtocol1_0::sendGrabClipboard(ClipboardID id)
{
log((CLOG_DEBUG "send grab clipboard %d to \"%s\"", id, getClient().c_str()));
CProtocolUtil::writef(getOutputStream(), kMsgCClipboard, id, 0);
}
void
CServerProtocol1_0::sendScreenSaver(bool on)
{
log((CLOG_DEBUG1 "send screen saver to \"%s\" on=%d", getClient().c_str(), on ? 1 : 0));
CProtocolUtil::writef(getOutputStream(), kMsgCScreenSaver, on ? 1 : 0);
}
void
CServerProtocol1_0::sendInfoAcknowledgment()
{
log((CLOG_DEBUG1 "send info ack to \"%s\"", getClient().c_str()));
CProtocolUtil::writef(getOutputStream(), kMsgCInfoAck);
}
void
CServerProtocol1_0::sendKeyDown(KeyID key, KeyModifierMask mask)
{
log((CLOG_DEBUG1 "send key down to \"%s\" id=%d, mask=0x%04x", getClient().c_str(), key, mask));
CProtocolUtil::writef(getOutputStream(), kMsgDKeyDown, key, mask);
}
void
CServerProtocol1_0::sendKeyRepeat(KeyID key, KeyModifierMask mask, SInt32 count)
{
log((CLOG_DEBUG1 "send key repeat to \"%s\" id=%d, mask=0x%04x, count=%d", getClient().c_str(), key, mask, count));
CProtocolUtil::writef(getOutputStream(), kMsgDKeyRepeat, key, mask, count);
}
void
CServerProtocol1_0::sendKeyUp(KeyID key, KeyModifierMask mask)
{
log((CLOG_DEBUG1 "send key up to \"%s\" id=%d, mask=0x%04x", getClient().c_str(), key, mask));
CProtocolUtil::writef(getOutputStream(), kMsgDKeyUp, key, mask);
}
void
CServerProtocol1_0::sendMouseDown(ButtonID button)
{
log((CLOG_DEBUG1 "send mouse down to \"%s\" id=%d", getClient().c_str(), button));
CProtocolUtil::writef(getOutputStream(), kMsgDMouseDown, button);
}
void
CServerProtocol1_0::sendMouseUp(ButtonID button)
{
log((CLOG_DEBUG1 "send mouse up to \"%s\" id=%d", getClient().c_str(), button));
CProtocolUtil::writef(getOutputStream(), kMsgDMouseUp, button);
}
void
CServerProtocol1_0::sendMouseMove(SInt32 xAbs, SInt32 yAbs)
{
log((CLOG_DEBUG2 "send mouse move to \"%s\" %d,%d", getClient().c_str(), xAbs, yAbs));
CProtocolUtil::writef(getOutputStream(), kMsgDMouseMove, xAbs, yAbs);
}
void
CServerProtocol1_0::sendMouseWheel(SInt32 delta)
{
log((CLOG_DEBUG2 "send mouse wheel to \"%s\" %+d", getClient().c_str(), delta));
CProtocolUtil::writef(getOutputStream(), kMsgDMouseWheel, delta);
}
void
CServerProtocol1_0::recvInfo()
{
// parse the message
SInt16 x, y, w, h, zoneInfo, mx, my;
CProtocolUtil::readf(getInputStream(), kMsgDInfo + 4,
&x, &y, &w, &h, &zoneInfo, &mx, &my);
log((CLOG_DEBUG "received client \"%s\" info shape=%d,%d %dx%d, zone=%d, pos=%d,%d", getClient().c_str(), x, y, w, h, zoneInfo, mx, my));
// validate
if (w <= 0 || h <= 0 || zoneInfo < 0) {
throw XBadClient();
}
if (mx < x || my < y || mx >= x + w || my >= y + h) {
throw XBadClient();
}
// tell server of change
getServer()->setInfo(getClient(), x, y, w, h, zoneInfo, mx, my);
}
void
CServerProtocol1_0::recvClipboard()
{
// parse message
ClipboardID id;
UInt32 seqNum;
CString data;
CProtocolUtil::readf(getInputStream(), kMsgDClipboard + 4, &id, &seqNum, &data);
log((CLOG_DEBUG "received client \"%s\" clipboard %d seqnum=%d, size=%d", getClient().c_str(), id, seqNum, data.size()));
// validate
if (id >= kClipboardEnd) {
throw XBadClient();
}
// send update
getServer()->setClipboard(id, seqNum, data);
}
void
CServerProtocol1_0::recvGrabClipboard()
{
// parse message
ClipboardID id;
UInt32 seqNum;
CProtocolUtil::readf(getInputStream(), kMsgCClipboard + 4, &id, &seqNum);
log((CLOG_DEBUG "received client \"%s\" grabbed clipboard %d seqnum=%d", getClient().c_str(), id, seqNum));
// validate
if (id >= kClipboardEnd) {
throw XBadClient();
}
// send update
getServer()->grabClipboard(id, seqNum, getClient());
}

View File

@ -1,41 +0,0 @@
#ifndef CSERVERPROTOCOL1_0_H
#define CSERVERPROTOCOL1_0_H
#include "CServerProtocol.h"
class CServerProtocol1_0 : public CServerProtocol {
public:
CServerProtocol1_0(CServer*, const CString&, IInputStream*, IOutputStream*);
~CServerProtocol1_0();
// manipulators
// accessors
// IServerProtocol overrides
virtual void run();
virtual void queryInfo();
virtual void sendClose();
virtual void sendEnter(SInt32 xAbs, SInt32 yAbs,
UInt32 seqNum, KeyModifierMask mask);
virtual void sendLeave();
virtual void sendClipboard(ClipboardID, const CString&);
virtual void sendGrabClipboard(ClipboardID);
virtual void sendScreenSaver(bool on);
virtual void sendInfoAcknowledgment();
virtual void sendKeyDown(KeyID, KeyModifierMask);
virtual void sendKeyRepeat(KeyID, KeyModifierMask, SInt32 count);
virtual void sendKeyUp(KeyID, KeyModifierMask);
virtual void sendMouseDown(ButtonID);
virtual void sendMouseUp(ButtonID);
virtual void sendMouseMove(SInt32 xAbs, SInt32 yAbs);
virtual void sendMouseWheel(SInt32 delta);
protected:
// IServerProtocol overrides
virtual void recvInfo();
virtual void recvClipboard();
virtual void recvGrabClipboard();
};
#endif

View File

@ -1,8 +1,9 @@
#include "CXWindowsPrimaryScreen.h"
#include "CServer.h"
#include "IPrimaryReceiver.h"
#include "CXWindowsClipboard.h"
#include "CXWindowsScreenSaver.h"
#include "CXWindowsUtil.h"
#include "CClipboard.h"
#include "CThread.h"
#include "CLog.h"
#include "CStopwatch.h"
@ -19,8 +20,8 @@
// CXWindowsPrimaryScreen
//
CXWindowsPrimaryScreen::CXWindowsPrimaryScreen() :
m_server(NULL),
CXWindowsPrimaryScreen::CXWindowsPrimaryScreen(IPrimaryReceiver* receiver) :
m_receiver(receiver),
m_active(false),
m_window(None)
{
@ -65,7 +66,7 @@ CXWindowsPrimaryScreen::run()
if (xevent.xclient.message_type == m_atomScreenSaver ||
xevent.xclient.format == 32) {
// screen saver activation/deactivation event
m_server->onScreenSaver(xevent.xclient.data.l[0] != 0);
m_receiver->onScreenSaver(xevent.xclient.data.l[0] != 0);
}
break;
@ -75,12 +76,12 @@ CXWindowsPrimaryScreen::run()
const KeyModifierMask mask = mapModifier(xevent.xkey.state);
const KeyID key = mapKey(&xevent.xkey);
if (key != kKeyNone) {
m_server->onKeyDown(key, mask);
m_receiver->onKeyDown(key, mask);
if (key == XK_Caps_Lock && m_capsLockHalfDuplex) {
m_server->onKeyUp(key, mask | KeyModifierCapsLock);
m_receiver->onKeyUp(key, mask | KeyModifierCapsLock);
}
else if (key == XK_Num_Lock && m_numLockHalfDuplex) {
m_server->onKeyUp(key, mask | KeyModifierNumLock);
m_receiver->onKeyUp(key, mask | KeyModifierNumLock);
}
}
}
@ -110,12 +111,12 @@ CXWindowsPrimaryScreen::run()
// no press event follows so it's a plain release
log((CLOG_DEBUG1 "event: KeyRelease code=%d, state=0x%04x", xevent.xkey.keycode, xevent.xkey.state));
if (key == XK_Caps_Lock && m_capsLockHalfDuplex) {
m_server->onKeyDown(key, mask);
m_receiver->onKeyDown(key, mask);
}
else if (key == XK_Num_Lock && m_numLockHalfDuplex) {
m_server->onKeyDown(key, mask);
m_receiver->onKeyDown(key, mask);
}
m_server->onKeyUp(key, mask);
m_receiver->onKeyUp(key, mask);
}
else {
// found a press event following so it's a repeat.
@ -123,7 +124,7 @@ CXWindowsPrimaryScreen::run()
// repeats but we'll just send a repeat of 1.
// note that we discard the press event.
log((CLOG_DEBUG1 "event: repeat code=%d, state=0x%04x", xevent.xkey.keycode, xevent.xkey.state));
m_server->onKeyRepeat(key, mask, 1);
m_receiver->onKeyRepeat(key, mask, 1);
}
}
}
@ -134,7 +135,7 @@ CXWindowsPrimaryScreen::run()
log((CLOG_DEBUG1 "event: ButtonPress button=%d", xevent.xbutton.button));
const ButtonID button = mapButton(xevent.xbutton.button);
if (button != kButtonNone) {
m_server->onMouseDown(button);
m_receiver->onMouseDown(button);
}
}
break;
@ -144,15 +145,15 @@ CXWindowsPrimaryScreen::run()
log((CLOG_DEBUG1 "event: ButtonRelease button=%d", xevent.xbutton.button));
const ButtonID button = mapButton(xevent.xbutton.button);
if (button != kButtonNone) {
m_server->onMouseUp(button);
m_receiver->onMouseUp(button);
}
else if (xevent.xbutton.button == 4) {
// wheel forward (away from user)
m_server->onMouseWheel(120);
m_receiver->onMouseWheel(120);
}
else if (xevent.xbutton.button == 5) {
// wheel backward (toward user)
m_server->onMouseWheel(-120);
m_receiver->onMouseWheel(-120);
}
}
break;
@ -183,7 +184,7 @@ CXWindowsPrimaryScreen::run()
}
else if (!m_active) {
// motion on primary screen
m_server->onMouseMovePrimary(m_x, m_y);
m_receiver->onMouseMovePrimary(m_x, m_y);
}
else {
// motion on secondary screen. warp mouse back to
@ -214,7 +215,7 @@ CXWindowsPrimaryScreen::run()
// warping to the primary screen's enter position,
// effectively overriding it.
if (x != 0 || y != 0) {
m_server->onMouseMoveSecondary(x, y);
m_receiver->onMouseMoveSecondary(x, y);
}
}
}
@ -231,17 +232,11 @@ CXWindowsPrimaryScreen::stop()
}
void
CXWindowsPrimaryScreen::open(CServer* server)
CXWindowsPrimaryScreen::open()
{
assert(m_server == NULL);
assert(server != NULL);
// open the display
openDisplay();
// set the server
m_server = server;
// check for peculiarities
// FIXME -- may have to get these from some database
m_numLockHalfDuplex = false;
@ -283,23 +278,18 @@ CXWindowsPrimaryScreen::open(CServer* server)
m_yCenter = y + (h >> 1);
// send screen info
m_server->setInfo(x, y, w, h, getJumpZoneSize(), m_x, m_y);
m_receiver->onInfoChanged(x, y, w, h, 1, m_x, m_y);
}
void
CXWindowsPrimaryScreen::close()
{
assert(m_server != NULL);
// stop being notified of screen saver activation/deactivation
getScreenSaver()->setNotify(None);
m_atomScreenSaver = None;
// close the display
closeDisplay();
// done with server
m_server = NULL;
}
void
@ -394,7 +384,7 @@ CXWindowsPrimaryScreen::leave()
}
void
CXWindowsPrimaryScreen::onConfigure()
CXWindowsPrimaryScreen::reconfigure()
{
// do nothing
}
@ -475,19 +465,6 @@ CXWindowsPrimaryScreen::grabClipboard(ClipboardID id)
setDisplayClipboard(id, NULL);
}
void
CXWindowsPrimaryScreen::getShape(
SInt32& x, SInt32& y, SInt32& w, SInt32& h) const
{
getScreenShape(x, y, w, h);
}
SInt32
CXWindowsPrimaryScreen::getJumpZoneSize() const
{
return 1;
}
void
CXWindowsPrimaryScreen::getClipboard(ClipboardID id,
IClipboard* clipboard) const
@ -555,13 +532,6 @@ CXWindowsPrimaryScreen::isLockedToScreen() const
return false;
}
bool
CXWindowsPrimaryScreen::isScreenSaverActive() const
{
CDisplayLock display(this);
return getScreenSaver()->isActive();
}
void
CXWindowsPrimaryScreen::onOpenDisplay(Display* display)
{
@ -616,16 +586,14 @@ void
CXWindowsPrimaryScreen::onUnexpectedClose()
{
// tell server to shutdown
if (m_server != NULL) {
m_server->shutdown();
}
m_receiver->onError();
}
void
CXWindowsPrimaryScreen::onLostClipboard(ClipboardID id)
{
// tell server that the clipboard was grabbed locally
m_server->grabClipboard(id);
m_receiver->onGrabClipboard(id);
}
void

View File

@ -5,28 +5,27 @@
#include "IPrimaryScreen.h"
#include "MouseTypes.h"
class IPrimaryReceiver;
class CXWindowsPrimaryScreen : public CXWindowsScreen, public IPrimaryScreen {
public:
CXWindowsPrimaryScreen();
CXWindowsPrimaryScreen(IPrimaryReceiver*);
virtual ~CXWindowsPrimaryScreen();
// IPrimaryScreen overrides
virtual void run();
virtual void stop();
virtual void open(CServer*);
virtual void open();
virtual void close();
virtual void enter(SInt32 xAbsolute, SInt32 yAbsolute, bool);
virtual bool leave();
virtual void onConfigure();
virtual void reconfigure();
virtual void warpCursor(SInt32 xAbsolute, SInt32 yAbsolute);
virtual void setClipboard(ClipboardID, const IClipboard*);
virtual void grabClipboard(ClipboardID);
virtual void getShape(SInt32&, SInt32&, SInt32&, SInt32&) const;
virtual SInt32 getJumpZoneSize() const;
virtual void getClipboard(ClipboardID, IClipboard*) const;
virtual KeyModifierMask getToggleMask() const;
virtual bool isLockedToScreen() const;
virtual bool isScreenSaverActive() const;
protected:
// CXWindowsScreen overrides
@ -61,7 +60,7 @@ private:
static Bool findKeyEvent(Display*, XEvent* xevent, XPointer arg);
private:
CServer* m_server;
IPrimaryReceiver* m_receiver;
bool m_active;
Window m_window;

46
server/IPrimaryReceiver.h Normal file
View File

@ -0,0 +1,46 @@
#ifndef IPRIMARYRECEIVER_H
#define IPRIMARYRECEIVER_H
#include "IInterface.h"
#include "ClipboardTypes.h"
#include "KeyTypes.h"
#include "MouseTypes.h"
#include "CString.h"
class IPrimaryReceiver : public IInterface {
public:
// manipulators
// notify of serious error. this implies that the primary screen
// cannot continue to function.
virtual void onError() = 0;
// notify of info change
virtual void onInfoChanged(SInt32 xScreen, SInt32 yScreen,
SInt32 wScreen, SInt32 hScreen,
SInt32 zoneSize,
SInt32 xMouse, SInt32 yMouse) = 0;
// notify of clipboard grab. returns true if the grab was honored,
// false otherwise.
virtual bool onGrabClipboard(ClipboardID) = 0;
// notify of new clipboard data. returns true if the clipboard data
// was accepted, false if the change was rejected.
virtual bool onClipboardChanged(ClipboardID,
const CString& data) = 0;
// call to notify of events. onMouseMovePrimary() returns
// true iff the mouse enters a jump zone and jumps.
virtual void onKeyDown(KeyID, KeyModifierMask) = 0;
virtual void onKeyUp(KeyID, KeyModifierMask) = 0;
virtual void onKeyRepeat(KeyID, KeyModifierMask, SInt32 count) = 0;
virtual void onMouseDown(ButtonID) = 0;
virtual void onMouseUp(ButtonID) = 0;
virtual bool onMouseMovePrimary(SInt32 x, SInt32 y) = 0;
virtual void onMouseMoveSecondary(SInt32 dx, SInt32 dy) = 0;
virtual void onMouseWheel(SInt32 delta) = 0;
virtual void onScreenSaver(bool activated) = 0;
};
#endif

View File

@ -5,7 +5,6 @@
#include "KeyTypes.h"
#include "ClipboardTypes.h"
class CServer;
class IClipboard;
class IPrimaryScreen : public IInterface {
@ -21,7 +20,8 @@ public:
// cause run() to return
virtual void stop() = 0;
// initialize the screen and start reporting events to the server.
// initialize the screen and start reporting events to the receiver
// (which is set through some interface of the derived class).
// events should be reported no matter where on the screen they
// occur but do not interfere with normal event dispatch. the
// screen saver engaging should be reported as an event. if that
@ -29,10 +29,11 @@ public:
// screen saver timer and should start the screen saver after
// idling for an appropriate time.
//
// open() must call server->setInfo() to notify the server of the
// primary screen's resolution and jump zone size. the mouse
// position is ignored and may be 0,0.
virtual void open(CServer* server) = 0;
// open() must call receiver->onInfoChanged() to notify of the
// primary screen's initial resolution and jump zone size. it
// must also call receiver->onClipboardChanged() for each
// clipboard that the primary screen has.
virtual void open() = 0;
// close the screen. should restore the screen saver timer if it
// was disabled.
@ -44,24 +45,30 @@ public:
// call to leave() which preceeds it, however the screen should
// assume an implicit call to enter() in the call to open().
// if warpCursor is false then do not warp the mouse.
//
// enter() must not call any receiver methods except onError().
virtual void enter(SInt32 xAbsolute, SInt32 yAbsolute,
bool forScreenSaver) = 0;
// called when the user navigates off the primary screen. hide
// the cursor and grab exclusive access to the input devices.
// return true iff successful.
// called when the user navigates off the primary screen. hide the
// cursor and grab exclusive access to the input devices. return
// true iff successful.
//
// leave() must not call any receiver methods except onError().
virtual bool leave() = 0;
// called when the configuration has changed. subclasses may need
// to adjust things (like the jump zones) after the configuration
// changes.
virtual void onConfigure() = 0;
virtual void reconfigure() = 0;
// warp the cursor to the given position
virtual void warpCursor(SInt32 xAbsolute, SInt32 yAbsolute) = 0;
// set the screen's clipboard contents. this is usually called
// soon after an enter().
//
// setClipboard() must not call any receiver methods except onError().
virtual void setClipboard(ClipboardID, const IClipboard*) = 0;
// synergy should own the clipboard
@ -69,16 +76,9 @@ public:
// accessors
// get the screen region
virtual void getShape(SInt32& x, SInt32& y,
SInt32& width, SInt32& height) const = 0;
// get the size of jump zone
virtual SInt32 getJumpZoneSize() const = 0;
// get the screen's clipboard contents. the implementation can
// and should avoid setting the clipboard object if the screen's
// clipboard hasn't changed.
// return the contents of the given clipboard.
//
// getClipboard() must not call any receiver methods except onError().
virtual void getClipboard(ClipboardID, IClipboard*) const = 0;
// get the primary screen's current toggle modifier key state.
@ -90,9 +90,6 @@ public:
// any other reason that the user should not be allowed to switch
// screens.
virtual bool isLockedToScreen() const = 0;
// return true if the screen saver is activated
virtual bool isScreenSaverActive() const = 0;
};
#endif

View File

@ -1,53 +0,0 @@
#ifndef ISERVERPROTOCOL_H
#define ISERVERPROTOCOL_H
#include "IInterface.h"
#include "ClipboardTypes.h"
#include "KeyTypes.h"
#include "MouseTypes.h"
#include "CString.h"
class IClipboard;
class IServerProtocol : public IInterface {
public:
// manipulators
// process messages from the client and insert the appropriate
// events into the server's event queue. return when the client
// disconnects.
virtual void run() = 0;
// send client info query and process reply
virtual void queryInfo() = 0;
// send various messages to client
virtual void sendClose() = 0;
virtual void sendEnter(SInt32 xAbs, SInt32 yAbs,
UInt32 seqNum, KeyModifierMask mask) = 0;
virtual void sendLeave() = 0;
virtual void sendClipboard(ClipboardID, const CString&) = 0;
virtual void sendGrabClipboard(ClipboardID) = 0;
virtual void sendScreenSaver(bool on) = 0;
virtual void sendInfoAcknowledgment() = 0;
virtual void sendKeyDown(KeyID, KeyModifierMask) = 0;
virtual void sendKeyRepeat(KeyID, KeyModifierMask, SInt32 count) = 0;
virtual void sendKeyUp(KeyID, KeyModifierMask) = 0;
virtual void sendMouseDown(ButtonID) = 0;
virtual void sendMouseUp(ButtonID) = 0;
virtual void sendMouseMove(SInt32 xAbs, SInt32 yAbs) = 0;
virtual void sendMouseWheel(SInt32 delta) = 0;
// accessors
protected:
// manipulators
virtual void recvInfo() = 0;
virtual void recvClipboard() = 0;
virtual void recvGrabClipboard() = 0;
// accessors
};
#endif

View File

@ -4,20 +4,23 @@ DEPTH = ..
bin_PROGRAMS = synergyd
synergyd_SOURCES = \
CClientProxy.cpp \
CClientProxy1_0.cpp \
CConfig.cpp \
CServerProtocol.cpp \
CServerProtocol1_0.cpp \
CXWindowsPrimaryScreen.cpp \
CServer.cpp \
CHTTPServer.cpp \
CPrimaryClient.cpp \
CServer.cpp \
CXWindowsPrimaryScreen.cpp \
server.cpp \
CClientProxy.h \
CClientProxy1_0.h \
CConfig.h \
CHTTPServer.h \
CPrimaryClient.h \
CServer.h \
CServerProtocol.h \
CServerProtocol1_0.h \
CSynergyHook.h \
CXWindowsPrimaryScreen.h \
IPrimaryReceiver.h \
IPrimaryScreen.h \
$(NULL)
synergyd_LDADD = \
$(DEPTH)/platform/libplatform.a \

91
synergy/IClient.h Normal file
View File

@ -0,0 +1,91 @@
#ifndef ICLIENT_H
#define ICLIENT_H
#include "IInterface.h"
#include "ClipboardTypes.h"
#include "KeyTypes.h"
#include "MouseTypes.h"
#include "CString.h"
class IClient : public IInterface {
public:
// manipulators
// open client
virtual void open() = 0;
// service client
virtual void run() = 0;
// close client
virtual void close() = 0;
// enter the screen. the cursor should be warped to xAbs,yAbs.
// the client should record seqNum for future reporting of
// clipboard changes. mask is the expected toggle button state.
// screenSaver is true if the screen is being entered because
// the screen saver is starting.
virtual void enter(SInt32 xAbs, SInt32 yAbs,
UInt32 seqNum, KeyModifierMask mask,
bool screenSaver) = 0;
// leave the screen. returns false if the user may not leave the
// client's screen.
virtual bool leave() = 0;
// FIXME -- methods for setting clipboard. on proxy side these
// will set/reset the gotClipboard flag and send the clipboard
// when not gotClipboard is false. grabbing goes in here too.
// basically, figure out semantics of these methods. note that
// ISecondaryScreen wants an IClipboard* passed to set not a
// string; will that be a problem?
// update the client's clipboard. this implies that the client's
// clipboard is now up to date. if the client's clipboard was
// already known to be up to date then this can do nothing.
virtual void setClipboard(ClipboardID, const CString&) = 0;
// grab the client's clipboard. since this is called when another
// client takes ownership of the clipboard it implies that the
// client's clipboard is dirty.
virtual void grabClipboard(ClipboardID) = 0;
// called to set the client's clipboard as dirty or clean
virtual void setClipboardDirty(ClipboardID, bool dirty) = 0;
// handle input events
virtual void keyDown(KeyID, KeyModifierMask) = 0;
virtual void keyRepeat(KeyID, KeyModifierMask, SInt32 count) = 0;
virtual void keyUp(KeyID, KeyModifierMask) = 0;
virtual void mouseDown(ButtonID) = 0;
virtual void mouseUp(ButtonID) = 0;
// FIXME -- if server uses IClient as interface to primary screen
// (should this class be renamed?) then be careful of absolute/relative
// coordinates here; move on primary and move on secondary take
// different values. probably not relevant, though.
virtual void mouseMove(SInt32 xAbs, SInt32 yAbs) = 0;
virtual void mouseWheel(SInt32 delta) = 0;
virtual void screenSaver(bool activate) = 0;
// accessors
// get the client's identifier
virtual CString getName() const = 0;
// get the screen's shape
// FIXME -- may want center pixel too
virtual void getShape(SInt32& x, SInt32& y,
SInt32& width, SInt32& height) const = 0;
// get the center pixel
virtual void getCenter(SInt32& x, SInt32& y) const = 0;
// get the size of jump zone
virtual SInt32 getJumpZoneSize() const = 0;
// what about getClipboard()? don't really want proxy to ask for it;
// it's a push data model. screen info is cached in proxy so it's
// different. will need to keep onClipboardChanged() in CClient.
};
#endif

43
synergy/IServer.h Normal file
View File

@ -0,0 +1,43 @@
#ifndef ISERVER_H
#define ISERVER_H
#include "IInterface.h"
#include "ClipboardTypes.h"
#include "KeyTypes.h"
#include "MouseTypes.h"
#include "CString.h"
class IServer : public IInterface {
public:
// manipulators
// notify of serious error. this implies that the server should
// shutdown.
virtual void onError() = 0;
// notify of client info change (maybe IClient should be named IScreen)
virtual void onInfoChanged(const CString& clientName) = 0;
// notify of clipboard grab. returns true if the grab was honored,
// false otherwise.
virtual bool onGrabClipboard(ClipboardID,
UInt32 seqNum, const CString& clientName) = 0;
// notify of new clipboard data
virtual void onClipboardChanged(ClipboardID,
UInt32 seqNum, const CString& data) = 0;
// call to notify of events. onMouseMovePrimary() returns
// true iff the mouse enters a jump zone and jumps.
virtual void onKeyDown(KeyID, KeyModifierMask) = 0;
virtual void onKeyUp(KeyID, KeyModifierMask) = 0;
virtual void onKeyRepeat(KeyID, KeyModifierMask, SInt32 count) = 0;
virtual void onMouseDown(ButtonID) = 0;
virtual void onMouseUp(ButtonID) = 0;
virtual bool onMouseMovePrimary(SInt32 x, SInt32 y) = 0;
virtual void onMouseMoveSecondary(SInt32 dx, SInt32 dy) = 0;
virtual void onMouseWheel(SInt32 delta) = 0;
virtual void onScreenSaver(bool activated) = 0;
};
#endif

View File

@ -17,10 +17,11 @@ libsynergy_a_SOURCES = \
CProtocolUtil.h \
CTCPSocketFactory.h \
ClipboardTypes.h \
IClient.h \
IClipboard.h \
IScreenSaver.h \
ISecondaryScreen.h \
IServerProtocol.h \
IServer.h \
ISocketFactory.h \
KeyTypes.h \
MouseTypes.h \