1 | Synergy Developer and Porting Guide
|
---|
2 | ===================================
|
---|
3 |
|
---|
4 | This document is under development.
|
---|
5 |
|
---|
6 | Code Organization
|
---|
7 | -----------------
|
---|
8 |
|
---|
9 | The synergy source code organization is:
|
---|
10 |
|
---|
11 | . -- root makefiles, some standard documentation
|
---|
12 | cmd -- program source code
|
---|
13 | launcher -- synergy launcher for Windows
|
---|
14 | synergyc -- synergy client
|
---|
15 | synergys -- synergy server
|
---|
16 | config -- stuff for autoconf/automake
|
---|
17 | dist -- files for creating distributions
|
---|
18 | nullsoft -- files for creating Nullsoft NSIS installer (Windows)
|
---|
19 | rpm -- files for creating RPMs
|
---|
20 | doc -- placeholder for documentation
|
---|
21 | examples -- example files
|
---|
22 | lib -- library source code
|
---|
23 | arch -- platform dependent utility library
|
---|
24 | base -- simple utilities
|
---|
25 | client -- synergy client library
|
---|
26 | common -- commonly needed header files
|
---|
27 | io -- I/O
|
---|
28 | mt -- multithreading
|
---|
29 | net -- networking
|
---|
30 | platform -- platform dependent display/window/event stuff
|
---|
31 | server -- synergy server library
|
---|
32 | synergy -- synergy shared client/server code library
|
---|
33 |
|
---|
34 | Note how the utility code required by the programs is placed into
|
---|
35 | separate library directories. This makes the makefiles a little
|
---|
36 | more awkward but makes for a cleaner organization. The top level
|
---|
37 | directory has only the standard documentation files and the files
|
---|
38 | necessary to configure and build the rest of the project.
|
---|
39 |
|
---|
40 |
|
---|
41 | Coding Style Guide
|
---|
42 | ------------------
|
---|
43 |
|
---|
44 | Synergy uses many coding conventions. Contributed code should
|
---|
45 | following these guidelines.
|
---|
46 |
|
---|
47 | - Symbol Naming
|
---|
48 | Names always begin with a letter (never an underscore). The first
|
---|
49 | letter of interior names are always capitalized. Acronyms should
|
---|
50 | be all uppercase. For example: myTextAsASCII.
|
---|
51 |
|
---|
52 | Names come it two flavors: leading capital and leading lowercase.
|
---|
53 | The former have the first character capitalized and the latter
|
---|
54 | don't. In the following table, leading capital names are indicated
|
---|
55 | by `Name' and leading lowercase names by `name'.
|
---|
56 |
|
---|
57 | The naming convention for various things are:
|
---|
58 |
|
---|
59 | * Exceptions -- X + Name XMyException
|
---|
60 | * Interfaces -- I + Name IMyInterface
|
---|
61 | * Template Classes -- T + Name TMyTemplate<>
|
---|
62 | * Other Classes -- C + Name CMyClass
|
---|
63 | * Enumerations -- E + Name EMyEnumeration
|
---|
64 | * Constants -- k + Name kMyConstant
|
---|
65 | * Data Members -- m_ + name m_myDataMember
|
---|
66 | * Methods -- name myMethod
|
---|
67 | * Functions -- name myFunction
|
---|
68 | * Variables -- name myVariable
|
---|
69 |
|
---|
70 | Exceptions are types that get thrown and are generally derived
|
---|
71 | (possibly indirectly) from XBase. Interfaces are derived (possibly
|
---|
72 | indirectly) from IInterface and have only pure virtual functions.
|
---|
73 | Other classes are classes that aren't exceptions or interfaces.
|
---|
74 | Constants include global constants and enumerants.
|
---|
75 |
|
---|
76 | Method names should usually have the form `verbObject'. For example:
|
---|
77 | * isGameOn()
|
---|
78 | * getBeer()
|
---|
79 | * pressPowerButton()
|
---|
80 | * setChannel()
|
---|
81 | In general, use `get' and `set' to read and write state but use `is'
|
---|
82 | to read boolean state. Note that classes that contain only `is',
|
---|
83 | `get', and `set' are probably plain old data; you might want to
|
---|
84 | consider using public data members only or, better, refactor your
|
---|
85 | design to have classes that actually do something more than just
|
---|
86 | hold data.
|
---|
87 |
|
---|
88 | - File Naming
|
---|
89 | Each class should have one source and one header file. If the
|
---|
90 | class is named `CMyClass' then the source file should be named
|
---|
91 | `CMyClass.cpp' and the header file `CMyClass.h'.
|
---|
92 |
|
---|
93 | Headers files not containing a class should have some meaningful
|
---|
94 | name with a leading capital (e.g. `Version.h').
|
---|
95 |
|
---|
96 | Source files without a header file have a leading lowercase name.
|
---|
97 | Only files containing the entry point for an application should
|
---|
98 | lack a header file.
|
---|
99 |
|
---|
100 | - Dependencies
|
---|
101 | * No circular library dependencies
|
---|
102 | Library dependencies form an acyclic graph. Conceptually
|
---|
103 | libraries can be arranged in layers where each library only
|
---|
104 | references libraries in layers below it, not in the same layer
|
---|
105 | or layers above it. The makefiles build the lowest layer
|
---|
106 | libraries first and work upwards.
|
---|
107 |
|
---|
108 | * Avoid circular uses-a relationships
|
---|
109 | When possible, design classes with one-way uses-a relationships
|
---|
110 | and avoid cycles. This makes it easier to understand the code.
|
---|
111 | However, sometimes it's not always practical so it is permitted.
|
---|
112 |
|
---|
113 | * Included files in headers
|
---|
114 | Headers should #include only the necessary headers. In
|
---|
115 | particular, if a class is referenced in a header file only as a
|
---|
116 | pointer or a reference then use `class COtherClass;' instead of
|
---|
117 | `#include "COtherClass.h".'
|
---|
118 |
|
---|
119 | * #include syntax
|
---|
120 | Non-synergy header files must be included using angle brackets
|
---|
121 | while synergy header files must be included using double quotes.
|
---|
122 | #include "CSynergyHeader.h"
|
---|
123 | #include <systemheader.h>
|
---|
124 | The file name in a #include must not be a relative path unless
|
---|
125 | it's a system header file and it's customary to use a relative
|
---|
126 | path, e.g. `#include <sys/types.h>'. Use compiler options to
|
---|
127 | add necessary directories to the include search path.
|
---|
128 |
|
---|
129 | * Included file ordering
|
---|
130 | Files should be included in the following order:
|
---|
131 | * Header for source file
|
---|
132 | The first include for CMyClass.cpp must be CMyClass.h.
|
---|
133 | * Other headers in directory, sorted alphabetically
|
---|
134 | * Headers for each library, sorted alphabetically per library
|
---|
135 | Include headers from the library closest in the dependency graph
|
---|
136 | first, then the next farthest, etc. Sort alphabetically within
|
---|
137 | each library.
|
---|
138 | * System headers
|
---|
139 |
|
---|
140 | - C++
|
---|
141 | * C++ features
|
---|
142 | Synergy uses the following more recent C++ features:
|
---|
143 | * bool
|
---|
144 | * templates
|
---|
145 | * exceptions
|
---|
146 | * mutable
|
---|
147 | * new scoping rules
|
---|
148 | * the standard C++ library
|
---|
149 |
|
---|
150 | Do not use the following C++ features:
|
---|
151 | * dynamic_cast
|
---|
152 | * run time type information
|
---|
153 | * namespaces and using (use std:: where necessary)
|
---|
154 |
|
---|
155 | The new scoping rules say that the scope of a variable declared
|
---|
156 | in a for statement is limited to the for loop. For example:
|
---|
157 |
|
---|
158 | for (int i = 0; i < 10; ++i) {
|
---|
159 | // i is in scope here
|
---|
160 | }
|
---|
161 | // i is not in scope here
|
---|
162 |
|
---|
163 | for (int i = -10; i < 0; ++i) {
|
---|
164 | // an entirely new i is in scope here
|
---|
165 | }
|
---|
166 | // i is not in scope here
|
---|
167 |
|
---|
168 | This is used routinely in synergy, but only in for loops. There
|
---|
169 | is a macro for `for' in lib/base/common.h when building under
|
---|
170 | Microsoft Visual C++ that works around the fact that that compiler
|
---|
171 | doesn't follow the new scoping rules. Use the macro if your
|
---|
172 | compiler uses the old scoping rules.
|
---|
173 |
|
---|
174 | * Standard C++ library
|
---|
175 | The standard C++ library containers should always be used in favor
|
---|
176 | of custom containers wherever reasonable. std::string is used
|
---|
177 | throughout synergy but only as the CString typedef; always use
|
---|
178 | CString, never std::string except in the arch library. Synergy
|
---|
179 | avoids using auto_ptr due to some portability problems. Synergy
|
---|
180 | makes limited use of standard algorithms and streams but they can
|
---|
181 | be freely used in new code.
|
---|
182 |
|
---|
183 | * Limited multiple inheritance
|
---|
184 | Classes should inherit implementation from at most one superclass.
|
---|
185 | Inheriting implementation from multiple classes can have unpleasant
|
---|
186 | consequences in C++ due to it's limited capabilities. Classes can
|
---|
187 | inherit from any number of interface classes. An interface class
|
---|
188 | provides only pure virtual methods. Synergy breaks this rule in
|
---|
189 | IInterface which implements the virtual destructor for convenience.
|
---|
190 |
|
---|
191 | * No globals
|
---|
192 | Avoid global variables. All global variables must be static, making
|
---|
193 | it visible only with its source file. Most uses of global variables
|
---|
194 | are better served by static data members of a class. Global
|
---|
195 | constants are permitted in some circumstances.
|
---|
196 |
|
---|
197 | Also avoid global functions. Use public static member functions in
|
---|
198 | a class instead.
|
---|
199 |
|
---|
200 | These rules are violated by the main source file for each program
|
---|
201 | (except that the globals are still static). They could easily be
|
---|
202 | rewritten to put all the variables and functions into a class but
|
---|
203 | there's little to be gained by that.
|
---|
204 |
|
---|
205 | * Private data only
|
---|
206 | If a class is plain-old-data (i.e. it has no methods) all of its
|
---|
207 | data members should be public. Otherwise all of its data members
|
---|
208 | should be private, not public or protected. This makes it much
|
---|
209 | easier to track the use of a member when reading code. Protected
|
---|
210 | data is not allowed because `protected' is a synonym for `public
|
---|
211 | to my subclasses' and public data is a Bad Thing. While it might
|
---|
212 | seem okay in this limited situation, the situation is not at all
|
---|
213 | limited since an arbitrary number of classes can be derived,
|
---|
214 | directly or indirectly, from the class and any of those classes
|
---|
215 | have full access to the protected data.
|
---|
216 |
|
---|
217 | * Plain old data
|
---|
218 | A class that merely contains data and doesn't perform operations
|
---|
219 | on that data (other than reads and writes) is plain old data (POD).
|
---|
220 | POD should have only public data members and non-copy constructors.
|
---|
221 | It must not have any methods other than constructors, not even a
|
---|
222 | destructor or assignment operators, nor protected or private data.
|
---|
223 | Note that this definition of POD is not the definition used in the
|
---|
224 | C++ standard, which limits the contained data types to types that
|
---|
225 | have no constructors, destructors, or methods.
|
---|
226 |
|
---|
227 | * Avoid using friend
|
---|
228 | Avoid declaring friend functions or classes. They're sometimes
|
---|
229 | necessary for operator overloading. If you find it necessary to
|
---|
230 | add friends to some class C, consider creating a utility class U.
|
---|
231 | A utility class is declared as the only friend of C and provides
|
---|
232 | only static methods. Each method forwards to a private method on
|
---|
233 | an object of C type (passed as a parameter to the U's method).
|
---|
234 | This makes maintenance easier since only U has friend access to C
|
---|
235 | and finding any call to U is trivial (they're prefixed by U::).
|
---|
236 |
|
---|
237 | * Don't test for NULL when using `delete' or `delete[]'
|
---|
238 | It's unnecessary since delete does it anyway.
|
---|
239 |
|
---|
240 | - Makefiles
|
---|
241 | Automake's makefiles (named Makefile.am) have a few requirements:
|
---|
242 | * Define the following macro at the top of the file:
|
---|
243 | NULL =
|
---|
244 | * Lists should have one item per line and end in $(NULL). For
|
---|
245 | example:
|
---|
246 | EXTRA_DIST = \
|
---|
247 | kiwi.txt \
|
---|
248 | mango.cpp \
|
---|
249 | papaya.h \
|
---|
250 | $(NULL)
|
---|
251 | Indentation must use tabs in a makefile. Line continuations
|
---|
252 | (backslashes) should be aligned using tabs.
|
---|
253 | * Lists of files should be sorted alphabetically in groups (e..g
|
---|
254 | source files, header files, then other files). Lists of
|
---|
255 | subdirectories must be in the desired build order.
|
---|
256 |
|
---|
257 | - Source Formatting
|
---|
258 | Every project has its own formatting style and no style satisfies
|
---|
259 | everyone. New code should be consistent with existing code:
|
---|
260 |
|
---|
261 | * All files should include the copyright and license notice
|
---|
262 | * Use tabs to indent
|
---|
263 | * Tabs are 4 columns
|
---|
264 | * Lines should not extend past the 80th column
|
---|
265 | * Open braces ({) go on same line as introducing statement
|
---|
266 | `for (i = 0; i < 10; ++i) {' not
|
---|
267 | for (i = 0; i < 10; ++i)
|
---|
268 | {
|
---|
269 | * Close braces line up with introducing statement
|
---|
270 | * Open brace for function is on a line by itself in first column
|
---|
271 | * Close brace for function lines up with open brace
|
---|
272 | * Always use braces on: if, else, for, while, do, switch
|
---|
273 | * `else {' goes on its own line
|
---|
274 | * Always explicitly test pointers against NULL
|
---|
275 | e.g. `if (ptr == NULL)' not `if (ptr)'
|
---|
276 | * Always explicitly test integral values against 0
|
---|
277 | e.g. `if (i == 0)' not `if (i)'
|
---|
278 | * Put spaces around binary operators and after statements
|
---|
279 | e.g. `if (a == b) {' not `if(a==b){'
|
---|
280 | * C'tor initializers are one per line, indented one tab stop
|
---|
281 | * Other indentation should follow existing practice
|
---|
282 | * Use Qt style comments for extraction by doxygen (i.e. //! and /*!)
|
---|
283 | * Mark incomplete or buggy code with `FIXME'
|
---|
284 |
|
---|
285 | - Other
|
---|
286 | * calls to LOG() should always be all on one line (even past column 80)
|
---|
287 |
|
---|
288 |
|
---|
289 | Class Relationships
|
---|
290 | -------------------
|
---|
291 |
|
---|
292 | The doxygen documentation can help in understanding the relationships
|
---|
293 | between objects. Use `make doxygen' in the top level directory to
|
---|
294 | create the doxygen documentation into doc/doxygen/html. You must have
|
---|
295 | doxygen installed, of course.
|
---|
296 |
|
---|
297 | FIXME -- high level overview of class relationships
|
---|
298 |
|
---|
299 |
|
---|
300 | Portability
|
---|
301 | -----------
|
---|
302 |
|
---|
303 | Synergy is mostly platform independent code but necessarily has
|
---|
304 | platform dependent parts. The mundane platform dependent parts
|
---|
305 | come from the usual suspects: networking, multithreading, file
|
---|
306 | system, high resolution clocks, system logging, etc. Porting
|
---|
307 | these parts is relatively straightforward.
|
---|
308 |
|
---|
309 | Synergy also has more esoteric platform dependent code. The
|
---|
310 | functions for low-level event interception and insertion,
|
---|
311 | warping the cursor position, character to keyboard event
|
---|
312 | translation, clipboard manipulation, and screen saver control
|
---|
313 | are often obscure and poorly documented. Unfortunately, these
|
---|
314 | are exactly the functions synergy requires to do its magic.
|
---|
315 |
|
---|
316 | Porting synergy to a new platform requires the following steps:
|
---|
317 |
|
---|
318 | - Setting up the build
|
---|
319 | - Adjusting lib/common/common.h
|
---|
320 | - Implementing lib/arch
|
---|
321 | - Implementing lib/platform
|
---|
322 | - Tweaks
|
---|
323 |
|
---|
324 | Setting up the build:
|
---|
325 |
|
---|
326 | The first phase is simply to create the files necessary to build the
|
---|
327 | other files. On Unix, synergy uses autoconf/automake which produces
|
---|
328 | a `configure' script that generates makefiles. On Windows, synergy
|
---|
329 | uses Visual C++ workspace and project files. If you're porting to
|
---|
330 | another Unix variant, you may need to adjust `configure.in',
|
---|
331 | `acinclude.m4', and Unix flavor dependent code in lib/arch. Note
|
---|
332 | especially the SYSAPI_* and WINAPI_* macro definitions in
|
---|
333 | ARCH_CFLAGS. Exactly one of each must be defined. It should also
|
---|
334 | add AM_CONDITIONALs if a new SYSAPI_* or WINAPI_* was added.
|
---|
335 |
|
---|
336 | Adjusting lib/common/common.h:
|
---|
337 |
|
---|
338 | The lib/common/common.h header file is included directly or indirectly
|
---|
339 | by every other file. Its primary job is to include config.h, which
|
---|
340 | defines macros depending on what the 'configure' script discovered
|
---|
341 | about the system. If the platform does not use the 'configure' script
|
---|
342 | it must define the appropriate SYSAPI_* and WINAPI_* macro. It may
|
---|
343 | also do other platform specific setup.
|
---|
344 |
|
---|
345 | Adjusting lib/common/BasicTypes.h:
|
---|
346 |
|
---|
347 | No changes should be necessary in BasicTypes.h. However, if the
|
---|
348 | platform's system header files define SInt8, et al. you may need
|
---|
349 | to adjust the typedefs to match the system's definitions.
|
---|
350 |
|
---|
351 | Implementing lib/arch:
|
---|
352 |
|
---|
353 | Much platform dependent code lives in lib/arch. There are several
|
---|
354 | interface classes there and they must all be implemented for each
|
---|
355 | platform. See the interface header files for more information.
|
---|
356 |
|
---|
357 | Platforms requiring special functions should create a class named
|
---|
358 | CArchMiscXXX where XXX is the platform name. The class should have
|
---|
359 | only static methods. Clients can include the appropriate header
|
---|
360 | file and make calls directly, surrounded by a suitable #ifdef/#endif.
|
---|
361 |
|
---|
362 | If using automake, the Makefile.am should list the system specific
|
---|
363 | files in a XXX_SOURCE_FILES macro where XXX matches the appropriate
|
---|
364 | AM_CONDITIONAL symbol. XXX_SOURCE_FILES must be added to EXTRA_DIST
|
---|
365 | and the following added above the INCLUDES macro:
|
---|
366 |
|
---|
367 | if XXX
|
---|
368 | libarch_a_SOURCES = \
|
---|
369 | $(COMMON_SOURCE_FILES) \
|
---|
370 | $(XXX_SOURCE_FILES) \
|
---|
371 | $(NULL)
|
---|
372 | endif
|
---|
373 |
|
---|
374 | Implementing lib/platform:
|
---|
375 |
|
---|
376 | Most of the remaining platform dependent code lives in lib/platform.
|
---|
377 | The code there implements platform dependent window, clipboard, keyboard
|
---|
378 | and screen saver handling. If a platform is named XXX then the following
|
---|
379 | classes should be derived and implemented:
|
---|
380 |
|
---|
381 | * CXXXClipboard : IClipboard
|
---|
382 | Provides clipboard operations. Typically, this class will
|
---|
383 | have helper classes for converting between various clipboard
|
---|
384 | data formats.
|
---|
385 |
|
---|
386 | * CXXXEventQueueBuffer : IEventQueueBuffer
|
---|
387 | Provides operations for waiting for, posting and retrieving events.
|
---|
388 | Also provides operations for creating and deleting timers.
|
---|
389 |
|
---|
390 | * CXXXKeyState : CKeyState
|
---|
391 | Provides operations for synthesizing key events and for mapping a
|
---|
392 | key ID to a sequence of events to generate that key.
|
---|
393 |
|
---|
394 | * CXXXScreen : IScreen, IPrimaryScreen, ISecondaryScreen, IPlatformScreen
|
---|
395 | Provides screen operations.
|
---|
396 |
|
---|
397 | * CXXXScreenSaver : IScreenSaver
|
---|
398 | Provides screen saver operations.
|
---|
399 |
|
---|
400 | If using automake, the Makefile.am should list the window system
|
---|
401 | specific files in a XXX_SOURCE_FILES macro where XXX matches the
|
---|
402 | appropriate AM_CONDITIONAL symbol. XXX_SOURCE_FILES must be added
|
---|
403 | to EXTRA_DIST and the following added above the INCLUDES macro:
|
---|
404 |
|
---|
405 | if XXX
|
---|
406 | libplatform_a_SOURCES = $(XXX_SOURCE_FILES)
|
---|
407 | endif
|
---|
408 |
|
---|
409 | Tweaks:
|
---|
410 |
|
---|
411 | Finally, each platform typically requires various adjustments here
|
---|
412 | and there. In particular, synergyc.cpp and synergys.cpp usually
|
---|
413 | require platform dependent code for the main entry point, parsing
|
---|
414 | arguments, and reporting errors. Also, some platforms may benefit
|
---|
415 | from a graphical user interface front end. These are generally
|
---|
416 | not portable and synergy doesn't provide any infrastructure for
|
---|
417 | the code common to any platform, though it may do so someday.
|
---|
418 | There is, however, an implementation of a GUI front end for Windows
|
---|
419 | that serves as an example.
|
---|