source: trunk/third/gtk/docs/widget_system.txt @ 14482

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