gtkadagtkada

How to create a file chooser with GtkAda?


I'm trying to create an application with GtkAda and need the user to select a file from his PC. However, I found no way to create a file chooser without leading to this error: raised PROGRAM_ERROR : unhandled signal.

Using Glade 3.22.1

I tried creating a file chooser button and link it to a file chooser dialog. It leads to the same error.


Without Glade

I tried creating a file chooser dialog and file chooser button in GPS but same error.

Then I found the Gtkada.File_Selection package. Its description says it handles himself the signals and only needs a single function. Sadly, it leads to the same fateful error.

I'm working on Fedora 29. GtkAda version 2018, GPS 2018 and GNAT 8.3.1.

Log_Filter_Handlers.ads

with Gtkada.File_Selection;   use Gtkada.File_Selection;

package Log_Filter_Handlers is

   Retour : Unbounded_String;


   procedure Button_Select_File_Clicked
     (Self : access Gtk_Button_Record'Class);

end Log_Filter_Handlers;

Log_Filter_Handlers.adb

   procedure Button_Select_File_Clicked
     (Self : access Gtk_Button_Record'Class) is

   begin

      Retour := To_Unbounded_String
        (File_Selection_Dialog (Title       => "Select your file",
                                Default_Dir => "",
                                Dir_Only    => False,
                                Must_Exist  => True) );

   end Button_Select_File_Clicked;

Gtkada-File_Selection.ads

package Gtkada.File_Selection is

function File_Selection_Dialog

      (Title       : Glib.UTF8_String := "Select File";
      Default_Dir : String := "";
      Dir_Only    : Boolean := False;
      Must_Exist  : Boolean := False) return String;

end Gtkada.File_Selection;

As soon as the application creates a file chooser widget (be it dialog or button), in this case by calling Button_Select_File_Clicked. It immediately leads to this error: raised PROGRAM_ERROR : unhandled signal

I'm having some warnings too

Gtk-Message: 10:43:33.615: Failed to load module "pk-gtk-module"

Gtk-Message: 10:43:33.615: Failed to load module "canberra-gtk-module"

Gtk-Message: 10:43:33.616: Failed to load module "pk-gtk-module"

Gtk-Message: 10:43:33.616: Failed to load module "canberra-gtk-module"

Fontconfig warning: "/home/bob/Applications/Gnat_IDE/Gnat-community/etc/fonts/fonts.conf", line 86: unknown element "blank"

(log_filter_main:24417): Gtk-WARNING **: 10:43:33.841: Could not load a pixbuf from icon theme.

This may indicate that pixbuf loaders or the mime database could not be found.

Thank you.


Solution

  • It's hard to say what causes the unhandled signal error. You could consider making a stack trace to see where the exception is raised (see also the example on Rosetta code).

    The example below works on GNAT CE 2019. You could test it in your own environment to see if the problem persists, or test your own code with latest version of GtkAda found on GitHub.


    Update

    A quick search reveals that a Program_Error with message "unhandled signal" is never raised from GtkAda. In fact, it seems that this kind of exception can only occur in the GNAT/Ada run-time (see init.c and seh_init.c). And while seh_init.c is used only by the run-times targeting Win32 and Cygwin (see comments near the beginning of that file), init.c, is used in various other run-times including the one for Linux. Hence, I think that the Program_Error you observe is raised in init.c because some kernel signal cannot be handled by the GNAT/Ada run-time.

    You might obtain some additional information by tracing the signals send to your application (see also this post on SO):

    strace -e 'trace=!all' <program_name>
    

    main.adb

    with File_Selection_Demo;
    
    procedure Main is
    begin
       File_Selection_Demo.Run;
    end Main;
    

    file_selection_demo.ads

    package File_Selection_Demo is
    
       procedure Run;
    
    end File_Selection_Demo;
    

    file_selection_demo.adb

    with Ada.Text_IO;
    
    with Gtk.Main;
    with Gtk.Widget;
    with Gtk.Builder;
    with Gtk.Window;
    with Gtk.Button;
    with Gtk.GEntry;
    
    with Gtkada.File_Selection;
    
    with Glib;       use Glib;
    with Glib.Error; use Glib.Error;
    
    package body File_Selection_Demo is
    
       --  Widgets
       Builder : Gtk.Builder.Gtk_Builder;
       Window  : Gtk.Window.Gtk_Window;
       Button  : Gtk.Button.Gtk_Button;
       GEntry  : Gtk.GEntry.Gtk_Entry;
    
    
       procedure Destroy_Event_Callback
         (Widget : access Gtk.Widget.Gtk_Widget_Record'Class);
    
       procedure Clicked_Event_Callback
         (Button : access Gtk.Button.Gtk_Button_Record'Class);
    
    
       ---------
       -- Run --
       ---------
    
       procedure Run is
    
          use Gtk.Builder;
          use Gtk.Window;
          use Gtk.Button;
          use Gtk.GEntry;
    
          Success : GUint;
          Error   : aliased GError;
    
       begin
    
          --  Initialize GtkAda.
          Gtk.Main.Init;
    
          -- Construct a Gtk_Builder instance and load our UI description.
          Gtk_New (Builder);
    
          Success := Builder.Add_From_File ("./example.glade", Error'Access);
          if Success = 0 then
             Ada.Text_IO.Put_Line ("failed to read Glade file");
             Error_Free (Error);         
             return;
          end if;
    
          --  Entry
          GEntry := Gtk_Entry (Builder.Get_Object ("Entry"));
    
          --  Button
          Button := Gtk_Button (Builder.Get_Object ("Button"));
          Button.On_Clicked (Clicked_Event_Callback'Access);
    
          -- Window
          Window := Gtk_Window (Builder.Get_Object ("Window"));
          Window.On_Destroy (Destroy_Event_Callback'Access);
          Window.Show_All;
    
          -- Start the main event loop
          Gtk.Main.Main;
    
       end Run;
    
    
       ----------------------------
       -- Destroy_Event_Callback --
       ----------------------------
    
       procedure Destroy_Event_Callback
         (Widget : access Gtk.Widget.Gtk_Widget_Record'Class)
       is
       begin
          Gtk.Main.Main_Quit;
       end Destroy_Event_Callback;
    
       ----------------------------
       -- Clicked_Event_Callback --
       ----------------------------
    
       procedure Clicked_Event_Callback
         (Button : access Gtk.Button.Gtk_Button_Record'Class) is
       begin
    
          declare
             Response : String :=
                          Gtkada.File_Selection.File_Selection_Dialog
                            (Title       => "Select your file",
                             Default_Dir => "",
                             Dir_Only    => False,
                             Must_Exist  => True);
          begin
             GEntry.Set_Text (Response);
          end;
    
       end Clicked_Event_Callback;
    
    end File_Selection_Demo;
    

    example.glade

    <?xml version="1.0" encoding="UTF-8"?>
    <!-- Generated with glade 3.16.1 -->
    <interface>
      <requires lib="gtk+" version="3.10"/>
      <object class="GtkWindow" id="Window">
        <property name="can_focus">False</property>
        <property name="title" translatable="yes">GTK File Selector Demo</property>
        <property name="resizable">False</property>
        <property name="window_position">center</property>
        <child>
          <object class="GtkBox" id="HBox">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <child>
              <object class="GtkEntry" id="Entry">
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="margin_left">10</property>
                <property name="margin_right">10</property>
                <property name="margin_top">5</property>
                <property name="margin_bottom">5</property>
                <property name="hexpand">True</property>
                <property name="editable">False</property>
              </object>
              <packing>
                <property name="expand">False</property>
                <property name="fill">True</property>
                <property name="position">0</property>
              </packing>
            </child>
            <child>
              <object class="GtkButton" id="Button">
                <property name="label" translatable="yes">Choose File...</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="receives_default">True</property>
                <property name="margin_left">10</property>
                <property name="margin_right">12</property>
                <property name="margin_top">5</property>
                <property name="margin_bottom">5</property>
              </object>
              <packing>
                <property name="expand">False</property>
                <property name="fill">True</property>
                <property name="position">1</property>
              </packing>
            </child>
          </object>
        </child>
      </object>
    </interface>