]> Pileus Git - ~andy/gtk/blob - docs/widget_system.txt
stylecontext: Do invalidation on first resize container
[~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 invocations.
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 necessary.)
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         which 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_REALIZED 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 internally 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 GTK_NEED_REQUEST:
199         This flag is set if the widget doesn't have an up to date 
200         requisition. If this flag is set, we must actually emit ::size-request
201         when gtk_widget_size_request() is called. Otherwise, we can
202         simply widget->requisition. We keep track of this all the time
203         however, widgets with this flag set are only added to the resize 
204         queue if they are viewable.
205
206 GTK_NEED_ALLOCATION:
207         This flag is set if the widget doesn't have an up to date 
208         allocation. If this flag is set, we must actually emit ::size-allocate
209         when gtk_widget_size_allocate() is called, even if the new allocation
210         is the same as the current allocation.
211  
212 Related Macros:
213
214 GTK_WIDGET_DRAWABLE:
215         This macro examines whether a widget is flagged as GTK_WIDGET_VISIBLE
216         and GTK_WIDGET_MAPPED.
217         Means: it _makes sense_ to draw in a widgets window.
218
219 GTK_WIDGET_IS_SENSITIVE:
220         This macro tells the real sensitivity state of a widget. It returns
221         whether both the widget and all its parents are in sensitive state.
222
223
224 II. Invariants:
225 ---------------
226
227 This section describes various constraints on the states of 
228 the widget:
229
230 In the following
231
232   A => B     means  if A is true, than B is true
233   A <=> B    means  A is true, if and only if B is true
234                     (equivalent to A => B and A <= B)
235
236
237 1)  GTK_WIDGET_DESTROYED (widget) => !GTK_WIDGET_REALIZED (widget)
238                                   => !GTK_WIDGET_VISIBLE (widget)
239 [ The latter is not currently in place, but it should be ] 
240  
241 2) GTK_WIDGET_MAPPED (widget) => GTK_WIDGET_REALIZED (widget)
242
243 3) if GTK_WIDGET_TOPLEVEL (widget):
244    GTK_WIDGET_VISIBLE (widget) <=> GTK_WIDGET_MAPPED (widget)
245
246 4) if !GTK_WIDGET_TOPLEVEL (widget):
247   widget->parent && GTK_WIDGET_REALIZED (widget->parent) <=>
248      GTK_WIDGET_REALIZED (widget)
249
250 5) if !GTK_WIDGET_TOPLEVEL (widget):
251
252    GTK_WIDGET_MAPPED (widget) => GTK_WIDGET_VISIBLE (widget)
253                               => GTK_WIDGET_CHILD_VISIBLE (widget)
254                               => GTK_WIDGET_REALIZED (widget)
255
256    widget->parent && GTK_WIDGET_MAPPED (widget->parent) && 
257      GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_CHILD_VISIBLE 
258        <=> GTK_WIDGET_MAPPED (widget)
259
260 Note:, the definition
261
262 [  GTK_WIDGET_DRAWABLE = GTK_WIDGET_VISIBLE && GTK_WIDGET_MAPPED
263    is made in gtkwidget.h, but by 3) and 5), 
264      
265       GTK_WIDGET_MAPPED => GTK_WIDGET_VISIBLE
266 ]
267
268 6) GTK_REDRAW_PENDING => GTK_WIDGET_REALIZED
269    GTK_RESIZE_PENDING =>         "
270    GTK_LEAVE_PENDING  =>         "
271    GTK_RESIZE_NEEDED  =>         "
272
273 III. How states are changed:
274 ----------------------------
275
276 How can the user control the state of a widget:
277 -----------------------------------------------
278
279 (In the following, set flag means set the flag, do appropriate
280 actions, and enforce above invariants) 
281
282 gtk_widget_show: 
283  if !GTK_DESTROYED sets GTK_VISIBLE
284
285 gtk_widget_hide:
286  if !GTK_VISIBLE for widget
287
288 gtk_widget_destroy:
289  sets GTK_DESTROYED
290  For a top-level widget
291
292 gtk_widget_realize:
293  if !GTK_DESTROYED sets GTK_REALIZED
294 - Calling gtk_widget_realize when the widget is not a descendant
295   of a toplevel is an ERROR.
296
297 gtk_container_add (container, widget) [ and container-specific variants ]
298  Sets widget->parent 
299
300 gtk_container_remove (container, widget)
301  unsets widget->parent
302
303 gtk_widget_reparent (widget, new_parent)
304  Equivalent to removing widget from old parent and adding it to
305  the new parent, except that the widget will not be temporarily 
306  unrealized if both the old parent and the new parent are realized.
307
308
309 gtk_widget_unrealize
310 gtk_widget_map
311 gtk_widget_unmap
312
313 These functions are not meant to be used by applications - they
314 are used only by GTK and widgets to enforce invariants on the
315 state.
316
317 When The X window corresponding to a GTK window is destroyed:
318 -------------------------------------------------------------
319
320 gtk_widget_destroy is called (as above).
321
322
323
324 IV. Responsibilities of widgets
325 --------------------------------
326
327 Adding to a container
328 ---------------------
329
330 When a widget is added to a container, the container:
331
332   1) calls gtk_widget_set_parent_window (widget, window) if 
333      the widget is being added to something other than container->window
334   2) calls gtk_widget_set_parent (widget, container)
335
336 Removing from a container
337 -------------------------
338
339 When a widget is removed to a container, the container:
340
341   1) Calls gtk_widget_unparent (widget)
342   2) Queues a resize.
343
344 Notes:
345
346  gtk_widget_unparent unrealizes the widget except in the 
347    special case GTK_IN_REPARENT is set.
348
349
350 At widget creation
351 ------------------
352
353 Widgets are created in an unrealized state. 
354
355  1) The widget should allocate and initialize needed data structures
356
357
358 The Realize signal
359 ------------------
360
361 When a widget receives the "realize" signal it should:
362
363  NO_WINDOW widgets: (probably OK to use default handler)
364
365   1) set the realized flag
366   2) set widget->window
367       widget->window = gtk_widget_get_parent_window (widget);
368       g_object_ref (widget->window);
369   3) attach the widget's style
370
371   widget->style = gtk_style_attach (widget->style, widget->window);
372
373  widget with window(s)
374
375   1) set the REALIZED flag
376   2) create windows with the parent obtained from
377       gtk_widget_get_parent_window (widget);
378   3) attach the widget's style
379   4) set the background color for the new window based on the style
380
381 The Map signal
382 --------------
383
384   1) Set the MAPPED flag
385   2) If the widget has any windows, gdk_window_show those windows
386   3) call gtk_widget_map for all child widgets that are 
387      VISIBLE, CHILD_VISIBLE and !MAPPED. (A widget will only
388      be !CHILD_VISIBLE if the container set it that way, so
389      most containers will not have to check this.)
390   3) Do any other functions related to putting the widget onscreen.
391      (for instance, showing extra popup windows...)
392
393 The Unmap signal
394 ----------------
395
396 When a widget receives the unmap signal, it must:
397
398  1) If the widget has a window, gdk_window_hide that window, 
399  2) If the widget does not have a window, unmap all child widgets
400  3) Do any other functions related to taking the widget offscreen
401      (for instance, removing popup windows...)
402  4) Unset GTK_MAPPED
403
404
405 The Unrealize signal
406 --------------------
407
408 When a widget receives the unrealize signal, it must
409
410  1) For any windows other than widget->window do:
411
412     gdk_window_set_user_data (window, NULL);
413     gdk_window_destroy (window);
414
415  2) Call the parent's unrealize handler
416
417
418 The Widget class unrealize handler will take care of unrealizing
419 all children if necessary. [should this be made consistent with
420 unmap???]
421
422
423 The Destroy Signal
424 ------------------
425
426 Commentary:
427
428   The destroy signal probably shouldn't exist at all. A widget
429   should merely be unrealized and removed from its parent
430   when the user calls gtk_widget_destroy or a GDK_DESTROY event
431   is received. However, a large body of code depends on
432   getting a definitive signal when a widget goes away.
433
434   That could be put in the finalization step, but, especially
435   with language bindings, the cleanup step may need to refer
436   back to the widget. (To use gtk_widget_get_data, for instance)
437   If it does so via a pointer in a closure (natural for
438   Scheme, or Perl), then the finalization procedure will never
439   be called. 
440
441   Also, if we made that the finalization step, we would have
442   to propagate the GDK_DESTROY event in any case, since it is
443   at that point at which user-visible actions need to be taken.
444
445
446 When a widget receives the destroy signal, it must:
447
448   1) If the widget "owns" any widgets other than its child
449      widgets, (for instance popup windows) it should
450      call gtk_widget_destroy () for them.
451
452   2) Call the parent class's destroy handler.
453
454
455 The "destroy" signal will only be received once. A widget
456 will never receive any other signals after the destroy
457 signal (but see the section on "Finalize" below)
458
459 The widget must handle calls to all publically accessible
460 functions in an innocuous manner even after a "destroy"
461 signal. (A widget can assume that it will not be realized 
462 after a "destroy" signal is received, which may simplify
463 handling this requirement)
464
465
466 The Finalize Pseudo-signal
467 --------------------------
468
469 The finalize pseudo-signal is received after all references
470 to the widget have been removed. The finalize callback
471 cannot make any GTK calls with the widget as a parameter.
472
473 1) Free any memory allocated by the widget. (But _not_
474    the widget structure itself.
475
476 2) Call the parent class's finalize signal
477
478
479 A note on chaining "destroy" signals and finalize signals:
480 ---------------------------------------------------------
481
482 This is done by code like:
483
484   if (GTK_OBJECT_CLASS (parent_class)->destroy)
485     (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
486
487 It may not be completely obvious why this works. Note
488 that parent_class is a static variable on a per-class
489 basis. So say: we have
490
491   GtkFoo <- GtkBar <- GtkWidget <-GtkObject
492
493 And that Foo, Widget, and Object all have destructors, but
494 not Bar.
495
496 Then gtk_foo_destroy will call gtk_widget_destroy (because
497 it was not overridden in the Bar class structure) and
498 gtk_widget_destroy will call gtk_object_destroy because
499 the parent_class variable referenced by gtk_foo_destroy is the 
500 static variable in gtkwidget.c: GtkObjectClass.