[prev in list] [next in list] [prev in thread] [next in thread] 

List:       gtkmm
Subject:    [gtkmm] [Fwd: my breif explaination of signals.]
From:       Todd Dukes <tdukes () ibmoto ! com>
Date:       1999-05-11 18:07:01
[Download RAW message or body]

[Attachment #3 (message/rfc822)]

This is a multi-part message in MIME format.

Peter Berlau wrote:
> 
> Todd Dukes <tdukes@ibmoto.com> writes:
> Hi Todd,
[...]
 > But finally:
> all newer examples using the signal-concept and
> a connector class,
> Can You tell me where I can more learn about this,
> and how to use this,
> I think I haven't understand this things, but they are
> very important.
> 
> Many thanks for help and patience with me
> and also for understanding my bad english
> must be very hard,
> 
> Wish You all the very best
> Peter
> --
> Peter Berlau
> email pberlau@muenster.de

I have copied this to the gtkmm list also so someone can tell
you if I am slightly confused about how this really works :)

There were some signal documents on the gtk-- home page hiding 
somewhere. None of them specifically describe the exact signaling
system used by gtk--. There is a steep learning curve, but it is short
and the signals are not too hard to use once you figure it out.
I have also attached a brief introduction below. It is really too
short and I apologize for that. I really wish I was better at
explaining this type of thing.

Todd.
-- 
   | Todd Dukes                      E-MAIL:  tdukes@ibmoto.com |
   | Motorola Somerset                  Phone:   (512) 424-8008 |
   | 6200 Bridgepoint Parkway Building #4 MS OE70               |
   | Austin, Texas 78730                                        |
["mysig.txt" (text/plain)]

Signals are instantiated templates. They appears as members of the
widget classes. They can also be members of classes you create by
having the class inherit from Gtk_Base.  You can connect signals to
signals, signals to functions, and signals to methods. By functions
and methods in the previous sentence; I mean functions as being free
standing functions not scoped within a class, and I mean methods as
being a function that is scoped within a class. There is a
connect_to_* function for each. ( replace * with one of function,
signal, method.)

The forms of these are:
  connect_to_function ( signal, function_ptr, arg1, arg2, ... );
  connect_to_signal ( signal, signal, arg1, arg2, ... );
  connect_to_method ( signal, object_ptr, method_ptr, arg1, arg2, ... );

In the above:
  
    signal is a signal member of a widget or any other Gtk_Base 
       descendant.

    funtion_ptr is the address of a function. Example:
	int f();
	&f; // function_ptr

    arg1, arg2, ... are the optional arguments to the signal. The number
	and type of these are indicated in the template
	instantiation. The signals will be of type SignalX
	where X is an integer between 0 and 6 inclusive. The symantics
	of the signals are not shown in the instantiation, but are
	using clear from the type.

    object_ptr is the address of an object. Example:
	Gtk_Window w;
	&w; // object_ptr

    method_ptr is the address of a member. Example:
	class a { int m(); };
	&(a::m); // method_ptr


If a signal in a class is public, any other code can connect to that
signal. Signals can be called like functions. Usually this is done
from code inside the owner of the signal. ( Although I can't see how
this is enforceable. I believe methods and functions that have
visibility of the signal can call it. I just don't think it is a good
idea.) When a signal is triggered by being called, it notifies
everyone who has been attached to the signal. This gives you great
flexibility and is type safe.

The connection is remembered by both the connector and the
"connectee".  By connectee I mean the method, or signal that was
connected to.  When a signal connection goes out of scope (ie the
connectee is destroyed), the signal connection is automatically
removed. An example of why this is neccessary: 

    Suppose you have three objects A, B, and C. A has a signal 'sig'
    that is connect to methods in B and C. Then B is deleted. If the
    destruction of the signal connection to B is not automatically
    removed, the next time sig is emitted from A you would get a
    sigsegv. In the current signaling system, this problem is avoided
    automatically. ( There may still be a few pathological cases where
    you can get into trouble, but they should not normally occur.)


The problem first encountered with using signals is the complexity of
the error message you get when you type something in incorrectly when
connecting to a signal. Sometimes it is obvious what is wrong. Other
times I have found it easiest to try to find an example of the connection
that works and try to figure out what is different with the one
that doesn't work.


Received: from teal.ece.ucdavis.edu (kenelson@teal.ece.ucdavis.edu [169.237.32.142])
	by scarlet.ece.ucdavis.edu (8.8.7/8.8.7) with ESMTP id MAA15641
	for <kenelson@scarlet.ece.ucdavis.edu>; Tue, 11 May 1999 12:08:05 -0700 (PDT)
Received: from teal.ece.ucdavis.edu (kenelson@localhost)
	by teal.ece.ucdavis.edu (8.8.7/8.8.7) with ESMTP id MAA20180;
	Tue, 11 May 1999 12:08:04 -0700 (PDT)
Message-Id: <199905111908.MAA20180@teal.ece.ucdavis.edu>
X-face: 
 RinRV?cII^~g?cLc9;-D}8xnP^:6hX}*,%&@y"6p7xm^Z]V<7(`zzI!/#s%[2G'fTVC+b"*
 4eYfecJ4=,gHu4o_{Z[VG{Em*{tC^LKZ6eUDc?PI0@dk}3"kJ7*"y8*hMv\qz[C5djlU#AQh0Cq.%W
 @2kSd~S<<NcD7L4'O#`737_IEe02\s!gB6HW13]sD)'$+''!eRE7jPH\G(R&(+:Tu8bs[kr?ixX}x!
 -6`4*-B[UB_Wl!rZyL/$R(xi`vb"+t6osqR?gPX^r);Zpm'5(b/Rs[uGBN>&}]!;ZNm(wUE4=
X-url: http://www.ece.ucdavis.edu/~kenelson
To: gtkmm@modeemi.cs.tut.fi
cc: kenelson@ece.ucdavis.edu
Subject: Re: [gtkmm] Handles and such. 
In-reply-to: Your message of "11 May 1999 19:06:08 PDT."
             <m3d8071qpr.fsf@linux2.worldnet.fr> 
Date: Tue, 11 May 1999 12:08:04 -0700
From: Karl Nelson <kenelson@ece.ucdavis.edu>

In message <m3d8071qpr.fsf@linux2.worldnet.fr>Guillaume Laurent writes
>Karl Nelson <kenelson@ece.ucdavis.edu> writes:
>
>> Auto_ptr and reference counting are just concepts I was using to explain
>> the concept of having an obituary service like you just described.
>> 
>> Auto_ptr just meant send out the funeral notices as soon as the
>> handle dies.  (Thus cutting the reference count of the object to
>> zero as the handles who are told of the impending death let go of
>> the object.  Then all have let go the object goes away.)
>
>You seriously reconsidered your point then. My main gripe against your 
>design was this (from a message of yours) :
>
>--8<--------------------
>> auto_ptr a=foo();
>> ref_ptr b=a;  // this will still be treated as a auto_ptr.
>>
>> If the user really wanted to make it into a ref_ptr they should
>> give the ownership to the ref_ptr
>> 
>> auto_ptr a=foo();
>> ref_ptr b=owns(a);  // extend the life time to that of b
>> 
>> If they want to make it an ref_ptr they do so
>> 
>> ref_ptr a=foo();
>> auto_ptr b=a;  // this will be treated as a ref_ptr
>> 
>> If they want to shorten the life span give the ownership to
>> the autoptr.
>> 
>> ref_ptr a=foo();
>> auto_ptr b=owns(a); // now a is limited to the lifetime of b.
>--8<--------------------
>
>No way I'd ever use such a framework. At any given point, you just
>can't tell whether a ref_ptr or auto_ptr is actually behaving like
>one.

That sequence is still possible to be coded, but because of your
objections I broke the behaviour allong a set of lines such that
it is conceptually unlikely.

Now there are two object types.

   ObjectReferenced
         ^
         |
   ObjectScoped

An ObjectReferenced is a purely reference counted object.
It can only be pointed to by Reference Handle.

A ObjectScoped is free to die at early is its handles are
willing to negotiate.  It can be pointed to by Handles
of type Reference, Extend, and Limit.  However, if even 
a single handle is of type Reference it can not go early.

So now let us look over that sequence again.

If I specialize a Limit handle to consider Ownership
(which the object tracks) and call it an auto_ptr
and typedef a ref_ptr to Extend, my previous example
will do exactly what I described. 

On the other hand if I define ref_ptr to Reference,
then it would give exactly the behavior you expect.

The problem as I read it was that you felt the ref_ptr
concept was not good if it was negotiable to free
early.  So I have split that concept away to 
extend.  Extend lengths the lifetime of an object, but
does not hold it if the object must go away.  Extends
are safer the References in that if the object can
possibly go away early then a Extends are capable of
cleaning up in that event.

You don't object to the possibly that one could define
a system with that behavior?

>> What I propose is a funeral service for objects.  
>>   * Objects have a self maintained list of interested parties 
>>     in the lifetime of an object.  
>>   * When the funeral notice goes out those parties receive
>>     notice, remove themselves from the list, and perform some action 
>>   * Funeral notices may be sent before the object is actually gone.
>>     (Auto_ptr/Limit type handles are used for requesting premature 
>>     notice based on their own lifetime.)  
>
>OK, but this has nothing to do with auto_ptrs or reference counted
>ptrs in particular.

Nothing other than if a handle can be set up to receive these
notices and give behavior similar to auto_ptr.

>>   * Object are reference counted and responsible for themselves.
>>   * Objects commit suicide when their reference count reaches zero.
>>     (Or this could be done with a GC system, but the idea is the same.)
>
>A GC would make these two things above much simpler. Indeed the idea
>is not incompatible with what you've implemented (or what I suppose you've
>implemented). It just replaces the ref_count part, and thus simplifies 
>things a lot.

I am not sure how much it would simplify things to have GC as then
all programs built with Gtk-- would need to be GC as well.  However
it is a minor point as reference/unreference are virtual functions
in this system and could be overriden to do nothing if some other
system is controlling the lifetime of the object.
(per your observation that we didn't need to reference count objects
in the Gtk-- system, but do for things that are outside.)

I am not sure how things can get simpler than the classical
reference counting system with standard double lock deletion.
(I took it from both gtk and other places in literature.)
GC offers no benifit over reference counting unless there
are backedges in the system.  (which gtk-- doesn't really need.)
However, there is nothing demanding an reference count being used
on the object.  If you don't use the reference counter it is 
just 32 dead bits.


class ObjectReferenced
  {
   protected:
     // count of current references
     unsigned int obj_count_    :24;

     // indicates object generated through an interface that marks dynamic
     unsigned int obj_dynamic_   :1;

     // indicates object will delete when count reachs zero
     //(only if dynamic_ set)
     unsigned int obj_managed_   :1;

     // indicates delete called on object 
     unsigned int obj_destroyed_ :1;

     // increase reference count
     virtual void reference();

     // decrease reference count (and possibly delete)
     virtual void unreference();

   public:
     ObjectReferenced();
     virtual ~ObjectReferenced();
  };

void ObjectReferenced::reference()
  {
   // if we exceed the int limit,  we should unset dynamic_
   if (!(++obj_count_))
     obj_dynamic_=0;
  }

void ObjectReferenced::unreference()
  {
   if (obj_count_)
     obj_count_--;
   if (!obj_count_&&obj_dynamic_&&obj_managed_&&!obj_destroyed_)
     {
      obj_destroyed_=1;
      delete this;
     }
  }


Received: from teal.ece.ucdavis.edu (kenelson@teal.ece.ucdavis.edu [169.237.32.142])
	by scarlet.ece.ucdavis.edu (8.8.7/8.8.7) with ESMTP id MAA15937
	for <kenelson@scarlet.ece.ucdavis.edu>; Tue, 11 May 1999 12:47:08 -0700 (PDT)
Received: from teal.ece.ucdavis.edu (kenelson@localhost)
	by teal.ece.ucdavis.edu (8.8.7/8.8.7) with ESMTP id MAA20423;
	Tue, 11 May 1999 12:47:07 -0700 (PDT)
Message-Id: <199905111947.MAA20423@teal.ece.ucdavis.edu>
X-face: 
 RinRV?cII^~g?cLc9;-D}8xnP^:6hX}*,%&@y"6p7xm^Z]V<7(`zzI!/#s%[2G'fTVC+b"*
 4eYfecJ4=,gHu4o_{Z[VG{Em*{tC^LKZ6eUDc?PI0@dk}3"kJ7*"y8*hMv\qz[C5djlU#AQh0Cq.%W
 @2kSd~S<<NcD7L4'O#`737_IEe02\s!gB6HW13]sD)'$+''!eRE7jPH\G(R&(+:Tu8bs[kr?ixX}x!
 -6`4*-B[UB_Wl!rZyL/$R(xi`vb"+t6osqR?gPX^r);Zpm'5(b/Rs[uGBN>&}]!;ZNm(wUE4=
X-url: http://www.ece.ucdavis.edu/~kenelson
To: gtkmm@modeemi.cs.tut.fi
cc: kenelson@ece.ucdavis.edu, Peter Berlau <pberlau@muenster.de>
Subject: Re: [gtkmm] [Fwd: my breif explaination of signals.] 
In-reply-to: Your message of "Tue, 11 May 1999 13:07:01 PDT."
             <373871C5.F822D50A@ibmoto.com> 
Date: Tue, 11 May 1999 12:47:06 -0700
From: Karl Nelson <kenelson@ece.ucdavis.edu>

>I have copied this to the gtkmm list also so someone can tell
>you if I am slightly confused about how this really works :)

Just a few minor corrections, but otherwise correct.  There
is only one callback data slot in connects.  (The new
system in development has more than one, gets rid of the
pathological cases, and gives better errors, but is still
too alpha to incorperate.) 

--Karl

===========

Signals are lists of callbacks. They appear as members of the
widget classes. They can also be members of classes you create by
having the class inherit from Gtk_Signal_Base.  You can connect signals to
signals, signals to functions, and signals to methods. By functions
and methods in the previous sentence; I mean functions as being free
standing functions not scoped within a class, and I mean methods as
being a function that is scoped within a class. There is a
connect_to_* function for each. ( replace * with one of function,
signal, method.)

The forms of these are:
  connect_to_function ( signal, function_ptr [, arg1] );
  connect_to_signal ( signal, signal [, arg1] );
  connect_to_method ( signal, object_ptr, method_ptr [, arg1] );

In the above:
  
    signal is a signal member of a widget or any other Gtk_Signal_Base 
      descendant.  It has a "signiture" which is a list of 
      argument types which are matched against connected functions.
      Signal2<int,int> only accepts functions like void foo(int,int);

    funtion_ptr is the address of a function. Example:
	int f();
	&f; // function_ptr

    arg1, arg2, ... are the optional arguments to the signal. The number
	and type of these are indicated in the template
	instantiation. The signals will be of type SignalX
	where X is an integer between 0 and 6 inclusive. The symantics
	of the signals are not shown in the instantiation, but are
	using clear from the type.

    object_ptr is the address of an object. Example:
	Gtk_Window w;
	&w; // object_ptr

    method_ptr is the address of a member. Example:
	class a { int m(); };
	&(a::m); // method_ptr


If a signal in a class is public, any other code can connect to that
signal. Signals can be called like functions. Usually this is done
from code inside the owner of the signal. ( Although I can't see how
this is enforceable. I believe methods and functions that have
visibility of the signal can call it. I just don't think it is a good
idea.) When a signal is triggered by being called, it notifies
everyone who has been attached to the signal. This gives you great
flexibility and is type safe.

The connection is remembered by both the connector and the
"connectee".  By connectee I mean the method, or signal that was
connected to.  When a signal connection goes out of scope (ie the
connectee is destroyed), the signal connection is automatically
removed. An example of why this is neccessary: 

    Suppose you have three objects A, B, and C. A has a signal 'sig'
    that is connect to methods in B and C. Then B is deleted. If the
    destruction of the signal connection to B is not automatically
    removed, the next time sig is emitted from A you would get a
    sigsegv. In the current signaling system, this problem is avoided
    automatically. ( There may still be a few pathological cases where
    you can get into trouble, but they should not normally occur.)
    (currently connections to dynamic signals are a basket case.)


The problem first encountered with using signals is the complexity of
the error message you get when you type something in incorrectly when
connecting to a signal. Sometimes it is obvious what is wrong. Other
times I have found it easiest to try to find an example of the connection
that works and try to figure out what is different with the one
that doesn't work.


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic