]> Pileus Git - ~andy/gtk/blob - docs/widget_system.txt
Implement gdk_color_parse() in terms of pango_color_parse().
[~andy/gtk] / docs / widget_system.txt
1 Notes about the inner workings of the widget system of GTK+
2 ===========================================================
3
4 This file contains some notes as to how the widget system does
5 and should work. It consists of three parts:
6
7  I) A description of the meaning of the various flags
8
9  II) A list of invariants about the states of the widgets. 
10     (Throughout this document, we refer to the states of the
11      widgets by referring to the flags for GtkWidget)
12
13  III) Some notes about the ways that a widget changes states
14
15  IV) A list of responsibilities of various widget signals when
16     the states change.
17
18 Any action necessary to maintain the invariants in II which is not
19 explicitly mentioned in IV), is the responsibility of the core GTK
20 code, which is roughly defined as:
21
22   gtkobject.c
23   gtkwidget.c
24   gtkcontainer.c
25   gtkmain.c
26   gtksignal.c
27
28 Section II is mostly of interest to those maintaining GTK, the
29 other sections may also be interesting to people writing
30 new widgets.
31
32 Main outline:
33         - Owen Taylor <owt1@cornell.edu>
34           1998/02/03
35
36 Flag descriptions:
37         - Tim Janik <timj@gimp.org>
38           1998/02/04
39
40 I. Flags
41 --------
42
43 GtkObject:
44
45 GTK_DESTROYED:
46         This flagged is set for a GtkObject right before its
47         destruction code is executed. Its main use is the
48         prevention of multiple destruction invokations.
49         
50 GTK_FLOATING:
51         This flag reflects the fact that the holder of the
52         initial reference count is unknown. Refer to refcounting.txt
53         for further details.
54
55 GTK_RESERVED_1:
56 GTK_RESERVED_2:
57         Reserved flags.
58
59
60 GtkWidget, public flags:
61
62 GTK_TOPLEVEL:
63         Widgets without a real parent, as there are GtkWindows and
64         GtkMenus have this flag set throughout their lifetime.
65         Toplevel widgets always contain their own GdkWindow.
66         
67 GTK_NO_WINDOW:
68         This flag is indicative for a widget that does not provide
69         its own GdkWindow. Visible action (e.g. drawing) is performed
70         on the parent's GdkWindow.
71
72 GTK_REALIZED:
73         Set by gtk_widget_realize, unset by gtk_widget_unrealize.
74         Relies on ((widget->parent && widget->parent->window)
75                    || GTK_WIDGET_TOPLEVEL (widget));
76         Means: widget has an associated GdkWindow (XWindow).
77
78 GTK_MAPPED:
79         Set by gtk_widget_map, unset by gtk_widget_unmap.
80         May only be set if GTK_WIDGET_REALIZED (widget).
81         Means: gdk_window_show() has been called on the widgets window(s).
82
83 GTK_VISIBLE:
84         Set by gtk_widget_show.
85         Implies that a widget will be flagged GTK_MAPPED as soon as its
86         parent is mapped.
87 !GTK_VISIBLE:
88         Set by gtk_widget_hide.
89         Implies that a widget is not onscreen, therefore !GTK_MAPPED.
90
91 GTK_CHILD_VISIBLE
92         Set by gtk_widget_set_child_visible, and if FALSE indicates that 
93         the widget should not be mapped even if the parent is mapped
94         and visible. Containers like GtkNotebook use this flag.
95         A private flag, not a public flag, so if you need to check
96         this flag, you should call gtk_widget_get_child_visible().
97         (Should be very rarely necesary.)
98
99 GTK_SENSITIVE:
100         Set and unset by gtk_widget_set_sensitive.
101         The sensitivity of a widget determines whether it will receive
102         certain events (e.g. button or key presses). One premise for
103         the widgets sensitivity is to have GTK_SENSITIVE set.
104
105 GTK_PARENT_SENSITIVE:
106         Set and unset by gtk_widget_set_sensitive operations on the
107         parents of the widget.
108         This is the second premise for the widgets sensitivity. Once
109         it has GTK_SENSITIVE and GTK_PARENT_SENSITIVE set, its state is
110         effectively sensitive. This is expressed (and can be examined) by
111         the GTK_WIDGET_IS_SENSITIVE macro.
112
113 GTK_CAN_FOCUS:
114         There are no directly corresponding functions for setting/unsetting
115         this flag, but it can be affected by the GtkWidget::has_focus argument
116         via gtk_widget_set_arg.
117         This flag determines whether a widget is able to handle focus grabs.
118
119 GTK_HAS_FOCUS:
120         This flag will be set by gtk_widget_grab_focus for widgets that also
121         have GTK_CAN_FOCUS set. The flag will be unset once another widget
122         grabs the focus.
123         
124 GTK_CAN_DEFAULT:
125 GTK_HAS_DEFAULT:
126         These two flags are mostly equal in functionality to their *_FOCUS
127         counterparts, but for the default widget.
128
129 GTK_HAS_GRAB:
130         Set by gtk_grab_add, unset by gtk_grab_remove.
131         Means: widget is in the grab_widgets stack, and will be the preferred
132         one for receiving events other than ones of cosmetic value.
133
134 GTK_BASIC:
135         The GTK_BASIC flag is an attempt at making a distinction
136         between widgets that handle user input e.g. key/button presses
137         and those that don't. Subsequent parent<->child relation ships
138         of non `basic' widgets should be avoided. The checking for
139         this is currently not properly enforced in the code. For
140         example GtkButton is a non `basic' widget, that will therefore
141         disallow to act as a container for another GtkButton. Now the
142         gnit is, one can add a GtkHBox (which is a `basic' widget) to
143         the first button, and put the second into the box.
144
145 GTK_RESERVED_3:
146
147 GTK_RC_STYLE:
148         This flag indicates that its style has been looked up through
149         the rc mechanism. It does not imply that the widget actually
150         had a style defined through the rc mechanism.
151
152
153 GtkWidget, private flags:
154
155 GTK_USER_STYLE:
156         A widget is flagged to have a user style, once gtk_widget_set_style
157         has been invoked for it. The use of this flag is to tell widgets
158         wich share a global user style from the ones which got a certain
159         style assign from outside the toolkit.
160         
161 GTK_RESIZE_PENDING:
162         First, this is only valid for GtkContainers.
163         [some of the code should move to gtkcontainer.c therefore]
164         Relies on GTK_WIDGET_REALIZED(widget)
165         [this is not really enforced throughout the code, but should
166          be. it only requires a few checks for GTK_WIDGET_RELIZED and
167          minor changes to gtk_widget_unrealize, we can then remove the check
168          in gtk_widget_real_destroy]
169         Means: there is an idle handler waiting for the container to
170         resize it.
171
172 GTK_RESIZE_NEEDED:
173         Relies on GTK_WIDGET_REALIZED(widget)
174         [this is not really enforced throughout the code, but should
175          be. once this is done special checking in gtk_widget_real_destroy
176          can be avoided]
177         Means: a widget has been added to the resize_widgets list of
178         its _toplevel_ container (keep this in mind for GtkViewport).
179         Remark: this flag is also used internaly by gtkwindow.c during
180         the evaluation of resizing worthy widgets.
181
182 GTK_LEAVE_PENDING:
183         A widget is flagged as such if there is a leave_notify event
184         pending for it. It will receive this event regardless of a grab
185         through another widget or its current sensitivity.
186         [this should be made relying on GTK_REALIZED]
187
188 GTK_HAS_SHAPE_MASK:
189         Set by gtk_widget_shape_combine_mask if a widget got a shape mask
190         assigned (making use of the X11 shaped window extension).
191
192 GTK_IN_REPARENT:
193         During the act of reparentation widgets which are already
194         realized and will be added to an already realized parent need
195         to have this flag set to prevent natural unrealization on the
196         process of getting unparented.
197
198 Related Macros:
199
200 GTK_WIDGET_DRAWABLE:
201         This macro examines whether a widget is flagged as GTK_WIDGET_VISIBLE
202         and GTK_WIDGET_MAPPED.
203         Means: it _makes sense_ to draw in a widgets window.
204
205 GTK_WIDGET_IS_SENSITIVE:
206         This macro tells the real sensitivity state of a widget. It returns
207         whether both the widget and all its parents are in sensitive state.
208
209
210 II. Invariants:
211 ---------------
212
213 This section describes various constraints on the states of 
214 the widget:
215
216 In the following
217
218   A => B     means  if A is true, than B is true
219   A <=> B    means  A is true, if and only if B is true
220                     (equivalent to A => B and A <= B)
221
222
223 1)  GTK_WIDGET_DESTROYED (widget) => !GTK_WIDGET_REALIZED (widget)
224                                   => !GTK_WIDGET_VISIBLE (widget)
225 [ The latter is not currently in place, but it should be ] 
226  
227 2) GTK_WIDGET_MAPPED (widget) => GTK_WIDGET_REALIZED (widget)
228
229 3) if GTK_WIDGET_TOPLEVEL (widget):
230    GTK_WIDGET_VISIBLE (widget) <=> GTK_WIDGET_MAPPED (widget)
231
232 4) if !GTK_WIDGET_TOPLEVEL (widget):
233   widget->parent && GTK_WIDGET_REALIZED (widget->parent) <=>
234      GTK_WIDGET_REALIZED (widget)
235
236 5) if !GTK_WIDGET_TOPLEVEL (widget):
237
238    GTK_WIDGET_MAPPED (widget) => GTK_WIDGET_VISIBLE (widget)
239                               => GTK_WIDGET_CHILD_VISIBLE (widget)
240                               => GTK_WIDGET_REALIZED (widget)
241
242    widget->parent && GTK_WIDGET_MAPPED (widget->parent) && 
243      GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_CHILD_VISIBLE 
244        => GTK_WIDGET_MAPPED (widget)
245
246 Note:, the definition
247
248 [  GTK_WIDGET_DRAWABLE = GTK_WIDGET_VISIBLE && GTK_WIDGET_MAPPED
249    is made in gtkwidget.h, but by 3) and 5), 
250      
251       GTK_WIDGET_MAPPED => GTK_WIDGET_VISIBLE
252 ]
253
254 6) GTK_REDRAW_PENDING => GTK_WIDGET_REALIZED
255    GTK_RESIZE_PENDING =>         "
256    GTK_LEAVE_PENDING  =>         "
257    GTK_RESIZE_NEEDED  =>         "
258
259 III. How states are changed:
260 ----------------------------
261
262 How can the user control the state of a widget:
263 -----------------------------------------------
264
265 (In the following, set flag means set the flag, do appropriate
266 actions, and enforce above invariants) 
267
268 gtk_widget_show: 
269  if !GTK_DESTROYED sets GTK_VISIBLE
270
271 gtk_widget_hide:
272  if !GTK_VISIBLE for widget
273
274 gtk_widget_destroy:
275  sets GTK_DESTROYED
276  For a top-level widget
277
278 gtk_widget_realize:
279  if !GTK_DESTROYED sets GTK_REALIZED
280 - Calling gtk_widget_realize when the widget is not a descendent
281   of a toplevel is an ERROR.
282
283 gtk_container_add (container, widget) [ and container-specific variants ]
284  Sets widget->parent 
285
286 gtk_container_remove (container, widget)
287  unsets widget->parent
288
289 gtk_widget_reparent (widget, new_parent)
290  Equivalent to removing widget from old parent and adding it to
291  the new parent, except that the widget will not be temporarily 
292  unrealized if both the old parent and the new parent are realized.
293
294
295 gtk_widget_unrealize
296 gtk_widget_map
297 gtk_widget_unmap
298
299 These functions are not meant to be used by applications - they
300 are used only by GTK and widgets to enforce invariants on the
301 state.
302
303 When The X window corresponding to a GTK window is destroyed:
304 -------------------------------------------------------------
305
306 gtk_widget_destroy is called (as above).
307
308
309
310 IV. Responsibilities of widgets
311 --------------------------------
312
313 Adding to a container
314 ---------------------
315
316 When a widget is added to a container, the container:
317
318   1) calls gtk_widget_set_parent_window (widget, window) if 
319      the widget is being added to something other than container->window
320   2) calls gtk_widget_set_parent (widget, container)
321
322 Removing from a container
323 -------------------------
324
325 When a widget is removed to a container, the container:
326
327   1) Calls gtk_widget_unparent (widget)
328   2) Queues a resize.
329
330 Notes:
331
332  gtk_widget_unparent unrealizes the widget except in the 
333    special case GTK_IN_REPARENT is set.
334
335
336 At widget creation
337 ------------------
338
339 Widgets are created in an unrealized state. 
340
341  1) The widget should allocate and initialize needed data structures
342
343
344 The Realize signal
345 ------------------
346
347 When a widget recieves the "realize" signal it should:
348
349  NO_WINDOW widgets: (probably OK to use default handler)
350
351   1) set the realized flag
352   2) set widget->window
353       widget->window = gtk_widget_get_parent_window (widget);
354       gdk_window_ref (widget->window);
355   3) attach the widget's style
356
357   widget->style = gtk_style_attach (widget->style, widget->window);
358
359  widget with window(s)
360
361   1) set the REALIZED flag
362   2) create windows with the parent obtained from
363       gtk_widget_get_parent_window (widget);
364   3) attach the widget's style
365   4) set the background color for the new window based on the style
366
367 The Map signal
368 --------------
369
370   1) Set the MAPPED flag
371   2) If the widget has any windows, gdk_window_show those windows
372   3) call gtk_widget_map for all child widgets that are 
373      VISIBLE, CHILD_VISIBLE and !MAPPED. (A widget will only
374      be !CHILD_VISIBLE if the container set it that way, so
375      most containers will not have to check this.)
376   3) Do any other functions related to putting the widget onscreen.
377      (for instance, showing extra popup windows...)
378
379 The Unmap signal
380 ----------------
381
382 When a widget receives the unmap signal, it must:
383
384  1) If the widget has a window, gdk_window_hide that window, 
385  2) If the widget does not have a window, unmap all child widgets
386  3) Do any other functions related to taking the widget offscreen
387      (for instance, removing popup windows...)
388  4) Unset GTK_MAPPED
389
390
391 The Unrealize signal
392 --------------------
393
394 When a widget receives the unrealize signal, it must
395
396  1) For any windows other than widget->window do:
397
398     gdk_window_set_user_data (window, NULL);
399     gdk_window_destroy (window);
400
401  2) Call the parent's unrealize handler
402
403
404 The Widget class unrealize handler will take care of unrealizing
405 all children if necessary. [should this be made consistent with
406 unmap???]
407
408
409 The Destroy Signal
410 ------------------
411
412 Commentary:
413
414   The destroy signal probably shouldn't exist at all. A widget
415   should merely be unrealized and removed from its parent
416   when the user calls gtk_widget_destroy or a GDK_DESTROY event
417   is received. However, a large body of code depends on
418   getting a definitive signal when a widget goes away.
419
420   That could be put in the finalization step, but, especially
421   with language bindings, the cleanup step may need to refer
422   back to the widget. (To use gtk_widget_get_data, for instance)
423   If it does so via a pointer in a closure (natural for
424   Scheme, or Perl), then the finalization procedure will never
425   be called. 
426
427   Also, if we made that the finalization step, we would have
428   to propagate the GDK_DESTROY event in any case, since it is
429   at that point at which user-visible actions need to be taken.
430
431
432 When a widget receives the destroy signal, it must:
433
434   1) If the widget "owns" any widgets other than its child
435      widgets, (for instance popup windows) it should
436      call gtk_widget_destroy () for them.
437
438   2) Call the parent class's destroy handler.
439
440
441 The "destroy" signal will only be received once. A widget
442 will never receive any other signals after the destroy
443 signal (but see the sectionalize on "Finalize" below)
444
445 The widget must handle calls to all publically accessible
446 functions in an innocuous manner even after a "destroy"
447 signal. (A widget can assume that it will not be realized 
448 after a "destroy" signal is received, which may simplify
449 handling this requirement)
450
451
452 The Finalize Pseudo-signal
453 --------------------------
454
455 The finalize pseudo-signal is received after all references
456 to the widget have been removed. The finalize callback
457 cannot make any GTK calls with the widget as a parameter.
458
459 1) Free any memory allocated by the widget. (But _not_
460    the widget structure itself.
461
462 2) Call the parent class's finalize signal
463
464
465 A note on chaining "destroy" signals and finalize signals:
466 ---------------------------------------------------------
467
468 This is done by code like:
469
470   if (GTK_OBJECT_CLASS (parent_class)->destroy)
471     (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
472
473 It may not be completely obvious why this works. Note
474 that parent_class is a static variable on a per-class
475 basis. So say: we have
476
477   GtkFoo <- GtkBar <- GtkWidget <-GtkObject
478
479 And that Foo, Widget, and Object all have destructors, but
480 not Bar.
481
482 Then gtk_foo_destroy will call gtk_widget_destroy (because
483 it was not overridden in the Bar class structure) and
484 gtk_widget_destroy will call gtk_object_destroy because
485 the parent_class variable referenced by gtk_foo_destroy is the 
486 static variable in gtkwidget.c: GtkObjectClass.