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 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.)
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.
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.
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.
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
126 These two flags are mostly equal in functionality to their *_FOCUS
127 counterparts, but for the default widget.
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.
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.
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.
153 GtkWidget, private flags:
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.
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
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
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.
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]
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).
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.
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.
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.
213 This section describes various constraints on the states of
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)
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 ]
227 2) GTK_WIDGET_MAPPED (widget) => GTK_WIDGET_REALIZED (widget)
229 3) if GTK_WIDGET_TOPLEVEL (widget):
230 GTK_WIDGET_VISIBLE (widget) <=> GTK_WIDGET_MAPPED (widget)
232 4) if !GTK_WIDGET_TOPLEVEL (widget):
233 widget->parent && GTK_WIDGET_REALIZED (widget->parent) <=>
234 GTK_WIDGET_REALIZED (widget)
236 5) if !GTK_WIDGET_TOPLEVEL (widget):
238 GTK_WIDGET_MAPPED (widget) => GTK_WIDGET_VISIBLE (widget)
239 => GTK_WIDGET_CHILD_VISIBLE (widget)
240 => GTK_WIDGET_REALIZED (widget)
242 widget->parent && GTK_WIDGET_MAPPED (widget->parent) &&
243 GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_CHILD_VISIBLE
244 => GTK_WIDGET_MAPPED (widget)
246 Note:, the definition
248 [ GTK_WIDGET_DRAWABLE = GTK_WIDGET_VISIBLE && GTK_WIDGET_MAPPED
249 is made in gtkwidget.h, but by 3) and 5),
251 GTK_WIDGET_MAPPED => GTK_WIDGET_VISIBLE
254 6) GTK_REDRAW_PENDING => GTK_WIDGET_REALIZED
255 GTK_RESIZE_PENDING => "
256 GTK_LEAVE_PENDING => "
257 GTK_RESIZE_NEEDED => "
259 III. How states are changed:
260 ----------------------------
262 How can the user control the state of a widget:
263 -----------------------------------------------
265 (In the following, set flag means set the flag, do appropriate
266 actions, and enforce above invariants)
269 if !GTK_DESTROYED sets GTK_VISIBLE
272 if !GTK_VISIBLE for widget
276 For a top-level widget
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.
283 gtk_container_add (container, widget) [ and container-specific variants ]
286 gtk_container_remove (container, widget)
287 unsets widget->parent
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.
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
303 When The X window corresponding to a GTK window is destroyed:
304 -------------------------------------------------------------
306 gtk_widget_destroy is called (as above).
310 IV. Responsibilities of widgets
311 --------------------------------
313 Adding to a container
314 ---------------------
316 When a widget is added to a container, the container:
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)
322 Removing from a container
323 -------------------------
325 When a widget is removed to a container, the container:
327 1) Calls gtk_widget_unparent (widget)
332 gtk_widget_unparent unrealizes the widget except in the
333 special case GTK_IN_REPARENT is set.
339 Widgets are created in an unrealized state.
341 1) The widget should allocate and initialize needed data structures
347 When a widget recieves the "realize" signal it should:
349 NO_WINDOW widgets: (probably OK to use default handler)
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
357 widget->style = gtk_style_attach (widget->style, widget->window);
359 widget with window(s)
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
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...)
382 When a widget receives the unmap signal, it must:
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...)
394 When a widget receives the unrealize signal, it must
396 1) For any windows other than widget->window do:
398 gdk_window_set_user_data (window, NULL);
399 gdk_window_destroy (window);
401 2) Call the parent's unrealize handler
404 The Widget class unrealize handler will take care of unrealizing
405 all children if necessary. [should this be made consistent with
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.
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
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.
432 When a widget receives the destroy signal, it must:
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.
438 2) Call the parent class's destroy handler.
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)
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)
452 The Finalize Pseudo-signal
453 --------------------------
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.
459 1) Free any memory allocated by the widget. (But _not_
460 the widget structure itself.
462 2) Call the parent class's finalize signal
465 A note on chaining "destroy" signals and finalize signals:
466 ---------------------------------------------------------
468 This is done by code like:
470 if (GTK_OBJECT_CLASS (parent_class)->destroy)
471 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
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
477 GtkFoo <- GtkBar <- GtkWidget <-GtkObject
479 And that Foo, Widget, and Object all have destructors, but
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.