Re: request for review: description of GtkSignals



On Sun, 5 Sep 1999, David Benson wrote:

> I am trying to write the signal section of the
> Gtk+ Reference Doc.  I think I understand signals
> fairly well (by reading the source code, primarily)
> but I thought it would be good to post a preliminary
> description.  Please point out any inaccuracies
> or shortcomings of this description, but remember that
> I'm trying to keep it brief.  (Also descriptions of each
> individual function will help cope with the details.)
> 
> I know it is bad-form to crosspost, I am very sorry.
> I am trying to solicit as much feedback as possible,
> since I am taking the accuracy of this section
> somewhat seriously.
> 
> 
> 			Thanks for your time,
> 			Dave Benson
> 			daveb@ffem.org
> 
> =====================================
> 
> Signals are a way to get notification when something happens.
> Every GtkSignal is identified by a name (a string) and a GtkType
> of a GtkObject.

signals are identified by a class (name) and a signal name,
in the notation <class-name>::<signal-name> (though you've outlined
that, the <class-name> being identified through a GtkType id is merely
an implementation detail). it is important to note
that signals are not uniquely identifyable through the pure signal
name, because that same name can identify different signals on
different class branches, e.g. you could have

GtkButton::clicked
and
GtkDrawingArea::clicked

because neither of these two classes derive from the other.

>  When they are allocated initially
> they are also assigned a unique unsigned integer.

i'd more talk about "creation" here, as a signal is not simply
a structure that gets "allocated". valid signal ids btw start
with 1 (not 0, that is used as a return value for failure
notification).

> Each is also tied to an array of types that describes
> prototype of the function pointer(s) you may
> connect to the signal.

>  Finally, every signal has
> a default method that is given by a function pointer
> in its class structure:  it is run every time the signal
> is emitted.

it is "usually" run...

for instance you can have a RUN_LAST signal, e.g. any of
the GtkWidget::*_event signals and stop emission of that
signal through a handler, in that case the default handler
will not get invoced.

> Signals are used by everyone, but they are only
> instantiated on a per class basis-- so you don't (and
> probably can't) call gtk_signal_new unless you are writing
> a new GtkObject type.

that is right, you may only use gtk_signal_new() if you implement
a new widget (object). there are specialized functions for
creation of user signals though:
gtk_object_class_user_signal_new()
gtk_object_class_user_signal_newv()

these functions will create new signals just as gtk_signal_new()
does, with the exception of the default handler (function pointer
to class method) slot: there is none.

> There are two basic actions in the signal handling game.
> If you want notification of an event, you must _connect_
> a function pointer/gpointer to that signal.

i'd s@pointer/gpointer@pointer@ here, since "function pointer"
is a generic term, and you don't actually pass a

(gpointer) my_function

into gtk_signal_copnnect(), but rather a

(GtkSignalFunc) my_function

pointer.


>  And if you
> are the function which causes the event, you must _emit_
> the signal.

i'm not sure i understand what you mean here, did you intend
to say

"functions that want to notify the user of certain actions,
do _emit_ signals." ?

> A lot of the complexity in GtkSignal comes from the
> parameter system.  When you define a GtkSignal (remember
> that there is only one per class-instance/name pair),
> you must specify the number of parameters and a list of
> their GtkTypes; the return value is treated like a final
> parameter which is a pointer to the return type.

"GtkSignal" is actually a structure, which itself is not as
complex actually. you might want to say "a lot of the complexity
in gtksignal.c comes from ...", but then again, you are falling
back to a description of implementation details again, and for the
RDP, it is more the API and general concepts that matter.
also, there is one signal per _class-branch_/name pair, i.e. with
GtkButton::clicked being introduced in the GtkButtonClass implementation,
you cannot create further ::clicked signals in derived classes anymore,
e.g. GtkToggleButton. thus ::clicked is taken for the complete class
branch starting out at GtkButton.

> The functions responsible for translating an array of GtkArgs
> to your C compilers normal semantics are called Marshallers.
> They are identified by return_value__parameter_list,
> for example a C function returning a gboolean and taking a gint
> can be invoked by the gtk_marshal_BOOL__INT function.

you should note that only a limited set of gtk_marshal_* functions
exist, namely those that are listed in gtkmarshal.list. for implementations
of new widgets, you often find yourself in the need to implement a new
specialized marshaller.

> Finally, signals provide some reentrance protection.
> This means that if you specify GTK_RUN_NO_RECURSE and you
> are handling a signal and you somehow emit that signal
> again, the call won't happen until the after the function
> returns (also if you emit it multiple times, it is only
> re-invoked once, in this mode).

though you are in principle telling the right thing here, i think that
this paragraph should be reworded. first, handler invocations during
signal emissions are in so far already reentrant, that you may destroy
or block a handler while it is currently being executed, and may even
emit !RUN_NO_RECURSE signals from whithin a handler of that same signal
without screwing up pointers, memory etc. however, in such a case you
better make damn sure to re-emit the signal conditionally, so you
don't end up in a recursion loop ;)
then you should note, that even !RUN_NO_RECURSE signals are often
recursively emitted, but usually not for the same signal/object
combination, e.g. if you emit ::draw for a VBox in a widget tree like

VBox
 + Label

at the point where gtk_label_draw is called, the GtkWidget::draw signal
is already emitted twice (or recursively), once for the VBox from your
code and from within the VBox' draw handler for Label. however, the
signal is not emitted recursively for one signal/object combination, and
that is the case where RUN_NO_RECURSE would actually take effect (to
the extend you already outlined).


david, i really apprechiate that you volounteered to work on this topic,
especially as the signal system is one of gtk+'s most usefull and
prominent features and indeed comes with a certain complexity. that being
said, i'd like to suggest that you try to more concentrate on the API side
of this and outline the available mechanisms with signals a bit more,
probably with the help of some short examples (even for this reply i used
a few short examples already, because describing the pure signal system
itself without actuall applications, is far to dry of a topic to be easily
comprehensible).
with "available mechanisms", i'm referring to the ability to block certain
signal handlers (of course also the ability to destroy them), stop emissions,
and the usefullness of RUN_LAST signals in regards to normal and _after
connections. especially the _after connections for RUN_LAST signals are
not only used for notification, but also for cusomization as well, a good
example here is the GtkWidget::delete_event signal, where with returning
TRUE you can intercept automated destruction of widgets (however, in
this specific case you don't need to _after connect, because GtkWidgetClass
does not implement a default handler for this signal).

as i said already, i'm aware that signals are not the easiest topic to cover,
so feel free to get back to me and ask any questions you may have, i'm more
then willing to give you a hand on this topic.

oh, and for the reader to get an initial picture of how signal emissions
work, i think it's a good idea to give a X point overview of signal
emissions in general:

Emission of a signal for an Object:
1) For RUN_FIRST signals, the class handler is invoced if specified in the
   class structure with a valid function pointer (i.e. not NULL).
2) The normal signal handlers are run in the order in which they got
   connected (normal here means signal_connect or signal_connect_object).
3) For RUN_LAST signals, the class handler is invoced if specified in the
   class structure with a valid function pointer (i.e. not NULL).
4) After-connected signal handlers are run in the order in which they got
   connected.


---
ciaoTJ




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]