source: doc/owl-window.txt @ e2cc848

release-1.7release-1.8release-1.9
Last change on this file since e2cc848 was 95d54e6, checked in by David Benjamin <davidben@mit.edu>, 11 years ago
Document the glib function casts
  • Property mode set to 100644
File size: 8.1 KB
Line 
1                                ==========
2                                owl_window
3                                ==========
4
5owl_window is intended to be a wrapper over ncurses WINDOW and PANEL
6objects to abstract away much of the nastiness that is ncurses. It
7provides redraw scheduling, and sane window moving and resizing.
8
9-------------------
10Hierarchy and types
11-------------------
12
13owl_window creates a hierarchy of window objects. The hierarchy
14currently uses ncurses' built-in window hierarchy system with
15subwins. This was easier to implement but has some caveats, detailed
16later.
17
18At the top level, we have the screen window which represents the
19actual screen. The screen window is not usually interacted with
20directly, but rather it is a handle to interface with the terminal as
21if it were a normal window.
22
23Underneath the screen, we have top-level windows, or panels. Panels
24are normal WINDOWs (newwin) connected to a PANEL (from
25libpanel). Panels may overlap freely and maintain a stacking
26order. (For now, this stacking order is not exposed except for a
27mechanism to move a panel to the top. This is not difficult to
28otherwise correct otherwise.)
29
30Under each panel is a tree of subwins. These are backed by ncurses
31subwins. Because ncurses subwins simply share their parent windows'
32buffer, we cannot provide as many nice guarantees about
33ordering. Sibling subwins may not overlap, and parents must
34(sometimes) take children position into account. More on this
35later. This model is sufficient for BarnOwl's current purposes. Should
36we need to, this may later be reworked. (Specifically, we'd want to
37back everything by pads and build a compositing window manager.)
38
39Each of these three types is temporarily stuffed into one type. We can
40later do subtyping of sorts, but that will require more heavy use of
41GObject.
42
43As an example, here is the graph used by BarnOwl's current interface:
44
45                        +==========+
46                        || screen ||
47                        +==========+
48                          /      \
49                +-----------+   +--------+
50                | mainpanel |   | popwin |
51                +-----------+   +--------+
52               /   /    |    \          \
53         recwin sepwin msgwin typwin   viewwin
54
55
56A window may be unlinked from its parent with a call to
57owl_window_unlink. From then on, the object is still accessible, but
58it will not do anything. If desired, we may add the ability to relink
59a window in future. This behavior allows us to safely hold references
60to windows, even after they have been "destroyed".
61
62----------
63Visibility
64----------
65
66Each window maintains state for whether or not the user has requested
67it be visible. A user calls owl_window_show to flip the 'shown' bit on
68a window and owl_window_show_all to do so recursively. Likewise,
69owl_window_hide disables this bit. If a window and all its parents are
70shown, then the user has requested this window be visible.
71
72We say a window is realized if it has a corresponding on-screen
73window. A window will only be realized if it is requested to be
74shown. Furthermore, the window's parent must also be realized (unless
75it is the screen). If a window is failed to be created for any reason
76(most notably if its dimensions are zero), owl_window will cope and
77consider it unrealized.
78
79This realized/unrealized state fixes two nuisances with the old code:
80
81     First, owl_window can safely manage all NULL windows. Interacting
82     code needn't check to avoid segfaults; the owl_window is never
83     NULL, and code requesting the WINDOW will never be called when
84     NULL.
85
86     Second, we have a consistent handle to a logical window, despite
87     changes in the physical window. This is important for resizing
88     windows. It is difficult to safely resize windows in ncurses. It
89     is usually far easier to destroy everything and recreate it.
90
91Note that this means owl_window will intentionally never expose the
92underlying WINDOW except during appropriate events.
93
94--------
95Resizing
96--------
97
98Windows may be moved and resized with owl_window_move,
99owl_window_resize, and owl_window_set_position. Internally, resizing
100is very simple. We unrealize the window, set new position, and then
101realize it at the new location. When a window changes size, it emits a
102"resized" signal which windows may react to. It may actually possible
103to optimize moves, but this has a slight nuisance with incorrect
104begy/begx values which cursors currently rely on.
105
106It is intended that top-level windows connect to this signal to change
107themselves, while windows containing subwins connect to their own
108signals to relayout their subwins. This is because top-level windows
109may be sized independently, while sibling subwins should not
110overlap. The signals are implemented currently with GObject signals.
111
112---------
113Redrawing
114---------
115
116Currently, users of widgets in BarnOwl must remember to call
117owl_foo_redisplay when a widget needs to be redrawn. This is quite
118annoying and an implementation detail that functions like
119owl_editwin_insert_string should take care of. To allow widget
120implementations to redraw themselves without calling an expensive
121redisplay many times, owl_window_dirty flags a window as "dirty". The
122framework will promise to redraw that window before the next doupdate,
123while repeated owl_window_dirty calls remain cheap.
124
125Windows currently redraw with a "redraw" GObject signal. This and the
126resize signal, is somewhat awkward for the editwin which attaches to
127and releases windows, as we must remember signal ids. However, if we
128make widget objects (owl_editwin, owl_mainwin, etc.) also GObjects,
129these signals will automatically detach. We may also consider a
130different mechanism than continuously attaching/detaching
131things. That's kinda weird anyway.
132
133(We may want to replace it with a normal callback at some
134point. Mostly using the GObject signals to play with them, and because
135we'd likely get some form of automatic binding generation.)
136
137----------------------
138Known issues and notes
139----------------------
140
141- owl_window does not export the underlying WINDOW*. This is
142  intentional. To safely resize windows, owl_window reserves the right
143  to destroy/recreate the window whenever it feels like. We can add
144  "window-realized"/"window-unrealized" signals if people really want
145  though.
146
147- This is currently using GObject. This buys us a lot of niceness, but
148  it is adding a new library with full-blown (and somewhat
149  overengineered) object system. It's very useful for prototyping, but
150  if people want, it can be replaced. I think it's actually
151  worthwhile, as most of the overengineering is explicitly designed
152  for language bindings, something we could be better at.
153
154- There is this really sketchy "three types in one" thing going on
155  with the screen, panels, and subwins. I'd like to refactor that into
156  some sort of subtyping, but that would ideally involve even more use
157  of GObject.
158
159- owl_mainwin is not very well ported and the windows do not have a
160  very consistent implementation. This is a known problem that will be
161  addressed in the next iteration. The current ports were done partly
162  as experiments for conventions and mostly to get something working
163  as soon as possible. Among things that should change is for the
164  widgets to all use new/delete/pointers instead of
165  init/cleanup/embed-in-struct.
166
167- The editwin and a few others are strange and keep track of signal
168  ids. This is somewhat a side effect of us not using GObject
169  everywhere; the signals can automatically disconnect in the right
170  contexts if we do.
171
172- The sepbar depends on a value computed while the mainwin is drawn,
173  so we currently ensure the windows are created in the right order
174  for the repaints to occur correctly. This is rather poor and should
175  be refactored later.
176
177- The code fairly routinely does casts to add extra throw-away
178  parameters to functions. Most notably, casting functions of type
179
180      void do_something(void *obj)
181
182  to something of type
183
184      void do_something(void *obj, void *user_data)
185
186  (the latter is a GFunc) with the expectation that the user_data
187  argument is discarded. While calling with this cast is undefined by
188  the standard and depends on calling convention, glib uses it
189  internally /everywhere/ and much of glib and gobject API heavily
190  depends on it. As BarnOwl already depends on glib, we implicitly
191  assume this cast works.
Note: See TracBrowser for help on using the repository browser.