]> Pileus Git - ~andy/gtk/blob - docs/widget_system.txt
Add a function to determine if a window is the focus widget within its
[~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 invokations.
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_SENSITIVE:
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.
96
97 GTK_PARENT_SENSITIVE:
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.
104
105 GTK_CAN_FOCUS:
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.
110
111 GTK_HAS_FOCUS:
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
114         grabs the focus.
115         
116 GTK_CAN_DEFAULT:
117 GTK_HAS_DEFAULT:
118         These two flags are mostly equal in functionality to their *_FOCUS
119         counterparts, but for the default widget.
120
121 GTK_HAS_GRAB:
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.
125
126 GTK_BASIC:
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.
136
137 GTK_RESERVED_3:
138
139 GTK_RC_STYLE:
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.
143
144
145 GtkWidget, private flags:
146
147 GTK_USER_STYLE:
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.
152         
153 GTK_RESIZE_PENDING:
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
162         resize it.
163
164 GTK_RESIZE_NEEDED:
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
168          can be avoided]
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.
173
174 GTK_LEAVE_PENDING:
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]
179
180 GTK_HAS_SHAPE_MASK:
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).
183
184 GTK_IN_REPARENT:
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.
189
190 Related Macros:
191
192 GTK_WIDGET_DRAWABLE:
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.
196
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.
200
201
202 II. Invariants:
203 ---------------
204
205 This section describes various constraints on the states of 
206 the widget:
207
208 In the following
209
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)
213
214
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 ] 
218  
219 2) GTK_WIDGET_MAPPED (widget) => GTK_WIDGET_REALIZED (widget)
220
221 3) if GTK_WIDGET_TOPLEVEL (widget):
222    GTK_WIDGET_VISIBLE (widget) <=> GTK_WIDGET_MAPPED (widget)
223
224 4) if !GTK_WIDGET_TOPLEVEL (widget):
225   widget->parent && GTK_WIDGET_REALIZED (widget->parent) <=>
226      GTK_WIDGET_REALIZED (widget)
227
228 5) if !GTK_WIDGET_TOPLEVEL (widget):
229
230    GTK_WIDGET_MAPPED (widget) => GTK_WIDGET_VISIBLE (widget)
231                               => GTK_WIDGET_REALIZED (widget)
232
233    widget->parent && GTK_WIDGET_MAPPED (widget->parent) && 
234      GTK_WIDGET_VISIBLE (widget) => GTK_WIDGET_MAPPED (widget)
235
236 Note:, the definition
237
238 [  GTK_WIDGET_DRAWABLE = GTK_WIDGET_VISIBLE && GTK_WIDGET_MAPPED
239    is made in gtkwidget.h, but by 3) and 5), 
240      
241       GTK_WIDGET_MAPPED => GTK_WIDGET_VISIBLE
242 ]
243
244 6) GTK_REDRAW_PENDING => GTK_WIDGET_REALIZED
245    GTK_RESIZE_PENDING =>         "
246    GTK_LEAVE_PENDING  =>         "
247    GTK_RESIZE_NEEDED  =>         "
248
249 III. How states are changed:
250 ----------------------------
251
252 How can the user control the state of a widget:
253 -----------------------------------------------
254
255 (In the following, set flag means set the flag, do appropriate
256 actions, and enforce above invariants) 
257
258 gtk_widget_show: 
259  if !GTK_DESTROYED sets GTK_VISIBLE
260
261 gtk_widget_hide:
262  if !GTK_VISIBLE for widget
263
264 gtk_widget_destroy:
265  sets GTK_DESTROYED
266  For a top-level widget
267
268 gtk_widget_realize:
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.
272
273 gtk_container_add (container, widget) [ and container-specific variants ]
274  Sets widget->parent 
275
276 gtk_container_remove (container, widget)
277  unsets widget->parent
278
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.
283
284
285 gtk_widget_unrealize
286 gtk_widget_map
287 gtk_widget_unmap
288
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
291 state.
292
293 When The X window corresponding to a GTK window is destroyed:
294 -------------------------------------------------------------
295
296 gtk_widget_destroy is called (as above).
297
298
299
300 IV. Responsibilities of widgets
301 --------------------------------
302
303 Adding to a container
304 ---------------------
305
306 When a widget is added to a container, the container:
307
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,
313      maps widget
314   5) Queues a resize if the widget is mapped
315
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)
319
320
321 Removing from a container
322 -------------------------
323
324 When a widget is removed to a container, the container:
325
326   1) Calls gtk_widget_unparent (widget)
327   2) Queues a resize.
328
329 Notes:
330
331  gtk_widget_unparent unrealizes the widget except in the 
332    special case GTK_IN_REPARENT is set.
333
334
335 At widget creation
336 ------------------
337
338 Widgets are created in an unrealized state. 
339
340  1) The widget should allocate and initialize needed data structures
341
342
343 The Realize signal
344 ------------------
345
346 When a widget recieves the "realize" signal it should:
347
348  NO_WINDOW widgets: (probably OK to use default handler)
349
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
355
356   widget->style = gtk_style_attach (widget->style, widget->window);
357
358  widget with window(s)
359
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
365
366 The Map signal
367 --------------
368
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 
372      VISIBLE and !MAPPED.
373   3) Do any other functions related to putting the widget onscreen.
374      (for instance, showing extra popup windows...)
375
376 The Unmap signal
377 ----------------
378
379 When a widget receives the unmap signal, it must:
380
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...)
385  4) Unset GTK_MAPPED
386
387
388 The Unrealize signal
389 --------------------
390
391 When a widget receives the unrealize signal, it must
392
393  1) For any windows other than widget->window do:
394
395     gdk_window_set_user_data (window, NULL);
396     gdk_window_destroy (window);
397
398  2) Call the parent's unrealize handler
399
400
401 The Widget class unrealize handler will take care of unrealizing
402 all children if necessary. [should this be made consistent with
403 unmap???]
404
405
406 The Destroy Signal
407 ------------------
408
409 Commentary:
410
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.
416
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
422   be called. 
423
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.
427
428
429 When a widget receives the destroy signal, it must:
430
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.
434
435   2) Call the parent class's destroy handler.
436
437
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)
441
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)
447
448
449 The Finalize Pseudo-signal
450 --------------------------
451
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.
455
456 1) Free any memory allocated by the widget. (But _not_
457    the widget structure itself.
458
459 2) Call the parent class's finalize signal
460
461
462 A note on chaining "destroy" signals and finalize signals:
463 ---------------------------------------------------------
464
465 This is done by code like:
466
467   if (GTK_OBJECT_CLASS (parent_class)->destroy)
468     (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
469
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
473
474   GtkFoo <- GtkBar <- GtkWidget <-GtkObject
475
476 And that Foo, Widget, and Object all have destructors, but
477 not Bar.
478
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.