1 Notes about the inner workings of the widget system of GTK+
2 ===========================================================
4 This file contains some notes as to how the widget system does
5 and should work. It consists of three parts:
7 I) A description of the meaning of the various flags
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)
13 III) Some notes about the ways that a widget changes states
15 IV) A list of responsibilities of various widget signals when
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:
28 Section II is mostly of interest to those maintaining GTK, the
29 other sections may also be interesting to people writing
33 - Owen Taylor <owt1@cornell.edu>
37 - Tim Janik <timj@gimp.org>
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.
51 This flag reflects the fact that the holder of the
52 initial reference count is unknown. Refer to refcounting.txt
60 GtkWidget, public flags:
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.
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.
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).
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).
84 Set by gtk_widget_show.
85 Implies that a widget will be flagged GTK_MAPPED as soon as its
88 Set by gtk_widget_hide.
89 Implies that a widget is not onscreen, therefore !GTK_MAPPED.
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.
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.
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.
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
118 These two flags are mostly equal in functionality to their *_FOCUS
119 counterparts, but for the default widget.
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.
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.
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.
145 GtkWidget, private flags:
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.
154 First, this is only valid for GtkContainers.
155 [some of the code should move to gtkcontainer.c therefore]
156 Relies on GTK_WIDGET_REALIZED(widget)
157 [this is not really enforced throughout the code, but should
158 be. it only requires a few checks for GTK_WIDGET_RELIZED and
159 minor changes to gtk_widget_unrealize, we can then remove the check
160 in gtk_widget_real_destroy]
161 Means: there is an idle handler waiting for the container to
165 Relies on GTK_WIDGET_REALIZED(widget)
166 [this is not really enforced throughout the code, but should
167 be. once this is done special checking in gtk_widget_real_destroy
169 Means: a widget has been added to the resize_widgets list of
170 its _toplevel_ container (keep this in mind for GtkViewport).
171 Remark: this flag is also used internaly by gtkwindow.c during
172 the evaluation of resizing worthy widgets.
175 A widget is flagged as such if there is a leave_notify event
176 pending for it. It will receive this event regardless of a grab
177 through another widget or its current sensitivity.
178 [this should be made relying on GTK_REALIZED]
181 Set by gtk_widget_shape_combine_mask if a widget got a shape mask
182 assigned (making use of the X11 shaped window extension).
185 During the act of reparentation widgets which are already
186 realized and will be added to an already realized parent need
187 to have this flag set to prevent natural unrealization on the
188 process of getting unparented.
193 This macro examines whether a widget is flagged as GTK_WIDGET_VISIBLE
194 and GTK_WIDGET_MAPPED.
195 Means: it _makes sense_ to draw in a widgets window.
197 GTK_WIDGET_IS_SENSITIVE:
198 This macro tells the real sensitivity state of a widget. It returns
199 whether both the widget and all its parents are in sensitive state.
205 This section describes various constraints on the states of
210 A => B means if A is true, than B is true
211 A <=> B means A is true, if and only if B is true
212 (equivalent to A => B and A <= B)
215 1) GTK_WIDGET_DESTROYED (widget) => !GTK_WIDGET_REALIZED (widget)
216 => !GTK_WIDGET_VISIBLE (widget)
217 [ The latter is not currently in place, but it should be ]
219 2) GTK_WIDGET_MAPPED (widget) => GTK_WIDGET_REALIZED (widget)
221 3) if GTK_WIDGET_TOPLEVEL (widget):
222 GTK_WIDGET_VISIBLE (widget) <=> GTK_WIDGET_MAPPED (widget)
224 4) if !GTK_WIDGET_TOPLEVEL (widget):
225 widget->parent && GTK_WIDGET_REALIZED (widget->parent) <=>
226 GTK_WIDGET_REALIZED (widget)
228 5) if !GTK_WIDGET_TOPLEVEL (widget):
230 GTK_WIDGET_MAPPED (widget) => GTK_WIDGET_VISIBLE (widget)
231 => GTK_WIDGET_REALIZED (widget)
233 widget->parent && GTK_WIDGET_MAPPED (widget->parent) &&
234 GTK_WIDGET_VISIBLE (widget) => GTK_WIDGET_MAPPED (widget)
236 Note:, the definition
238 [ GTK_WIDGET_DRAWABLE = GTK_WIDGET_VISIBLE && GTK_WIDGET_MAPPED
239 is made in gtkwidget.h, but by 3) and 5),
241 GTK_WIDGET_MAPPED => GTK_WIDGET_VISIBLE
244 6) GTK_REDRAW_PENDING => GTK_WIDGET_REALIZED
245 GTK_RESIZE_PENDING => "
246 GTK_LEAVE_PENDING => "
247 GTK_RESIZE_NEEDED => "
249 III. How states are changed:
250 ----------------------------
252 How can the user control the state of a widget:
253 -----------------------------------------------
255 (In the following, set flag means set the flag, do appropriate
256 actions, and enforce above invariants)
259 if !GTK_DESTROYED sets GTK_VISIBLE
262 if !GTK_VISIBLE for widget
266 For a top-level widget
269 if !GTK_DESTROYED sets GTK_REALIZED
270 - Calling gtk_widget_realize when the widget is not a descendent
271 of a toplevel is an ERROR.
273 gtk_container_add (container, widget) [ and container-specific variants ]
276 gtk_container_remove (container, widget)
277 unsets widget->parent
279 gtk_widget_reparent (widget, new_parent)
280 Equivalent to removing widget from old parent and adding it to
281 the new parent, except that the widget will not be temporarily
282 unrealized if both the old parent and the new parent are realized.
289 These functions are not meant to be used by applications - they
290 are used only by GTK and widgets to enforce invariants on the
293 When The X window corresponding to a GTK window is destroyed:
294 -------------------------------------------------------------
296 gtk_widget_destroy is called (as above).
300 IV. Responsibilities of widgets
301 --------------------------------
303 Adding to a container
304 ---------------------
306 When a widget is added to a container, the container:
308 1) calls gtk_widget_set_parent (widget, container)
309 2) calls gtk_widget_set_parent_window (widget, window) if
310 the widget is being added to something other than container->window
311 3) if container is realized, and not widget, realizes widget
312 4) if container is mapped, and not widget and widget is GTK_VISIBLE,
314 5) Queues a resize if the widget is mapped
316 Note: It would be nice to remove 3) and 4) out of widget specific code
317 since they are of the invariant-enforcing nature, but it is
318 a bit hard, since they can't be done until after 2)
321 Removing from a container
322 -------------------------
324 When a widget is removed to a container, the container:
326 1) Calls gtk_widget_unparent (widget)
331 gtk_widget_unparent unrealizes the widget except in the
332 special case GTK_IN_REPARENT is set.
338 Widgets are created in an unrealized state.
340 1) The widget should allocate and initialize needed data structures
346 When a widget recieves the "realize" signal it should:
348 NO_WINDOW widgets: (probably OK to use default handler)
350 1) set the realized flag
351 2) set widget->window
352 widget->window = gtk_widget_get_parent_window (widget);
353 gdk_window_ref (widget->window);
354 3) attach the widget's style
356 widget->style = gtk_style_attach (widget->style, widget->window);
358 widget with window(s)
360 1) set the REALIZED flag
361 2) create windows with the parent obtained from
362 gtk_widget_get_parent_window (widget);
363 3) attach the widget's style
364 4) set the background color for the new window based on the style
369 1) Set the MAPPED flag
370 2) If the widget has any windows, gdk_window_show those windows
371 3) call gtk_widget_map for all child widgets that are
373 3) Do any other functions related to putting the widget onscreen.
374 (for instance, showing extra popup windows...)
379 When a widget receives the unmap signal, it must:
381 1) If the widget has a window, gdk_window_hide that window,
382 2) If the widget does not have a window, unmap all child widgets
383 3) Do any other functions related to taking the widget offscreen
384 (for instance, removing popup windows...)
391 When a widget receives the unrealize signal, it must
393 1) For any windows other than widget->window do:
395 gdk_window_set_user_data (window, NULL);
396 gdk_window_destroy (window);
398 2) Call the parent's unrealize handler
401 The Widget class unrealize handler will take care of unrealizing
402 all children if necessary. [should this be made consistent with
411 The destroy signal probably shouldn't exist at all. A widget
412 should merely be unrealized and removed from its parent
413 when the user calls gtk_widget_destroy or a GDK_DESTROY event
414 is received. However, a large body of code depends on
415 getting a definitive signal when a widget goes away.
417 That could be put in the finalization step, but, especially
418 with language bindings, the cleanup step may need to refer
419 back to the widget. (To use gtk_widget_get_data, for instance)
420 If it does so via a pointer in a closure (natural for
421 Scheme, or Perl), then the finalization procedure will never
424 Also, if we made that the finalization step, we would have
425 to propagate the GDK_DESTROY event in any case, since it is
426 at that point at which user-visible actions need to be taken.
429 When a widget receives the destroy signal, it must:
431 1) If the widget "owns" any widgets other than its child
432 widgets, (for instance popup windows) it should
433 call gtk_widget_destroy () for them.
435 2) Call the parent class's destroy handler.
438 The "destroy" signal will only be received once. A widget
439 will never receive any other signals after the destroy
440 signal (but see the sectionalize on "Finalize" below)
442 The widget must handle calls to all publically accessible
443 functions in an innocuous manner even after a "destroy"
444 signal. (A widget can assume that it will not be realized
445 after a "destroy" signal is received, which may simplify
446 handling this requirement)
449 The Finalize Pseudo-signal
450 --------------------------
452 The finalize pseudo-signal is received after all references
453 to the widget have been removed. The finalize callback
454 cannot make any GTK calls with the widget as a parameter.
456 1) Free any memory allocated by the widget. (But _not_
457 the widget structure itself.
459 2) Call the parent class's finalize signal
462 A note on chaining "destroy" signals and finalize signals:
463 ---------------------------------------------------------
465 This is done by code like:
467 if (GTK_OBJECT_CLASS (parent_class)->destroy)
468 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
470 It may not be completely obvious why this works. Note
471 that parent_class is a static variable on a per-class
472 basis. So say: we have
474 GtkFoo <- GtkBar <- GtkWidget <-GtkObject
476 And that Foo, Widget, and Object all have destructors, but
479 Then gtk_foo_destroy will call gtk_widget_destroy (because
480 it was not overridden in the Bar class structure) and
481 gtk_widget_destroy will call gtk_object_destroy because
482 the parent_class variable referenced by gtk_foo_destroy is the
483 static variable in gtkwidget.c: GtkObjectClass.