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 invocations.
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 necessary.)
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 which 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_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
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 internally 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.
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.
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.
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.
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.
227 This section describes various constraints on the states of
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)
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 ]
241 2) GTK_WIDGET_MAPPED (widget) => GTK_WIDGET_REALIZED (widget)
243 3) if GTK_WIDGET_TOPLEVEL (widget):
244 GTK_WIDGET_VISIBLE (widget) <=> GTK_WIDGET_MAPPED (widget)
246 4) if !GTK_WIDGET_TOPLEVEL (widget):
247 widget->parent && GTK_WIDGET_REALIZED (widget->parent) <=>
248 GTK_WIDGET_REALIZED (widget)
250 5) if !GTK_WIDGET_TOPLEVEL (widget):
252 GTK_WIDGET_MAPPED (widget) => GTK_WIDGET_VISIBLE (widget)
253 => GTK_WIDGET_CHILD_VISIBLE (widget)
254 => GTK_WIDGET_REALIZED (widget)
256 widget->parent && GTK_WIDGET_MAPPED (widget->parent) &&
257 GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_CHILD_VISIBLE
258 <=> GTK_WIDGET_MAPPED (widget)
260 Note:, the definition
262 [ GTK_WIDGET_DRAWABLE = GTK_WIDGET_VISIBLE && GTK_WIDGET_MAPPED
263 is made in gtkwidget.h, but by 3) and 5),
265 GTK_WIDGET_MAPPED => GTK_WIDGET_VISIBLE
268 6) GTK_REDRAW_PENDING => GTK_WIDGET_REALIZED
269 GTK_RESIZE_PENDING => "
270 GTK_LEAVE_PENDING => "
271 GTK_RESIZE_NEEDED => "
273 III. How states are changed:
274 ----------------------------
276 How can the user control the state of a widget:
277 -----------------------------------------------
279 (In the following, set flag means set the flag, do appropriate
280 actions, and enforce above invariants)
283 if !GTK_DESTROYED sets GTK_VISIBLE
286 if !GTK_VISIBLE for widget
290 For a top-level widget
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.
297 gtk_container_add (container, widget) [ and container-specific variants ]
300 gtk_container_remove (container, widget)
301 unsets widget->parent
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.
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
317 When The X window corresponding to a GTK window is destroyed:
318 -------------------------------------------------------------
320 gtk_widget_destroy is called (as above).
324 IV. Responsibilities of widgets
325 --------------------------------
327 Adding to a container
328 ---------------------
330 When a widget is added to a container, the container:
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)
336 Removing from a container
337 -------------------------
339 When a widget is removed to a container, the container:
341 1) Calls gtk_widget_unparent (widget)
346 gtk_widget_unparent unrealizes the widget except in the
347 special case GTK_IN_REPARENT is set.
353 Widgets are created in an unrealized state.
355 1) The widget should allocate and initialize needed data structures
361 When a widget receives the "realize" signal it should:
363 NO_WINDOW widgets: (probably OK to use default handler)
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
371 widget->style = gtk_style_attach (widget->style, widget->window);
373 widget with window(s)
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
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...)
396 When a widget receives the unmap signal, it must:
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...)
408 When a widget receives the unrealize signal, it must
410 1) For any windows other than widget->window do:
412 gdk_window_set_user_data (window, NULL);
413 gdk_window_destroy (window);
415 2) Call the parent's unrealize handler
418 The Widget class unrealize handler will take care of unrealizing
419 all children if necessary. [should this be made consistent with
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.
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
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.
446 When a widget receives the destroy signal, it must:
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.
452 2) Call the parent class's destroy handler.
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)
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)
466 The Finalize Pseudo-signal
467 --------------------------
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.
473 1) Free any memory allocated by the widget. (But _not_
474 the widget structure itself.
476 2) Call the parent class's finalize signal
479 A note on chaining "destroy" signals and finalize signals:
480 ---------------------------------------------------------
482 This is done by code like:
484 if (GTK_OBJECT_CLASS (parent_class)->destroy)
485 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
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
491 GtkFoo <- GtkBar <- GtkWidget <-GtkObject
493 And that Foo, Widget, and Object all have destructors, but
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.