Search code examples
cxmlgtk4

How to capture names of clicked folders in the right pane of a GtkFileChooserWidget (GTK4)?


My box runs Ubuntu 21.10. I use GTK4, C-language and XML description of the GUI. I am new to GUIs in general, and to GTK4 in particular.

The program uses a GtkFileChooserWidget because I need a Widget which, in addition to being embedded to the main window, displays in its right pane the list of files & folders according to the navigation of the user.

The goal of this program is simply to capture the name of the folder (folder's names only, not file's names) the user just clicked on in the list of files & folders of the right pane of the GtkFileChooserWidget.

The code (see below) has 2 issues:

  1. the name of the captured folder is not that of the click that has just been performed, but that of the previous click;
  2. the program also capture the names of the folders after clicking on the 'full path' displayed in the upper part of the GtkFileChooserWidget, which this program should not authorize.

Here is the XML-code:

<?xml version="1.0" encoding="UTF-8"?>
<interface>
  <requires lib="gtk" version="4.0"/>
  <object class="GtkWindow" id="window1">
    <property name="child">
      <object class="GtkGrid" id="grid1">
        <child>
          <object class="GtkFrame" id="frame1">
            <child>
              <object class="GtkFileChooserWidget" id="folderChooserWidget1">
                <property name="action">select-folder</property>
                <property name="select-multiple">True</property>
              </object>
            </child>
          </object>
        </child>
      </object>
    </property>
  </object>
</interface>

Here is the C-code:

#include <gtk/gtk.h>
#include <glib/gprintf.h>

static void on_click (GtkGestureClick *controller, int n, double x, double y, GtkFileChooser *folderChooser)
{
  GFile *file = NULL;
  char *basename = (char *)NULL;

  file  = gtk_file_chooser_get_file (folderChooser);
  if (file == NULL)
    g_printf ("No folder selected!\n");
  else
  {
    basename = g_file_get_basename (file);
    g_printf ("folder selected: %s\n", basename);
    g_free (basename);
  }
}    

static void app_activate (GApplication *application)
{
  GtkApplication *app;
  GtkBuilder *builder1;
  GObject *window1;
  GObject *folderChooserWidget1;

  app = GTK_APPLICATION (application);

  builder1 = gtk_builder_new ();
  gtk_builder_add_from_file (builder1, "xml.ui", NULL);

  window1 = gtk_builder_get_object (builder1, "window1");
  gtk_window_set_application (GTK_WINDOW (window1), app);

  folderChooserWidget1 = gtk_builder_get_object (builder1, "folderChooserWidget1");
  GtkGesture *controller;
  controller = gtk_gesture_click_new ();
  gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (controller), 0);
  gtk_gesture_single_set_exclusive (GTK_GESTURE_SINGLE (controller), TRUE);
  gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (controller), GTK_PHASE_CAPTURE);
  g_signal_connect_after (controller, "pressed", G_CALLBACK (on_click), GTK_FILE_CHOOSER (folderChooserWidget1));
  gtk_widget_add_controller (GTK_WIDGET (folderChooserWidget1), GTK_EVENT_CONTROLLER (controller));


  gtk_widget_show (GTK_WIDGET (window1));

  g_object_unref (builder1);
}    

int main (int argc, char *argv[])
{
  GtkApplication *app;
  int status;

  app = gtk_application_new ("xx.yy.zz", G_APPLICATION_FLAGS_NONE);
  g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
  status = g_application_run (G_APPLICATION (app), argc, argv);

  g_object_unref (app);

  return (status);
}

Solution

  • Regarding issue #1, I built a project on my Ubuntu 20.04 machine using your code and "ui" definition. When I ran the program, I could bring up the file chooser and I experienced the selection lag that you noted. That made me focus in on your signal connection statement.

        g_signal_connect_after (controller, "pressed", G_CALLBACK (on_click), GTK_FILE_CHOOSER (folderChooserWidget1));
    

    That made me consider that the call to signal handler possibly should not come during the click of the mouse button, but rather on the release of the mouse button. So, I made a small revision to your signal connection statement.

        g_signal_connect_after (controller, "released", G_CALLBACK (on_click), GTK_FILE_CHOOSER (folderChooserWidget1));
    

    After I made that change and rebuilt the program, the file chooser seemed to behave in the manner you were after. Please try this small modification and see if that resolves issue #1.

    Regards.