Synergy Developer and Porting Guide
===================================

This document is under development.

Code Organization
-----------------

The synergy source code organization is:

.               -- root makefiles, some standard documentation
cmd             -- program source code
  launcher      -- synergy launcher for Windows
  synergyc      -- synergy client
  synergys      -- synergy server
config          -- stuff for autoconf/automake
dist            -- files for creating distributions
  nullsoft      -- files for creating Nullsoft NSIS installer (Windows)
  rpm           -- files for creating RPMs
doc             -- placeholder for documentation
examples        -- example files
lib             -- library source code
  arch          -- platform dependent utility library
  base          -- simple utilities
  client        -- synergy client library
  common        -- commonly needed header files
  io            -- I/O
  mt            -- multithreading
  net           -- networking
  platform      -- platform dependent display/window/event stuff
  server        -- synergy server library
  synergy       -- synergy shared client/server code library

Note how the utility code required by the programs is placed into
separate library directories.  This makes the makefiles a little
more awkward but makes for a cleaner organization.  The top level
directory has only the standard documentation files and the files
necessary to configure and build the rest of the project.


Coding Style Guide
------------------

Synergy uses many coding conventions.  Contributed code should
following these guidelines.

- Symbol Naming
  Names always begin with a letter (never an underscore).  The first
  letter of interior names are always capitalized.  Acronyms should
  be all uppercase.  For example: myTextAsASCII.

  Names come it two flavors:  leading capital and leading lowercase.
  The former have the first character capitalized and the latter
  don't.  In the following table, leading capital names are indicated
  by `Name' and leading lowercase names by `name'.

  The naming convention for various things are:

    * Exceptions       -- X + Name    XMyException
    * Interfaces       -- I + Name    IMyInterface
    * Template Classes -- T + Name    TMyTemplate<>
    * Other Classes    -- C + Name    CMyClass
    * Enumerations     -- E + Name    EMyEnumeration
    * Constants        -- k + Name    kMyConstant
    * Data Members     -- m_ + name   m_myDataMember
    * Methods          -- name        myMethod
    * Functions        -- name        myFunction
    * Variables        -- name        myVariable

  Exceptions are types that get thrown and are generally derived
  (possibly indirectly) from XBase.  Interfaces are derived (possibly
  indirectly) from IInterface and have only pure virtual functions.
  Other classes are classes that aren't exceptions or interfaces.
  Constants include global constants and enumerants.

  Method names should usually have the form `verbObject'.  For example:
    * isGameOn()
    * getBeer()
    * pressPowerButton()
    * setChannel()
  In general, use `get' and `set' to read and write state but use `is'
  to read boolean state.  Note that classes that contain only `is',
  `get', and `set' are probably plain old data;  you might want to
  consider using public data members only or, better, refactor your
  design to have classes that actually do something more than just
  hold data.

- File Naming
  Each class should have one source and one header file.  If the
  class is named `CMyClass' then the source file should be named
  `CMyClass.cpp' and the header file `CMyClass.h'.

  Headers files not containing a class should have some meaningful
  name with a leading capital (e.g. `Version.h').

  Source files without a header file have a leading lowercase name.
  Only files containing the entry point for an application should
  lack a header file.

- Dependencies
  * No circular library dependencies
    Library dependencies form an acyclic graph.  Conceptually
    libraries can be arranged in layers where each library only
    references libraries in layers below it, not in the same layer
    or layers above it.  The makefiles build the lowest layer
    libraries first and work upwards.

  * Avoid circular uses-a relationships
    When possible, design classes with one-way uses-a relationships
    and avoid cycles.  This makes it easier to understand the code.
    However, sometimes it's not always practical so it is permitted.

  * Included files in headers
    Headers should #include only the necessary headers.  In
    particular, if a class is referenced in a header file only as a
    pointer or a reference then use `class COtherClass;' instead of
    `#include "COtherClass.h".'

  * #include syntax
    Non-synergy header files must be included using angle brackets
    while synergy header files must be included using double quotes.
      #include "CSynergyHeader.h"
      #include <systemheader.h>
    The file name in a #include must not be a relative path unless
    it's a system header file and it's customary to use a relative
    path, e.g. `#include <sys/types.h>'.  Use compiler options to
    add necessary directories to the include search path.

  * Included file ordering
    Files should be included in the following order:
    * Header for source file
      The first include for CMyClass.cpp must be CMyClass.h. 
    * Other headers in directory, sorted alphabetically
    * Headers for each library, sorted alphabetically per library
      Include headers from the library closest in the dependency graph
        first, then the next farthest, etc.  Sort alphabetically within
        each library.
    * System headers

- C++
  * C++ features
    Synergy uses the following more recent C++ features:
    * bool
    * templates
    * exceptions
    * mutable
    * new scoping rules
    * the standard C++ library

    Do not use the following C++ features:
    * dynamic_cast
    * run time type information
    * namespaces and using (use std:: where necessary)

    The new scoping rules say that the scope of a variable declared
    in a for statement is limited to the for loop.  For example:

      for (int i = 0; i < 10; ++i) {
        // i is in scope here
      }
      // i is not in scope here

      for (int i = -10; i < 0; ++i) {
        // an entirely new i is in scope here
      }
      // i is not in scope here

    This is used routinely in synergy, but only in for loops.  There
    is a macro for `for' in lib/base/common.h when building under
    Microsoft Visual C++ that works around the fact that that compiler
    doesn't follow the new scoping rules.  Use the macro if your
    compiler uses the old scoping rules.

  * Standard C++ library
    The standard C++ library containers should always be used in favor
    of custom containers wherever reasonable.  std::string is used
    throughout synergy but only as the CString typedef;  always use
    CString, never std::string except in the arch library.  Synergy
    avoids using auto_ptr due to some portability problems.  Synergy
    makes limited use of standard algorithms and streams but they can
    be freely used in new code.

  * Limited multiple inheritance
    Classes should inherit implementation from at most one superclass. 
    Inheriting implementation from multiple classes can have unpleasant
    consequences in C++ due to it's limited capabilities.  Classes can
    inherit	from any number of interface classes.  An interface class
    provides only pure virtual methods.  Synergy breaks this rule in
	IInterface which implements the virtual destructor for convenience.

  * No globals
	Avoid global variables.  All global variables must be static, making
    it visible only with its source file.  Most uses of global variables
    are better served by static data members of a class.  Global
    constants are permitted in some circumstances.

    Also avoid global functions.  Use public static member functions in
    a class instead.

    These rules are violated by the main source file for each program
    (except that the globals are still static).  They could easily be
    rewritten to put all the variables and functions into a class but
    there's little to be gained by that.

  * Private data only
    If a class is plain-old-data (i.e. it has no methods) all of its
    data members should be public.  Otherwise all of its data members
    should be private, not public or protected.  This makes it much
    easier to track the use of a member when reading code.  Protected
    data is not allowed because `protected' is a synonym for `public
    to my subclasses' and public data is a Bad Thing.  While it might
    seem okay in this limited situation, the situation is not at all
    limited since an arbitrary number of classes can be derived,
    directly or indirectly, from the class and any of those classes
    have full access to the protected data.

  * Plain old data
    A class that merely contains data and doesn't perform operations
    on that data (other than reads and writes) is plain old data (POD).
    POD should have only public data members and non-copy constructors.
    It must not have any methods other than constructors, not even a
    destructor or assignment operators, nor protected or private data.
    Note that this definition of POD is not the definition used in the
    C++ standard, which limits the contained data types to types that
    have no constructors, destructors, or methods.

  * Avoid using friend
    Avoid declaring friend functions or classes.  They're sometimes
    necessary for operator overloading.  If you find it necessary to
    add friends to some class C, consider creating a utility class U.
    A utility class is declared as the only friend of C and provides
    only static methods.  Each method forwards to a private method on
    an object of C type (passed as a parameter to the U's method).
    This makes maintenance easier since only U has friend access to C
    and finding any call to U is trivial (they're prefixed by U::).

  * Don't test for NULL when using `delete' or `delete[]'
    It's unnecessary since delete does it anyway.

- Makefiles
  Automake's makefiles (named Makefile.am) have a few requirements:
  * Define the following macro at the top of the file:
      NULL =
  * Lists should have one item per line and end in $(NULL).  For
    example:
      EXTRA_DIST =     \
          kiwi.txt     \
          mango.cpp    \
          papaya.h     \
          $(NULL)
    Indentation must use tabs in a makefile.  Line continuations
    (backslashes) should be aligned using tabs.
  * Lists of files should be sorted alphabetically in groups (e..g
    source files, header files, then other files).  Lists of
    subdirectories must be in the desired build order.

- Source Formatting
  Every project has its own formatting style and no style satisfies
  everyone.  New code should be consistent with existing code:

  * All files should include the copyright and license notice
  * Use tabs to indent
  * Tabs are 4 columns
  * Lines should not extend past the 80th column
  * Open braces ({) go on same line as introducing statement
    `for (i = 0; i < 10; ++i) {' not
     for (i = 0; i < 10; ++i)
     {
  * Close braces line up with introducing statement
  * Open brace for function is on a line by itself in first column
  * Close brace for function lines up with open brace
  * Always use braces on: if, else, for, while, do, switch
  * `else {' goes on its own line
  * Always explicitly test pointers against NULL
    e.g. `if (ptr == NULL)' not `if (ptr)'
  * Always explicitly test integral values against 0
    e.g. `if (i == 0)' not `if (i)'
  * Put spaces around binary operators and after statements
    e.g. `if (a == b) {' not `if(a==b){'
  * C'tor initializers are one per line, indented one tab stop
  * Other indentation should follow existing practice
  * Use Qt style comments for extraction by doxygen (i.e. //! and /*!)
  * Mark incomplete or buggy code with `FIXME'

- Other
  * calls to LOG() should always be all on one line (even past column 80)


Class Relationships
-------------------

The doxygen documentation can help in understanding the relationships
between objects.  Use `make doxygen' in the top level directory to
create the doxygen documentation into doc/doxygen/html.  You must have
doxygen installed, of course.

FIXME -- high level overview of class relationships


Portability
-----------

Synergy is mostly platform independent code but necessarily has
platform dependent parts.  The mundane platform dependent parts
come from the usual suspects:  networking, multithreading, file
system, high resolution clocks, system logging, etc.  Porting
these parts is relatively straightforward.

Synergy also has more esoteric platform dependent code.  The
functions for low-level event interception and insertion,
warping the cursor position, character to keyboard event
translation, clipboard manipulation, and screen saver control
are often obscure and poorly documented.  Unfortunately, these
are exactly the functions synergy requires to do its magic.

Porting synergy to a new platform requires the following steps:

- Setting up the build
- Adjusting lib/common/common.h
- Implementing lib/arch
- Implementing lib/platform
- Tweaks

Setting up the build:

The first phase is simply to create the files necessary to build the
other files.  On Unix, synergy uses autoconf/automake which produces
a `configure' script that generates makefiles.  On Windows, synergy
uses Visual C++ workspace and project files.  If you're porting to
another Unix variant, you may need to adjust `configure.in',
`acinclude.m4', and Unix flavor dependent code in lib/arch.  Note
especially the SYSAPI_* and WINAPI_* macro definitions in
ARCH_CFLAGS.  Exactly one of each must be defined.  It should also
add AM_CONDITIONALs if a new SYSAPI_* or WINAPI_* was added.

Adjusting lib/common/common.h:

The lib/common/common.h header file is included directly or indirectly
by every other file.  Its primary job is to include config.h, which
defines macros depending on what the 'configure' script discovered
about the system.  If the platform does not use the 'configure' script
it must define the appropriate SYSAPI_* and WINAPI_* macro.  It may
also do other platform specific setup.

Adjusting lib/common/BasicTypes.h:

No changes should be necessary in BasicTypes.h.  However, if the
platform's system header files define SInt8, et al. you may need
to adjust the typedefs to match the system's definitions.

Implementing lib/arch:

Much platform dependent code lives in lib/arch.  There are several
interface classes there and they must all be implemented for each
platform.  See the interface header files for more information.

Platforms requiring special functions should create a class named
CArchMiscXXX where XXX is the platform name.  The class should have
only static methods.  Clients can include the appropriate header
file and make calls directly, surrounded by a suitable #ifdef/#endif.

If using automake, the Makefile.am should list the system specific
files in a XXX_SOURCE_FILES macro where XXX matches the appropriate
AM_CONDITIONAL symbol.  XXX_SOURCE_FILES must be added to EXTRA_DIST
and the following added above the INCLUDES macro:

	if XXX
	libarch_a_SOURCES =			\
		$(COMMON_SOURCE_FILES)	\
		$(XXX_SOURCE_FILES)		\
		$(NULL)
	endif

Implementing lib/platform:

Most of the remaining platform dependent code lives in lib/platform.
The code there implements platform dependent window, clipboard, keyboard
and screen saver handling.  If a platform is named XXX then the following
classes should be derived and implemented:

  * CXXXClipboard : IClipboard
    Provides clipboard operations.  Typically, this class will
    have helper classes for converting between various clipboard
    data formats.

  * CXXXEventQueueBuffer : IEventQueueBuffer
    Provides operations for waiting for, posting and retrieving events.
	Also provides operations for creating and deleting timers.

  * CXXXKeyState : CKeyState
    Provides operations for synthesizing key events and for mapping a
	key ID to a sequence of events to generate that key.

  * CXXXScreen : IScreen, IPrimaryScreen, ISecondaryScreen, IPlatformScreen
    Provides screen operations.

  * CXXXScreenSaver : IScreenSaver
	Provides screen saver operations.

If using automake, the Makefile.am should list the window system
specific files in a XXX_SOURCE_FILES macro where XXX matches the
appropriate AM_CONDITIONAL symbol.  XXX_SOURCE_FILES must be added
to EXTRA_DIST and the following added above the INCLUDES macro:

	if XXX
	libplatform_a_SOURCES = $(XXX_SOURCE_FILES)
	endif

Tweaks:

Finally, each platform typically requires various adjustments here
and there.  In particular, synergyc.cpp and synergys.cpp usually
require platform dependent code for the main entry point, parsing
arguments, and reporting errors.  Also, some platforms may benefit
from a graphical user interface front end.  These are generally
not portable and synergy doesn't provide any infrastructure for
the code common to any platform, though it may do so someday.
There is, however, an implementation of a GUI front end for Windows
that serves as an example.
