From http://www.jwz.org/xscreensaver/xscreensaver-5.39.tar.gz
[xscreensaver] / README.hacking
1
2 ==========================================================================
3
4                      Writing new XScreenSaver modules
5
6 ==========================================================================
7
8 Any program that can be made to render on an X window created by another
9 process can be used as a screen saver.  Just get the window ID out of
10 $XSCREENSAVER_WINDOW, draw on that, and you're done.
11
12 In theory, you can write a screen saver in any language you like.  In
13 practice, however, languages other than C or C++ tend not to allow you to
14 draw to windows that they did not create themselves.  Unfortunately, this
15 means that if you want to write a screen saver, you must write it in C.
16
17 Given that you're going to be writing in C, you might as well take
18 advantage of the various utility functions that I have written to make
19 that easier.  Writing a new screen saver in C using the frameworks
20 included with xscreensaver simplifies things enormously.
21
22 Generally, the best way to learn how to do something is to find a similar
23 program, and play around with it until you understand it.  Another
24 approach is to not worry about understanding it, but to just hack it out.
25 Either way, your best bet is probably to start with one of the existing
26 xscreensaver demos, included in the "hacks/" directory, rename the file,
27 and edit it until it does what you want.
28
29 The "Greynetic" and "Deluxe" hacks are probably good ones to start with,
30 since they are so very simple.  For OpenGL programs, "DangerBall" is a
31 good example.
32
33
34 ==========================================================================
35 Requirements for inclusion with the XScreenSaver collection
36 ==========================================================================
37
38   If you come up with anything, send it to me!  If it's good, I'd love to
39   include it in the xscreensaver distribution.  However, there are a few
40   requirements for me to distribute it:
41
42   - Write in portable ANSI C.  No C++.  No nonstandard libraries.
43
44   - Write a .man page describing all command-line options.
45
46   - Write an .xml file describing the graphical configuration dialog box.
47
48   - Include a BSD-like copyright/license notice at the top of each source
49     file (preferably, just use the one from "screenhack.h", and include
50     your name and the current year).  The GNU GPL is not compatible with
51     the rest of XScreenSaver.
52
53
54 ==========================================================================
55 The XScreenSaver API
56 ==========================================================================
57
58   - Start with #include "screenhack.h"
59
60   - Define 2 global variables:
61
62       yoursavername_defaults -- Default values for the resources you use.
63       yoursavername_options  -- The command-line options you accept.
64
65   - Define 5 functions:
66
67       yoursavername_init     -- Return an object holding your global state.
68       yoursavername_draw     -- Draw a single frame, quickly.
69       yoursavername_free     -- Free everything you've allocated.
70       yoursavername_reshape  -- Called when the window is resized.
71       yoursavername_event    -- Called when a keyboard or mouse event happens.
72
73       The "event" function will only be called when running in a window
74       (not as a screen saver).  The "reshape" event will be called when the
75       window size changes, or (as a screen saver) when the display size
76       changes as a result of a RANDR event (e.g., plugging in a new monitor).
77
78       It's ok for both the "event" and "resize" functions to do nothing.
79
80   - All other functions should be static.
81
82   - The last line of the file should be 
83     XSCREENSAVER_MODULE ("YourSaverName", yoursavername)
84
85   - Finally, edit the Makefile to add a rule for your program.
86     Just cut-and-paste one of the existing rules.
87
88   Your "draw" must not run for more than a fraction of a second without
89   returning.  This means "don't call usleep()".  Everything has to be a
90   state machine.
91
92   You may not store global state in global variables, or in function-local
93   static variables.  All of your runtime state must be encapsulted in the
94   "state" object created by your "init" function.  If you use global or
95   static variables, your screen saver will not work properly on macOS.
96
97   Do not call XSync() or XFlush().  If you think you need to do that, it
98   probably means that you are you are relying on the speed of the graphics
99   card for timing, which probably means that your "draw" function is
100   taking too long.
101
102
103 ==========================================================================
104 The xlockmore API
105 ==========================================================================
106
107   Some of the display modes that come with xscreensaver were ported from
108   xlock, and so, for historical reasons, they follow a slightly different
109   programming convention.  For newly-written Xlib programs, you'd be
110   better off following the pattern used in hacks like "Deluxe" than in
111   hacks like "Flag".  The xlockmore ones are the ones that begin with
112   "#ifdef STANDALONE" and #include "xlockmore.h".
113
114   But, all OpenGL screen savers have to follow the xlockmore API.
115
116   The xlockmore API is similar to the XScreenSaver API, in that you define
117   (roughly) the same set of functions, but the naming conventions are
118   slightly different.  Instead of "hackname_init", it's "init_hackname",
119   and it should be preceeded with the pseudo-declaration ENTRYPOINT.
120
121   One annoying mis-feature of the xlockmore API is that it *requires* you
122   to make use of global variables for two things: first, for each of your
123   command line options; and second, for an array that holds your global
124   state objects.  These are the only exceptions to the "never use global
125   variables" rule.
126
127   There are a few important differences between the original xlockmore API
128   and XScreenSaver's implementation:
129
130   - XScreenSaver does not use refresh_hackname or change_hackname.
131
132   - XScreenSaver provides two additional hooks not present in xlockmore:
133     reshape_hackname, and hackname_handle_event. These are respectively
134     equivalent to hackname_reshape and hackname_event in the XScreenSaver
135     API.
136
137   - Under Xlib, MI_CLEARWINDOW doesn't clear the window immediately.
138     Instead, due to double buffering on macOS/iOS/Android, it waits until
139     after init_hackname or draw_hackname returns before clearing. Make
140     sure not to issue any Xlib drawing calls immediately after a call to
141     MI_CLEARWINDOW, as these will be erased. To clear the window
142     immediately, just use XClearWindow.
143
144
145 ==========================================================================
146 Programming Tips
147 ==========================================================================  
148
149   - Your screen saver should look reasonable at 20-30 frames per second.
150     That is, do not assume that your "draw" function will be called more
151     than 20 times a second.  Even if you return a smaller requested delay
152     than that, you might not get it.  Likewise, if your "draw" function
153     takes longer than 1/20th of a second to run, your screen saver may be
154     consuming too much CPU.
155
156   - Don't make assumptions about the depth of the display, or whether it
157     is colormapped.  You must allocate all your colors explicitly: do not
158     assume you can construct an RGB value and use that as a pixel value
159     directly.  In particular, you can't make assumptions about whether
160     pixels are RGB, RGBA, ARGB, ABGR, or even whether they are 32, 24,
161     16 or 8 bits.  Use the utility routines provided by "utils/colors.h"
162     to simplify color allocation.
163
164   - It is better to eliminate flicker by double-buffering to a Pixmap
165     than by erasing and re-drawing objects.  Do not use drawing tricks
166     involving XOR.
167
168   - If you use double-buffering, have a resource to turn it off. (MacOS,
169     iOS and Android have double-buffering built in, so you'd end up
170     triple-buffering.)
171
172   - Understand the differences between Pixmaps and XImages, and keep in
173     mind which operations are happening in client memory and which are in
174     server memory, and which cause latency due to server round-trips.
175     Sometimes using the Shared Memory extension can be helpful, but
176     probably not as often as you might think.
177
178   - On modern machines, OpenGL will always run faster than Xlib.  It's
179     also more portable.  Consider writing in OpenGL whenever possible.
180
181
182 ==========================================================================
183 macOS, iOS and Android
184 ==========================================================================
185
186   Though XScreenSaver started its life as an X11 program, it also now runs
187   on macOS, iOS and Android, due to a maniacal collection of compatibility
188   shims.  If you do your development on an X11 system, and follow the
189   usual XScreenSaver APIs, you shouldn't need to do anything special for
190   it to also work on macOS and on phones.
191
192   See the READMEs in the OSX/ and android/ directories for instructions on
193   compiling for those platforms.
194
195   To check that an X11 saver will fit well on a mobile device, test it
196   with -geometry 640x1136 and 640x960.  That's a good first step, anyway.
197
198 ==========================================================================