summaryrefslogtreecommitdiff
path: root/docs/widget_system.txt
diff options
context:
space:
mode:
authorOwen Taylor <otaylor@src.gnome.org>1998-02-03 23:31:21 +0000
committerOwen Taylor <otaylor@src.gnome.org>1998-02-03 23:31:21 +0000
commit23a13fd4a57cf3c6742fda7ee768a8433e1bbe39 (patch)
tree8a1b5dbeae8311826a0393fe87eca6b42cb37db8 /docs/widget_system.txt
parent64ca527ecbcbbf715551b59a7248ef3b225894ce (diff)
downloadgdk-pixbuf-23a13fd4a57cf3c6742fda7ee768a8433e1bbe39.tar.gz
Renamed widget_states.txt to widget_system.txt, and
made some further revisions.
Diffstat (limited to 'docs/widget_system.txt')
-rw-r--r--docs/widget_system.txt379
1 files changed, 379 insertions, 0 deletions
diff --git a/docs/widget_system.txt b/docs/widget_system.txt
new file mode 100644
index 000000000..6607aa276
--- /dev/null
+++ b/docs/widget_system.txt
@@ -0,0 +1,379 @@
+This file contains some notes as to how the widget system does
+and should work. It consists of three parts:
+
+ I) A description of the meaning of the various flags
+
+ II) A list of invariants about the states of the widgets.
+ (Throughout this document, we refer to the states of the
+ widgets by referring to the flags for gtkwidget)
+
+ III) Some notes about the ways that a widget changes states
+
+ IV) A list of responsibilities of various widget signals when
+ the states change.
+
+Any action necessary to maintain the invariants in II which is not
+explicitly mentioned in IV), is the responsibility of the core GTK
+code, which is roughly defined as:
+
+ gtkobject.c
+ gtkwidget.c
+ gtkcontainer.c
+ gtkmain.c
+ gtksignal.c
+
+Section II is mostly of interest to those maintaining GTK, the
+other sections may also be interesting to people writing
+new widgets.
+
+ Owen Taylor <owt1@cornell.edu>
+ 98/02/03
+
+I. Flags
+--------
+
+GTK_REALIZED:
+ set by gtk_widget_realize, unset by gtk_widget_unrealize
+ relies on ((widget->parent && widget->parent->window)
+ || GTK_WIDGET_TOPLEVEL (widget);
+ means: widget has an associated GdkWindow (XWindow)
+
+GTK_MAPPED:
+ set by gtk_widget_map, unset by gtk_widget_unmap
+ may only be set if GTK_WIDGET_REALIZED(widget)
+ means: gdk_window_show() has been called on the widgets window(s).
+
+GTK_VISIBLE:
+ set by gtk_widget_show
+ implies that a widget will be GTK_MAPPED as soon as it's
+ parent is GTK_MAPPED.
+!GTK_VISIBLE:
+ set by gtk_widget_hide
+ implies that a widget is not onscreen, therefore !GTK_MAPPED
+
+GTK_REDRAW_PENDING:
+ relies on GTK_WIDGET_MAPPED(widget)
+ [this is not really enforced throughout the code, but should
+ be. it only requires a few checks for GTK_WIDGET_MAPPED and
+ minor changes to gtk_widget_unmap, we can then remove the check
+ in gtk_widget_real_destroy]
+ means: there is an idle handler waiting for the widget, that
+ will cause a full redraw (gtk_widget_draw(widget, NULL))
+
+GTK_RESIZE_PENDING:
+ first, this is only valid for GtkContainers.
+ [some of the code should move to gtkcontainer.c therefore]
+ relies on GTK_WIDGET_REALIZED(widget)
+ [this is not really enforced throughout the code, but should
+ be. it only requires a few checks for GTK_WIDGET_RELIZED and
+ minor changes to gtk_widget_unrealize, we can then remove the check
+ in gtk_widget_real_destroy]
+ means: there is an idle handler waiting for the container to
+ resize it.
+
+GTK_RESIZE_NEEDED:
+ relies on GTK_WIDGET_REALIZED(widget)
+ [puhhh, this isn't rely enforced either..., bla bla ...remove check
+ in gtk_widget_real_destroy]
+ means: a widget has been added to the resize_widgets list of
+ its _toplevel_ container (keep this in mind for GtkViewport).
+ remark: this flag is also used internaly by gtkwindow.c.
+
+GTK_LEAVE_PENDING:
+ a widget is flagged as such if there is a leave_notify event
+ pending for it. it receives this event regardless of a grab or
+ its current sensitivity.
+ [this should be made relying on GTK_REALIZED]
+
+GTK_HAS_GRAB:
+ set by gtk_grab_add, unset by gtk_grab_remove
+ means: widget is in the grab_widgets stack.
+
+GTK_WIDGET_DRAWABLE:
+ a widget is flagged as GTK_WIDGET_VISIBLE and GTK_WIDGET_MAPPED
+ means: it _makes sense_ to draw in a widgets window.
+
+
+
+II. Invariants:
+---------------
+
+This section describes various constraints on the states of
+the widget:
+
+In the following
+
+ A => B means if A is true, than B is true
+ A <=> B means A is true, if and only if B is true
+ (equivalent to A => B and B <= A)
+
+
+1) GTK_WIDGET_DESTROYED (widget) => !GTK_WIDGET_REALIZED (widget)
+ => !GTK_WIDGET_VISIBLE (widget)
+[ The latter is not currently in place, but it should be ]
+
+2) GTK_WIDGET_MAPPED (widget) => GTK_WIDGET_REALIZED (widget)
+
+3) if GTK_WIDGET_TOPLEVEL (widget):
+ GTK_WIDGET_VISIBLE (widget) <=> GTK_WIDGET_MAPPED (widget)
+
+4) if !GTK_WIDGET_TOPLEVEL (widget):
+ widget->parent && GTK_WIDGET_REALIZED (widget->parent) <=>
+ GTK_WIDGET_REALIZED (widget)
+
+5) if !GTK_WIDGET_TOPLEVEL (widget):
+
+ GTK_WIDGET_MAPPED (widget) => GTK_WIDGET_VISIBLE (widget)
+ => GTK_WIDGET_REALIZED (widget)
+
+ widget->parent && GTK_WIDGET_MAPPED (widget->parent) &&
+ GTK_WIDGET_VISIBLE (widget) => GTK_WIDGET_MAPPED (widget)
+
+Note:, the definition
+
+[ GTK_WIDGET_DRAWABLE = GTK_WIDGET_VISIBLE && GTK_WIDGET_MAPPED
+ is made in gtkwidget.c, but by 3) and 5),
+
+ GTK_WIDGET_MAPPED => GTK_WIDGET_VISIBLE
+]
+
+
+
+III. How states are changed:
+----------------------------
+
+How can the user control the state of a widget:
+-----------------------------------------------
+
+(In the following, set flag means set the flag, do appropriate
+actions, and enforce above invariants)
+
+gtk_widget_show:
+ if !GTK_DESTROYED sets GTK_VISIBLE
+
+gtk_widget_hide:
+ if !GTK_VISIBLE for widget
+
+gtk_widget_destroy:
+ sets GTK_DESTROYED
+ For a top-level widget
+
+gtk_widget_realize:
+ if !GTK_DESTROYED sets GTK_REALIZED
+- Calling gtk_widget_realize when the widget is not a descendent
+ of a toplevel is an ERROR.
+
+gtk_container_add (container, widget) [ and container-specific variants ]
+ Sets widget->parent
+
+gtk_container_remove (container, widget)
+ unsets widget->parent
+
+gtk_widget_reparent (widget, new_parent)
+ Equivalent to removing widget from old parent and adding it to
+ the new parent, except that the widget will not be temporarily
+ unrealized if both the old parent and the new parent are realized.
+
+
+gtk_widget_unrealize
+gtk_widget_map
+gtk_widget_unmap
+
+These functions are not meant to be used by applications - they
+are used only by GTK and widgets to enforce invariants on the
+state.
+
+When The X window corresponding to a GTK window is destroyed:
+-------------------------------------------------------------
+
+gtk_widget_destroy is called (as above).
+
+
+
+IV. Responsibilities of widgets
+--------------------------------
+
+Adding to a container
+---------------------
+
+When a widget is added to a container, the container:
+
+ 1) calls gtk_widget_set_parent (widget, container)
+ 2) calls gtk_widget_set_parent_window (widget, window) if
+ the widget is being added to something other than container->window
+ 3) if container is realized, and not widget, realizes widget
+ 4) if container is mapped, and not widget and widget is GTK_VISIBLE,
+ maps widget
+ 5) Queues a resize if the widget is mapped
+
+Note: It would be nice to remove 3) and 4) out of widget specific code
+ since they are of the invariant-enforcing nature, but it is
+ a bit hard, since they can't be done until after 2)
+
+
+Removing from a container
+-------------------------
+
+When a widget is removed to a container, the container:
+
+ 1) Calls gtk_widget_unparent (widget)
+ 2) Sets widget->parent to NULL
+ 3) Queues a resize.
+
+Notes:
+
+ gtk_widget_unparent unrealizes the widget except in the
+ special case GTK_IN_REPARENT is set.
+
+
+At widget creation
+------------------
+
+Widgets are created in an unrealized state.
+
+ 1) The widget should allocate and initialize needed data structures
+
+
+The Realize signal
+------------------
+
+When a widget recieves the "realize" signal it should:
+
+ NO_WINDOW widgets: (probably OK to use default handler)
+
+ 1) set the realized flag
+ 2) set widget->window
+ widget->window = gtk_widget_get_parent_window (widget);
+ gdk_window_ref (widget->window);
+ 3) attach the widget's style
+
+ widget->style = gtk_style_attach (widget->style, widget->window);
+
+ widget with window(s)
+
+ 1) set the REALIZED flag
+ 2) create windows with the parent obtained from
+ gtk_widget_get_parent_window (widget);
+ 3) attach the widget's style
+ 4) set the background color for the new window based on the style
+
+The Map signal
+--------------
+
+ 1) Set the MAPPED flag
+ 2) If the widget has any windows, gdk_window_show those windows
+ 3) call gtk_widget_map for all child windows that are
+ VISIBLE and !MAPPED.
+ 3) Do any other functions related to putting the widget onscreen.
+ (for instance, showing extra popup windows...)
+
+The Unmap signal
+----------------
+
+When a widget receives the unmap signal, it must:
+
+ 1) If the widget has a window, gdk_window_hide that window,
+ 2) If the widget does not have a window, unmap all child widgets
+ 3) Do any other functions related to taking the widget offscreen
+ (for instance, removing popup windows...)
+ 3) Unset GTK_MAPPED
+
+
+The Unrealize signal
+--------------------
+
+When a widget receives the unrealize signal, it must
+
+ 1) For any windows other than widget->window do:
+
+ gdk_window_set_user_data (window, NULL);
+ gdk_window_destroy (window);
+
+ 2) Call the parent's unrealize handler
+
+
+The Widget class unrealize handler will take care of unrealizing
+all children if necessary. [should this be made consistent with
+unmap???]
+
+
+The Destroy Signal
+------------------
+
+Commentary:
+
+ The destroy signal probably shouldn't exist at all. A widget
+ should merely be unrealized and removed from its parent
+ when the user calls gtk_widget_destroy or a GDK_DESTROY event
+ is received. However, a large body of code depends on
+ getting a definitive signal when a widget goes away.
+
+ That could be put in the finalization step, but, especially
+ with language bindings, the cleanup step may need to refer
+ back to the widget. (To use gtk_widget_get_data, for instance)
+ If it does so via a pointer in a closure (natural for
+ Scheme, or Perl), then the finalization procedure will never
+ be called.
+
+ Also, if we made that the finalization step, we would have
+ to propagate the GDK_DESTROY event in any case, since it is
+ at that point at which user-visible actions need to be taken.
+
+
+When a widget receives the destroy signal, it must:
+
+ 1) If the widget "owns" any widgets other than its child
+ widgets, (for instance popup windows) it should
+ call gtk_widget_destroy () for them.
+
+ 2) Call the parent class's destroy handler.
+
+
+The "destroy" signal will only be received once. A widget
+will never receive any other signals after the destroy
+signal (but see the sectionalize on "Finalize" below)
+
+The widget must handle calls to all publically accessible
+functions in an innocuous manner even after a "destroy"
+signal. (A widget can assume that it will not be realized
+after a "destroy" signal is received, which may simplify
+handling this requirement)
+
+
+The Finalize Pseudo-signal
+--------------------------
+
+The finalize pseudo-signal is received after all references
+to the widget have been removed. The finalize callback
+cannot make any GTK calls with the widget as a parameter.
+
+1) Free any memory allocated by the widget. (But _not_
+ the widget structure itself.
+
+2) Call the parent class's finalize signal
+
+
+A note on chaining "destroy" signals and finalize signals:
+---------------------------------------------------------
+
+This is done by code like:
+
+ if (GTK_OBJECT_CLASS (parent_class)->destroy)
+ (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
+
+It may not be completely obvious why this works. Note
+that parent_class is a static variable on a per-class
+basis. So say: we have
+
+ GtkFoo <- GtkBar <- GtkWidget <-GtkObject
+
+And that Foo, Widget, and Object all have destructors, but
+not Bar.
+
+Then gtk_foo_destroy will call gtk_widget_destroy (because
+it was not overridden in the Bar class structure) and
+gtk_widget_destroy will call gtk_object_destroy because
+the parent_class variable referenced by gtk_foo_destroy is the
+static variable in gtkwidget.c: GtkObjectClass.
+
+