1= f.functions
2
3This document will describe how functions get written and dispatched.  It
4should be a useful reference when you intend to add a new function, or
5understand how the code works.
6
7
8== Document Conventions
9
10Unless otherwise stated, most mentions of "`f.function`" (in singular or
11plural) are meant to be generic references to any `f.anything` that ctwm
12implements, rather than specifically the `f.function` function.  This is
13done because just calling them "`functions`" can be ambiguous, especially
14when talking about the implementation, because the implementation of a
15ctwm _function_ is done in terms of a C _function_, so there's often
16opportunity for terminological confusion.
17
18
19== Functional Considerations
20
21There are a few choices in the way functions work to consider in any
22given case.
23
24[[func-arguments,Arguments]]
25=== Arguments
26
27Some functions take an argument, while others don't.  For example, the
28case of <<example-gotoworkspace>> as described below takes an argument,
29so you'd have something like `f.gotoworkspace "one"` in a key binding or
30menu.  Contrarily, <<example-identify>> doesn't, so you'd merely have
31`f.identify` in the config.
32
33This is controlled by a column in the `functions_defs.list` file; see
34below where the <<impl-functions-defs-sections>> are discussed.
35
36[[cons-deferral,Deferral]]
37=== Deferral
38
39There is also a concept of _function deferral_.  This happens in the case
40of f.functions that in some way target a window (`f.move` and friends,
41`f.resize`, `f.occupy`, and a great many others).  When you activate them
42from a mouse/key binding or titlebar icon or the like, ctwm can see which
43window you're pointing at, and targets it from there.  However, when run
44from a menu, you can't be pointing at a window; you're pointing at the
45menu.
46
47As a result, ctwm _defers_ the execution of the f.function.  It changes
48the mouse cursor to something to prod the user, and waits for you to
49click on a window.  _Then_ it runs back into the function execution to
50actually to the work.
51
52So any f.function that has to do something related to a window has to be
53setup to defer, or it won't work from a menu.  This is also controlled in
54`functions_defs.list`; x-ref the description of the
55<<impl-functions-defs-sections>>.  The right cursor for any given case is
56a matter of judgement, but generally move/resize actions have one cursor
57(the `DC_MOVE` choice), and other functions use the other (`DC_SELECT`).
58
59=== Magic and Internal
60
61There are a few "`synthetic`" or "`internal`" f.functions, which exist
62only to link up some magic like the `TwmWindows` auto-generated menu.
63Unless you're working with magic menus, you never need to go near or know
64anything about them.
65
66There are also two somewhat magical f.functions.  One is `f.function`
67which runs a user-defined function, which is a sequence of other existing
68functions.  This is commonly used in conjunction with the other magical
69function, `f.deltastop`, to let you do stuff to a window that varies
70depending on whether you move the mouse or not.  See the user manual for
71details of them.  They get executed slightly differently than other
72functions; see the <<impl-dispatch>> section below for details.
73
74
75== Implementation Overview
76
77Much over the overall control for dispatching and finding f.functions is
78done via generated code, from the definitions in `functions_def.list`.
79f.function execution begins by calling into the `ExecuteFunction()`
80function from various places (usually event handlers for menu selections
81or mouse/key bindings, but there are a few other ways).  There it uses
82various of the autogenerated bits to look up what sort of deferral or
83other magic it might do, and then falls down into individual C functions
84for implementing each ctwm f.function.
85
86=== `functions_defs.list` and autogenerated controls.
87
88As part of the build process, `tools/mk_function_bits.sh` builds various
89generated header files (_i.e._, `build/functions_*.h`) from the
90`functions_defs.list` file.  Comments in that file give a good reference
91to the details of the syntax.  We'll skim the higher-level overview here.
92
93[[impl-functions-defs-sections,functions_defs.list sections]]
94==== Sections
95
96There are 3 sections in the file, delineated by comments like
97`#START(section)` and `#END(section)`; these are used as markers by the
98`mk_function_bits.sh` script to find the bits it needs at any given time.
99
100The `aliases` and `synthetic` section are almost certainly not anything
101you need to touch.  `aliases` are alternate names for f.functions.  Those
102that exist are historical, and we should probably avoid adding any new
103ones; just name a function what it should be named, and don't add
104confusion by having multiple names.  `synthetic` are f.functions not
105exposed to the user (_i.e._, not available in config files) but get
106called from things like the magic `TwmWindow` menu.  Both are very
107special cases, so unless you're doing something very unusual, you'll
108never go near them.
109
110The `main` section is where you'll be playing.  It contains space
111delimited columns (mostly visually lined up in the file for convenience;
112the script only cares about whitespace).  First is the name; obvious.
113Second determines whether it's a f.function that takes an argument (like
114<<example-gotoworkspace>> below) or one that doesn't.
115
116The third column defines the deferral cursor; this has the side effect of
117determining whether it's a deferred f.function or not; see discussion of
118<<cons-deferral>> above.  And the fourth allows hiding info about the
119function behind an #ifdef.  The only current use of that is for the
120rplay-based sound support, and it should probably be avoided for new
121functions.  Generally, the function should be available all the time, and
122just do nothing (or beep, or something appropriate) when the conditional
123code isn't available.  This saves users from some complication in writing
124their config files.
125
126==== Generated Files
127
128From that, `mk_function_bits.sh` generates header files that contain the
129various info about the f.functions.
130
131* One file contains the ``#define``'s for all the `F_WHATEVER` contants
132used in the code to refer to the f.functions internally.  This only
133really needs the names.
134
135* It also generates the `funckeytable` lookup table the config file
136parser (in `parse_keyword()`) uses to look up the functions referred to
137in the config table.  This needs the second column to distinguish
138functions taking argument from those that don't.  It also uses bits from
139the `aliases` section, since we need to parse those names when give (and
140treat them the same as the real f.function names).
141
142* It generates the `fdef_table` lookup table which is used in the
143f.function execution (in `EF_main()`) to determine whether to defer
144calling the function, and what X cursor to set when it defers.  This uses
145the third column (and only includes f.functions that have something
146there).  See earlier discussion of <<cons-deferral>>.
147
148* And finally, it generates the `func_dispatch` table used in `EF_main()`
149to dispatch the actual execution of the f.function to the underlying C
150function that implements it.  This is just built off the names.
151
152[[impl-dispatch,Function Dispatching]]
153=== Dispatching and Executing
154
155Some mechanism (usually invocation from menu or button/key binding) calls
156some f.function.  This calls into `ExecuteFunction()` to do the
157dispatching, which is just an external thunk into `EF_main()`.  This
158checks the environment and the `fdef_table` we generated to determine
159whether the function should be deferred; if so, it sets the deferral
160cursor and returns.  Actual execution then happens via another fresh call
161into `ExecuteFunction()` via slightly creepy magic in the `ButtonPress`
162event handling code.  You don't want to know.
163
164Then it falls into actually dispatching the f.function.  There are two
165special cases described below.  Most f.functions simply run through to an
166individual C function that implements them, via the `func_dispatch` table
167and specific naming; the implemetation of the ctwm function `f.abcdef`
168will be in the C function `f_abcdef_impl()`.
169
170The two special cases revolve around the `f.function` construction which
171allows user creation of ctwm functions that alias or chain multiple other
172f.functions (x-ref `Function` keyword in the user name).  The first is
173`f.function` itself, which loops over the list of things the user told it
174to do and recurses back into `EF_main()` for them.  The second is the
175magic `f.deltastop` (which is only meaningful as part of a
176``f.function``'s chain), which checks its magic and returns a value from
177`EF_main()` to tell the calling `f.function` invocation to stop where it
178is instead of proceeding.  _This is the only use of ``EF_main()``'s
179return value_.
180
181
182== Implementating A Function
183
184Most of the work of implementing a new f.function should be whatever code
185you actually need to write to _do_ what the function is supposed to do.
186We want to minimize the boilerplate you need to do to hook it up.
187
188Generally, you only need to do two things:
189
190. Add it to the `main` section of the `functions_defs.list` file, with
191whatever options are appropriate.  The build system will notice the
192change and add it to the generated files next time you build.  Then it's
193ready to be parsed from a config file and executed at runtime.  Note that
194this will cause a compile failure until you also
195
196. Create the implementation in the appropriately named C function.  The
197`DFHANDLER()` macro exists to set the right name and argument list; use
198it instead of trying to do it manually.  Even an empty function will be
199enough to satify the compiler and get you running.
200
201=== Internal Macros And Details
202
203The `functions_internal.h` file contains a few macros used in defining
204and calling f.function implementations, the prototypes for all those
205implementations, and a few other bits that get shared among the
206`function_*.c` implementation files.
207
208`EF_FULLPROTO` gives the full list of arguments that `ExecuteFunction()`
209and all the f.function handlers takes.  It's also used in some backend
210functions the handlers call.  Commonly these are cases where several
211functions act almost identically, and so just thunk through to a shared
212backend function; _e.g._, how all of `f.move`, `f.forcemove`,
213`f.movepack`, and `f.movepush` merely call `movewindow()` in
214`functions_win_moveresize.c`.  The `EF_ARGS` macro is the same set of
215arguments, just in the form of the names as you'd use in calling the
216function; you can see its usage in those same cases.
217
218The `DFHANDLER()` macro is used in **D**efining a **F**unction
219**HANDLER**.  It's used in both the prototypes in `functions_internal.h`
220and in all the implementations in the `functions_*.c` files.  By just
221calling it with the function name, we can automate away making sure the
222implementation is named correctly so the generated `func_dispatch` table
223can find them in the dispatch (x-ref <<impl-dispatch>>), and that it
224takes the right args.  Along with the mentioned `EF_*` macros, that will
225save us a lot of trouble visiting hundreds of places if/when we change
226the set of args we pass around function execution and handlers.
227
228
229== Implementation Examples
230
231[[example-identify,f.identify]]
232=== `f.identify` and `f.version`
233
234`f.version` pops up a window with info about the ctwm build and version.
235`f.identify` pops up a window with information about a given window,
236which has also all that `f.version` information up top.  So they can be
237considered variants of the same thing.  And in fact, they both wind up
238implemented by the same code on the backend.
239
240So, to trace from the top, we find the `version` and `identify` lines in
241the `main` section of `functions_defs.list`.  The `version` line has
242nothing in the other 3 fields; it takes no argument, and since it doesn't
243target a window it doesn't need any deferral.  `identify` also takes no
244argument, but _does_ target a window, so it needs to be deferred; the
245`CS` entry means we're using the "`select`" style cursor.  From that
246file, the various lookup arrays for deferring and dispatching get
247autogenerated.
248
249The implementations are in `functions_identify.c`.  As with all
250functions, the `DFHANDLER()` macro is used to name the function and
251arguments.  Each of those implementations just calls the `Identify()`
252backend function for the implementation; `f.identify` passes the
253targetted window (the `tmp_win` argument to the handler), while
254`f.version` passes `NULL`.  `Identify()` then builds the window with the
255ctwm version/build info, and then the window info if it were given one.
256
257[[example-gotoworkspace,f.gotoworkspace]]
258=== `f.gotoworkspace`
259
260`f.gotoworkspace` warps you to a named workspace, so it takes an
261argument.  See discussion in <<func-arguments>> above.  So we see in its
262line in `functions_defs.list` that it has an `S` in the first field,
263indicating it's taking a string argument (the only choice other than the
264stand-in `-` for functions not taking args).
265
266The implementation in `functions_workspaces.c` is then a fairly thin
267wrapper around the existing `GotoWorkSpaceByName()` function used
268elsewhere.  The `action` argument to the handler contains the value of
269the argument given in the config file, which in the case is a string of
270the name of the workspace, and `GotoWorkSpaceByName()` does its thing.
271