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