Saturday, January 21, 2017

Message Service with GtkAda Windows

Now I am turning more attention to driving an A661 protocol Display Application using one of the Message Service (MS) framework applications to enable the display layer window. 

Upon receiving the enable command via an A661 protocol message, the Display Application is now able to display a window for A661 layer 1.  This took a bit of doing.


Previously, my exploratory project (EP) used Microsoft C# as the programming language to implement the Display Application.  I was able to use it for free for study.  It was nice enough to use since it was a visual compiler where widgets could be placed in the window form and had interfaces with Windows that could be looked up online to determine what was needed to respond to mouse clicks, enter text into dialog boxes, refresh the display, etc.

However, Microsoft now wants much bigger bucks than I'm willing to spend to just play around with it.

Therefore, with the new incarnation of the exploratory project that I have dubbed MS I was looking for another language that would interface to Microsoft Windows.  Upon the options was just to use the Mono language that I had used with EP for its Linux version.  There seems to be a Cygwin add-on that is supposed to support Mono running on Windows.  However, after starting downloads, I put it aside.

GNAT GtkAda then became an option.  I had already created a dummy Display Application in Ada where I had implemented a very much partial interface from one of the two MS framework applications.  Just to be able to send the Enable Layer command and have the dummy Display Application respond with the A661 message that the layer was enabled.  Thus using GtkAda, that supports interfaces to Microsoft Windows as well as for Linux, would allow me to keep this preliminary code while adding the ability to actually display something on the console screen.

So to keep busy I have embarked upon such a Display Application that will necessitate incorporating various code or techniques of EP into the MS framework application.  For instance, using the Delivery Identifier of a message topic that has already been built into the MS framework to route a particular A661 message with a particular Widget Id to the application component that has registered to treat the message.

Therefore, the first order of business was to use GtkAda to display a Windows window when the Enable Layer command was received by the Display Application.

GtkAda Learning Experience

It took quite a bit of time (week and half, two weeks) getting started with GtkAda.  I at first let it create a project gpr with Ada and C to include the two C functions that get called to determine if the other application is running using the code from the dummy Display app.  This code is used to determine when to open MS Pipes between the two apps where I use one pipe by one app to transmit to the other where the pipe is opened for receive.  And vice versus for the other app with the other pipe of the pipe pair.

However, the build would then say that the Gtk spec had to be recompiled.  Or with other attempts it would say that the references to C functions were undefined whereas the without GtkAda builds knew how to link them in.  Or, after rewriting a C file in Ada with the references to the Windows functions that are identified in the GNAT installation were undefined – again no such problem with the C functions in the non GtkAda build.  I spent hours and hours on internet searches related to this but the suggestions never solved the problem.

Before removing the C functions completely to just have regular Ada invoking the GtkAda functions of a simple example (that I tried and which ran successfully) I also had combinations where I got
C:\Source\MS\Try12>C:\gnat\2016\bin\gnatbind -x C:\Source\MS\Build11\app11.ali
error: "gtk.ali" not found, "gtk.ads" must be compiled
error message.  Where, of course, gtk.ads can't be recompiled since it is part of the dll files that come with the GtkAda installation.

Anyway, I tried various project gpr file combinations as well as the use of batch files to do the build in make, bind, link steps with none that would build successfully. 

Finally I gave up and removed the use of the C functions meaning that the Display application couldn't first determine whether the MS framework application that it was paired with was running before opening the pipes to it.  That is, just its receive pipe since the dummy Display application hadn't opened the transmit pipe until it was time to send the response to the Enable Layer request back to the framework application.

It still took some fussing to come up with a project file that would successfully build.  However, I finally came up with
with "gtkada";

project App11New is

   for Source_Dirs use ("C:\Source\MS\Try13\srcDisplay\App11", "C:\Source\MS\Utilities");
   for Object_Dir use "C:\Source\MS\Build11";
   for Main use ("C:\Source\MS\Try13\srcDisplay\App11\app11.adb");

   package Builder is
      for Default_Switches ("ada") use ("-s", "-m", "-g", "-k");
   end Builder;

   package Compiler is
      for Default_Switches ("ada") use ("-g");
   end Compiler;

end App11New;
that I run from a batch file that just invokes it with
C:\gnat\2016\bin\gprbuild -P C:\Source\MS\Try13\App11New.gpr

Notice that the project file contains
   for Exec_Dir use "C:\Source\GUI\User_App";
for where to store the exe file.  This is because I had previously found that I had had to copy the GtkAda dll files from their GNAT folder to where I was going to bind and link the executable.  That is, GNAT could find its Ada libraries via the System path but didn't seem to be able to find the GtkAda libraries even though that System path was also defined.  I had found that early on in attempting to build the simple example.

GtkAda Success

In any case, I was then able to build the Display app and by launching it first, the framework app could send the Enable Layer request to the Display app and it would then display a small window to be used for the A661 layer 1.

However, its minimize, full screen, and terminate buttons of the upper right of the standard Windows window didn't work as they had in the simple example.

Doing some further internet searches I found GtkAda function calls to specify the size to be used for the window and to center it.  Including these calls didn't compile - at least the one to specify the starting size.  However, I then found that the more recent GtkAda release that I was using had eliminated it and suggested another.  But the search also turned up a third that I tried.

Thus, always starting the Display app first, the larger window displayed centered on the console screen.

Double checking the simple example it did its calls as
with Gtk.Main, Gtk.Window;

procedure Simple_Application is
   Window : Gtk.Window.Gtk_Window;
begin
   Gtk.Main.Init;
   Gtk.Window.Gtk_New (Window);
   Gtk.Window.Show (Window);
   Gtk.Main.Main;
end Simple_Application;
where I had found that Main enabled a loop to treat events.

In my code I had done the various setups including Gtk.Main.Main at initialization time but had left Gtk.Window.Show until the Enable Layer had been received and the response had been sent.

Changing my initialization sequence to
    -- Initializes GtkAda
    Gtk.Main.Init;

    -- Create the basic window
    Gtk.Window.Gtk_New
    ( Window   => Win,
      The_Type => Gtk.Enums.Window_Toplevel );
   
    Set_Position( Win, Win_Pos_Center );
   
    Set_Default_Size( Win, 500, 300 );

    --  Set a window title
    Gtk.Window.Set_Title
    ( Window => Win,
      Title  => "Layer 1" );
where use statements had been added in the meantime so that the leftover dot notation is no longer needed.

And moving the call to Main to after the Show; that is,
    if Request.Command = A661.Types.UA_Request then

      if Request.Request = A661.Types.Layer_Active then

        Index := Index + A661.Types.A661_Request_Structure_Size;

        -- Send Notify that the layer is active back to the
        –- user application
        Send_Notify_Layer_Active;

        -- Show the window.
        Gtk.Window.Show_All( Win );

        -- Signal handling loop
        Gtk.Main.Main;

        return True;

      elsif ...
eliminated the problem.

The displayed window (prior to resizing it) is


GtkAda To Do

Now I can continue attempting to redo some of the past C# work involving buttons, list boxes, edit boxes, and such along with sending mouse clicks on the widgets back to the A661 user application program (the framework application) and having it send commands back to the display program to hide the clicked button and display a different one or produce a different page, etc thus mimicking aircraft MCDU behavior.


I'll surely discover some other gotchas between the documented GtkAda function calls and changes made in the newer release.

No comments: