1= CTWM PRINCIPLES OF OPERATION
2Olaf 'Rhialto' Seibert <rhialto@falu.nl>
3
4This document briefly explains some of the internal workings of ctwm.
5
6== Screens ==
7
8Every X server may serve multiple screens, and ctwm can manage them all
9at once from a single instance. In practice, this does not happen often.
10Furthermore, in ctwm's code you see this only in a few places; it is
11hidden in quite a few more. Each screen can have its own configuration
12file: `$HOME/.ctwmrc.<screen number>`.
13
14At the start of the event handler, the screen for the current event is
15determined. That is stored in the global variable `Scr`. Everything that
16uses `Scr` is properly separated for the different screens.
17
18== Workspaces ==
19
20The idea of workspaces is that every window has a bitfield called
21`occupation` which indicates in which workspaces it should be visible.
22
23If a window's occupation changes, or if the user switches the current
24workspace, the visibility of windows needs to be adjusted.
25All windows actually "`exist`" at all times (they are not destroyed), but
26the ones that are not to be visible are unmapped. When switching
27workspaces or occupation, some windows will be unmapped and others will
28be remapped.
29
30Because windows are merely unmapped when invisible (and not destroyed),
31they remain in the _window stack_. In other words they retain their
32_stacking order_ which is the order in which they are front-to-back.
33There is only a single stacking order for all workspaces, even though it
34seems that every workspace has its own. Each workspace really just shows
35a subset of the global stacking order.
36
37Because of the unmapping, all windows can keep the same root window as
38their parent.
39
40=== The Occupation Window ===
41
42There is a single _Occupation Window_ for each Screen, which is used
43every time the `f.occupy` function is invoked.
44The Occupation Window is reparented and moved every time it is needed.
45If it is already mapped, and `f.occupy` is invoked again, the invocation
46fails. This makes it impossible for the user to manipulate the
47occupation of the occupation window in this way.
48
49=== The Workspace Manager Window ===
50
51Each _Virtual Screen_ has a separate _Workspace Manager Window_.
52By default it has _full occupation_, i.e. it is visible in all
53workspaces.
54You can change its occupation if you wish.
55
56This window is filled by asking the X server for the stacking order
57with `XQueryTree()`. Now that we have _OTP_ (see later), this should be
58used instead.
59
60== On Top Priority ==
61
62After version 3.8.2, _OTP_ (OnTopPriority) was added. This allows the
63user to select a priority for each window. Windows of lower priority can
64never get on top of a window of higher priority.
65
66To administrate this, the _OTP_  module aims to keep a private
67representation of a somewhat idealized single window stack.  This
68clashes with reality somewhat, as will become clear in other sections.
69
70To check if the internalized single window stack matches the X server's
71idea of the stack, there are regular consistency checks. If the _OTP_
72stack doesn't match, ctwm aborts.
73This should possibly be relaxed before a full release.
74
75== Window boxes ==
76
77Windows that are inside a box are not children of the root window.
78Therefore they are not in its stacking order either.  But they must fit
79somewhere in OTP's illusion of the global stacking order.
80The solution for that is that windows in a box are thought to be
81directly on top of their box.
82
83In the _OTP_ consistency checking, the windows in a box are special-cased.
84They are not checked to be in proper order in the stacking order because
85they are not in the stacking order at all.
86
87If they were not ignored in this way, they would cause false alarms
88about the OWL list being incorrect.
89
90== Virtual Screens ==
91
92At some point, X servers started to be able to present multiple monitors
93as a single screen. This is the so-called Xinerama extension (or
94nowadays XRandR).  However, people often still want to have some
95separation between their monitors. Thus, Virtual Screens were invented
96in ctwm.
97
98Ctwm's Virtual Screens (_vscreen_, or _vs_) work best if your monitors are
99the same size.  What they do is allow you to show one workspace on one
100screen, and another workspace on the other. You can switch workspaces
101independently (with some small limitations).
102
103To make each virtual screen independent of the others (for example, each
104one needs their own coordinate system starting at (0,0)), a separate
105virtual root window is created for each virtual screen. Each monitor
106then is associated with one of the virtual screens (and their root
107window). In your configuration you must give the geometry such that the
108_vscreens_ match the monitors.
109
110X has the important property that the windows form a strict tree: a
111window can have only a single parent, and it can't be added twice to the
112same parent either.
113
114Because of that, you can't view the same workspace on two virtual
115screens, for that would show its windows twice. Moreover, windows that
116occupy multiple workspaces can also be visible once only, in a single
117_vscreen_.  If multiple visibility is about to happen, a single
118_vscreen_ is chosen to show the window. If a window is hidden from one
119_vscreen_, it might be possible to then show it on another.
120
121If a window was first shown on one _vscreen_, and later on another, it
122needs to be reparented from one root window to another. This is done
123lazily.
124
125Ctwm administrates this with the `TwmWin.vs` and `TwmWin.parent_vs`.
126`parent_vs` indicates the current parent virtual root window. Because a
127window always has a parent, this can never be `NULL`.
128`TwmWin.vs` indicates the virtual screen where it is visible. This may be
129`NULL`, if the window has no occupation in (the workspace currently shown
130in) the virtual screen. If it is not `NULL`, it must equal `.parent_vs`.
131(So `.vs` could be replaced with a boolean in most places)
132
133Note that most of ctwm's code still assumes there is a single window
134stack for all windows, but with the virtual screens this is not true
135any more! Each virtual root window has its own window stack.
136
137What is true, for each separate _vscreen_, is that if you select from
138ctwm's global stack those windows that are actually parented in that
139vscreen, that selection corresponds to the _vscreen_'s window stack.
140
141In effect, the various _vscreen_'s window stacks are potentially
142interlaced like several packs of cards. Depending on "where you are",
143you must ignore the "wrong" windows in it.
144
145== Icon Managers ==
146
147=== Let's start with the one-workspace case. ===
148
149In the `.ctwmrc` you can specify multiple icon managers, and which
150windows will be placed in them. Let's call them the primary `IconMgr`
151and secondary ``IconMgr``s.  There is nothing stopping you from
152specifying them so, that one window might appear in multiple icon
153managers, but it will only go into the first one that matches.
154
155`ScreenInfo.iconmgr` (`Scr->iconmgr`) points to the primary icon manager.
156The secondary ones are linked to it via `IconMgr.next` and `.prev`.
157
158So each window occurs in a single icon manager: it has a little
159sub-window in it.
160The sub-window is represented by a `WList`.
161`twm_win->iconmanagerlist` points to the `WList` for the window.
162
163The various `WLists` that are in the same iconmanager are linked via
164`WList.next` and `.prev`.
165
166.Undiscovered:
167- `IconMgr.lasti`
168- how `IconMgr.first` `.last` `.active` (``WList``s) are related to the
169  pointers from the windows
170
171=== Expand to multiple workspaces. ===
172
173The Icon Managers are different windows in each workspace: it is not
174just a single window with multiple occupation. This is so that you
175can move it where you want in each of them.
176(Personally I would probably have used a single window and moved it
177around to remembered locations in each workspace)
178
179So both the `IconMgr` and the ``WList``s are replicated for each
180workspace.  These instances are linked via `IconMgr.nextv` and
181`WList.nextv`.
182
183The replicated instances are created after the first `IconMgr`, in
184`AllocateOtherIconManagers()`.
185
186If we believe `CreateIconManagers()`, then from the primary `IconMgr`
187for workspace #0 (`Scr->iconmgr`), you can follow `->nextv` to get to the
188replicas for workspace #1, #2, ..., and from each of those, follow
189`->next` to get to the secondary ``IconMgr``s for the same workspace.
190But the replication function is confusing.
191
192On the other hand, in `AddIconManager()`, a primary or secondary
193`IconMgr` is selected from workspace #0, and then `->nextv` is
194followed to find each of the replicas.
195
196`WorkSpace.iconmgr` points to the primary _Icon Manager_ that belongs to
197that workspace.
198
199In `GotoWorkspace()`, there is a "`reorganisation`" of ``WList``s.
200I am not 100% sure what that means.
201Probably it is doing the job that more logically should be done in
202`ChangeOccupation()`, but lazily: put windows (``WList``s) in icon
203managers and take them out, depending on their occupation.
204
205== Icons ==
206
207Icons consist of several parts. Some of them can come from different sources
208or be shared among windows.
209
210* `struct Icon`, which refers to
211** `struct Image`, which contains
212*** X `Pixmap`(s) for image and optionally shape
213** X `Window` to place the `Pixmap`(s) in
214
215Each `TwmWindow` may have a `struct Icon` which describes the currently
216associated icon. Icons may change, if the title matches different images
217from the Icon list over time:
218
219--------------------
220Icons
221{
222     "XTerm"   "xpm:xterm"
223     "* - VIM" "xpm:vim"
224}
225--------------------
226
227``Image``s that are loaded from an xpm or other file are stored as
228`struct Image` and cached in a global cache named `Scr->ImageCache`.
229Therefore they can be shared. The source of an `Image` is recorded in
230`Icon->match` and can have the values `match_none`, `match_list`,
231`match_icon_pixmap_hint`, `match_net_wm_icon`, `match_unknown_default`.
232
233match_list::
234If a window changes icons like this (Vim changes the terminal window's
235title when it starts up), it stores old icons on `TwmWin->iconslist` for
236later re-use. It must be certain that all these ``Image``s are indeed
237from the cache and not from other sources, otherwise there may be a
238memory leak or use-after-free.  The `iconslist` is freed when a window
239is freed, but the ``Image``s it points to are left alone.
240footnote:[A different implementation would allow ``Image``s from any
241source on the `iconslist` and check their source when freeing the list.]
242
243match_icon_pixmap_hint::
244Another source of `struct Image` is the Pixmap(s) that are given in the
245`WM_HINTS` property. These are not shared.
246
247match_net_wm_icon::
248The image is specified in the `_NET_WM_ICON` property. These `struct
249Images` are also not shared. Usually there are icons of different sizes.
250The user can specify the desired size (width * height). If an exact
251match is not found, the closest match is taken. This is based on
252the area (total number of pixels) of the icon. The differences are
253compared proportionally: the specified size times 2 is closer than
254the size divided by 3.
255
256match_unknown_default::
257Finally there is a default `Image`, which is shared among all windows
258where needed.
259
260Usually ctwm creates the window to display the icon itself, but again
261there may be one given in the `WM_HINTS`. If so, this window must not be
262destroyed.
263
264
265// vim:ft=asciidoc:expandtab:
266// Gen:
267//  asciidoc -atoc -anumbered -o PRINCIPLES-OF-OPERATION.html PRINCIPLES-OF-OPERATION.txt
268
269