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.
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
howevever, 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 descendent
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 recieves 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
gdk_window_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 sectionalize 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.