[gtkada] Heap corruption and other problems

Dmitry A. Kazakov mailbox at dmitry-kazakov.de
Tue Aug 13 08:31:37 CEST 2013


On Mon, 12 Aug 2013 20:46:29 -0700, you wrote:

> Dmitry A. Kazakov wrote:
>> Glib.Main.Timeout_Add + Gtk.Widget.Queue_Draw from there. It should 
>> not be tighter than 20ms, human eye cannot see any difference anyway. 
>> This is exactly how the refresh engine from AICWL works. It is used 
>> for animated widgets like the oscilloscope, clocks etc. 
> I'd like to see an example of this.  This new way of dealing with main 
> loops is a bit daunting without an example.

It does not have to deal with that. Here is what it does:

   procedure Set_Period
             (  Engine : in out Layered_Refresh_Engine;
                Period : Duration
             )  is
   begin
      if Period /= Engine.Period then
         declare
            Interval : GUInt := GUInt (GDouble (Period) * 1_000.0);
         begin
            if Engine.Timer /= 0 then
               if 0 = Remove (Engine.Timer) then
                  null;
               end if;
               Engine.Timer := 0;
            end if;
            Engine.Timer :=
               Timeout_Add
               (  Interval,
                  Timer'Access,
                  Engine'Address
               );
            Engine.Period := Period;
         end;
      end if;
   end Set_Period;

The timer goes through the list of widgets serviced by the engine and does
Queue_Draw for each. The list elements are weak references which are
automatically invalidated when the referenced widget disappears. Such
elements are removed from the list.

   function Timer (Data : System.Address) return GBoolean is
      Engine : Layered_Refresh_Engine renames
                  Conversions.To_Pointer (Data).all;
   begin
      if Engine.List /= null then
         Engine.Active := True;
         declare
            This : not null access List_Element := Engine.List;
            Next : not null access List_Element := This;
         begin
            loop
               Next := This.Next;
               if Is_Valid (This.Widget) then
                  Queue_Draw (Get (This.Widget));
               else
                  Delete (Engine, This.all'Unchecked_Access);
                  exit when Engine.List = null;
               end if;
               exit when Next = Engine.List;
               This := Next;
            end loop;
         end;
         Engine.Active := False;
      end if;
      return 1;
   end Timer;

Note that this is fully compatible with the event-controlled path of
updating widget. E.g. if you change the widget by some other means (resize
for example) it will get a draw notification independently on the timer.

>> I don't understand this. Your widget must be a descendant of at least 
>> Gtk_Widget_Record.
> No.  I create my own Widgets using Gdk.Window as a base and my own class 
> hierarchy.

Which is the source of your problems. You are throwing overboard almost
everything Gtk has to offer.

>> I am waiting for other problems resolved and GtkAda packaged for 
>> Linux. I can post code snippets from AICWL if you are interested.
> I would appreciate all the help I can get.

Let me know then.

>> Gdk_Window is unusable, IMO.
> That is all I use.  It has become less useful because of Cairo but I 
> wouldn't say it is unusable! :-)

So can see that from its declaration:

   type Gdk_Window is new Glib.C_Proxy;

And from the design POV it does not make any sense to have your stuff as a
window rather than a widget. A widget can be put into a container and used
in thousand useful ways in which a window cannot (be themed, have
properties, styles and so on). You gain nothing by doing it window. A
widget can always be made a window by putting it into one. Since Gtk3
widgets can be transparent because Cairo uses alpha channel.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de


More information about the gtkada mailing list