c++gtksignalsgladegeany

How to connect signals to handle in gtk+-3.0 application, using glade ang geany ide's on arch linux system?


I tried to make simple application using glade and geany ide's but can't do nothing to connect signals set in glade to my handlers. I used this command to build:

"Short" version:

gcc -Wall -w -g `pkg-config --cflags gtk+-3.0 gmodule-2.0 gmodule-export-2.0` -o "%e" "%f" `pkg-config --libs gtk+-3.0 gmodule-2.0 gmodule-export-2.0`

Full comand:

gcc -Wall -w -g -I/usr/include/gtk-3.0 -I/usr/include/pango-1.0 -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/harfbuzz -I/usr/include/freetype2 -I/usr/include/libpng16 -I/usr/include/libmount -I/usr/include/blkid -I/usr/include/fribidi -I/usr/include/cairo -I/usr/include/lzo -I/usr/include/pixman-1 -I/usr/include/gdk-pixbuf-2.0 -I/usr/include/gio-unix-2.0 -I/usr/include/cloudproviders -I/usr/include/atk-1.0 -I/usr/include/at-spi2-atk/2.0 -I/usr/include/dbus-1.0 -I/usr/lib/dbus-1.0/include -I/usr/include/at-spi-2.0 -pthread -o "%e" "%f" -lgtk-3 -lgdk-3 -lz -lpangocairo-1.0 -lpango-1.0 -lharfbuzz -latk-1.0 -lcairo-gobject -lcairo -lgdk_pixbuf-2.0 -lgio-2.0 -lgobject-2.0 -lglib-2.0 -Wl,--export-dynamic -lgmodule-2.0 -pthread -lglib-2.0 -lglib-2.0

My code (based on russian tutorials): main.cpp

#include <stdio.h> 
#include <gtk/gtk.h>
#include <string.h>
#include <stdlib.h>
#include <libintl.h>
#include <locale.h>
#include <locale>
#include <cstdlib>

//main gtk objects
using namespace std;
/* это тот волшебный объект, который сделает за нас окошко */
GtkBuilder *builder;

/* это виджет окна */
GtkWidget *window;

//function to quit the app without data corruption
void safe_quit (GtkWidget* object, gpointer data)
{
        gtk_main_quit();
}

void click (GtkButton *button, gpointer label)
{
        /* установить метке текст */
        gtk_label_set_text ((GtkLabel*)label, "Привет, Хабр!");
}

/* создание окна в этот раз мы вынесли в отдельную функцию */
static GtkWidget* create_window (void)
{
        
        /* сюда будем складывать ошибки */
        GError* error = NULL;

        /* тут загружаем файл с интерфейсом */
        builder = gtk_builder_new ();
        
        //gtk_builder_set_translation_domain(builder,"ru");
        if (!gtk_builder_add_from_file (builder, "glade1.glade", &error))
        {
                /* загрузить файл не удалось */
                g_critical ("Не могу загрузить файл: %s", error->message);
                g_error_free (error);
        }

        /* получаем виджет окна, чтобы его показать */
        window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
        if (window == NULL)
        {
                /* что-то не так, наверное, ошиблись в имени */
                g_critical ("Ошибка при получении виджета окна");
        }
        
        //g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(safe_quit), NULL);
        
        /* помните, мы подключали сигналы вручную? теперь это происходит автоматически! */
        gtk_builder_connect_signals (builder, NULL);
        gtk_builder_connect_signals (builder, window);
        g_object_unref (builder);
        return window;
}
int main (int argc, char **argv)
{       
        setlocale(LC_ALL, "");
        auto lang = "";
        bindtextdomain(lang, "./locale");
        textdomain(lang);
        //std::cout << gettext("hello, world!") << std::endl;
        auto _ = gettext;
        printf(_("help"));
        
        /* виджет окна */
        GtkWidget *window;
        /* запускаем GTK+ */
        gtk_init (&argc, &argv);
        
        /* вызываем нашу функцию для создания окна */
        window = create_window();
        
        gtk_widget_show (window);
        gtk_window_set_title (GTK_WINDOW(window), "main");
        /* передаём управление GTK+ */
        gtk_main ();
       // printf("f");
        return 0;
}

My glade file: glade1.glade

<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.2 -->
<interface>
  <requires lib="gtk+" version="3.24"/>
  <object class="GtkApplicationWindow" id="window">
    <property name="can-focus">False</property>
    <property name="default-width">440</property>
    <property name="default-height">250</property>
    <signal name="destroy" handler="safe_quit" after="yes" swapped="no"/>
    <child>
      <object class="GtkBox" id="box1">
        <property name="visible">True</property>
        <property name="can-focus">False</property>
        <property name="orientation">vertical</property>
        <child>
          <object class="GtkMenuBar">
            <property name="visible">True</property>
            <property name="can-focus">False</property>
            <child>
              <object class="GtkMenuItem">
                <property name="visible">True</property>
                <property name="can-focus">False</property>
                <property name="label" translatable="yes">_File</property>
                <property name="use-underline">True</property>
                <child type="submenu">
                  <object class="GtkMenu">
                    <property name="visible">True</property>
                    <property name="can-focus">False</property>
                    <child>
                      <object class="GtkImageMenuItem">
                        <property name="label">gtk-new</property>
                        <property name="visible">True</property>
                        <property name="can-focus">False</property>
                        <property name="use-underline">True</property>
                        <property name="use-stock">True</property>
                      </object>
                    </child>
                    <child>
                      <object class="GtkImageMenuItem">
                        <property name="label">gtk-open</property>
                        <property name="visible">True</property>
                        <property name="can-focus">False</property>
                        <property name="use-underline">True</property>
                        <property name="use-stock">True</property>
                      </object>
                    </child>
                    <child>
                      <object class="GtkImageMenuItem">
                        <property name="label">gtk-save</property>
                        <property name="visible">True</property>
                        <property name="can-focus">False</property>
                        <property name="use-underline">True</property>
                        <property name="use-stock">True</property>
                      </object>
                    </child>
                    <child>
                      <object class="GtkImageMenuItem">
                        <property name="label">gtk-save-as</property>
                        <property name="visible">True</property>
                        <property name="can-focus">False</property>
                        <property name="use-underline">True</property>
                        <property name="use-stock">True</property>
                      </object>
                    </child>
                    <child>
                      <object class="GtkSeparatorMenuItem">
                        <property name="visible">True</property>
                        <property name="can-focus">False</property>
                      </object>
                    </child>
                    <child>
                      <object class="GtkImageMenuItem">
                        <property name="label">gtk-quit</property>
                        <property name="visible">True</property>
                        <property name="can-focus">False</property>
                        <property name="use-underline">True</property>
                        <property name="use-stock">True</property>
                      </object>
                    </child>
                  </object>
                </child>
              </object>
            </child>
            <child>
              <object class="GtkMenuItem">
                <property name="visible">True</property>
                <property name="can-focus">False</property>
                <property name="label" translatable="yes">_Edit</property>
                <property name="use-underline">True</property>
                <child type="submenu">
                  <object class="GtkMenu">
                    <property name="visible">True</property>
                    <property name="can-focus">False</property>
                    <child>
                      <object class="GtkImageMenuItem">
                        <property name="label">gtk-cut</property>
                        <property name="visible">True</property>
                        <property name="can-focus">False</property>
                        <property name="use-underline">True</property>
                        <property name="use-stock">True</property>
                      </object>
                    </child>
                    <child>
                      <object class="GtkImageMenuItem">
                        <property name="label">gtk-copy</property>
                        <property name="visible">True</property>
                        <property name="can-focus">False</property>
                        <property name="use-underline">True</property>
                        <property name="use-stock">True</property>
                      </object>
                    </child>
                    <child>
                      <object class="GtkImageMenuItem">
                        <property name="label">gtk-paste</property>
                        <property name="visible">True</property>
                        <property name="can-focus">False</property>
                        <property name="use-underline">True</property>
                        <property name="use-stock">True</property>
                      </object>
                    </child>
                    <child>
                      <object class="GtkImageMenuItem">
                        <property name="label">gtk-delete</property>
                        <property name="visible">True</property>
                        <property name="can-focus">False</property>
                        <property name="use-underline">True</property>
                        <property name="use-stock">True</property>
                      </object>
                    </child>
                  </object>
                </child>
              </object>
            </child>
            <child>
              <object class="GtkMenuItem">
                <property name="visible">True</property>
                <property name="can-focus">False</property>
                <property name="label" translatable="yes">_View</property>
                <property name="use-underline">True</property>
              </object>
            </child>
            <child>
              <object class="GtkMenuItem">
                <property name="visible">True</property>
                <property name="can-focus">False</property>
                <property name="label" translatable="yes">_Help</property>
                <property name="use-underline">True</property>
                <child type="submenu">
                  <object class="GtkMenu">
                    <property name="visible">True</property>
                    <property name="can-focus">False</property>
                    <child>
                      <object class="GtkImageMenuItem">
                        <property name="label">gtk-about</property>
                        <property name="visible">True</property>
                        <property name="can-focus">False</property>
                        <property name="use-underline">True</property>
                        <property name="use-stock">True</property>
                      </object>
                    </child>
                  </object>
                </child>
              </object>
            </child>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">0</property>
          </packing>
        </child>
        <child>
          <object class="GtkAspectFrame">
            <property name="visible">True</property>
            <property name="can-focus">False</property>
            <property name="label-xalign">0</property>
            <property name="shadow-type">none</property>
          </object>
          <packing>
            <property name="expand">True</property>
            <property name="fill">True</property>
            <property name="position">2</property>
          </packing>
        </child>
        <child>
          <object class="GtkSeparator">
            <property name="visible">True</property>
            <property name="can-focus">False</property>
            <property name="margin-top">2</property>
            <property name="margin-bottom">2</property>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">3</property>
          </packing>
        </child>
        <child>
          <object class="GtkBox">
            <property name="visible">True</property>
            <property name="can-focus">False</property>
            <child>
              <object class="GtkLabel">
                <property name="visible">True</property>
                <property name="can-focus">False</property>
                <property name="label" translatable="yes">status: normal</property>
              </object>
              <packing>
                <property name="expand">False</property>
                <property name="fill">True</property>
                <property name="position">0</property>
              </packing>
            </child>
            <child>
              <object class="GtkButton">
                <property name="label" translatable="yes">button</property>
                <property name="visible">True</property>
                <property name="can-focus">True</property>
                <property name="receives-default">True</property>
                <signal name="clicked" handler="click" object="__glade_unnamed_23" swapped="no"/>
              </object>
              <packing>
                <property name="expand">False</property>
                <property name="fill">True</property>
                <property name="position">1</property>
              </packing>
            </child>
            <child>
              <placeholder/>
            </child>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">4</property>
          </packing>
        </child>
      </object>
    </child>
  </object>
</interface>

When I tried to launch my app I allways get this 3 mesages:

(main:32570): Gtk-WARNING **: 17:41:09.237: Could not find signal handler 'safe_quit'. Did you compile with -rdynamic?

(main:32570): Gtk-WARNING **: 17:41:09.237: Could not lookup object __glade_unnamed_23 on signal clicked of object ___object_24

(main:32570): Gtk-WARNING **: 17:41:09.237: Could not find signal handler 'click'. Did you compile with -rdynamic?

I read a lot of same problems on stackoverflow but nothing helped. I change handlers parameters, names, add static and G_MODULE_EXPORT but ALL of that don't work.

On this site I found this "On Linux and Unices, this is not necessary (G_MODULE_EXPORT); applications should instead be compiled with the -Wl,--export-dynamic CFLAGS, and linked against gmodule-export-2.0." but my app compiled with -Wl and --export-dynamic!!! WHAT I DO WRONG??? Please anyone who knows the answer or have the same problem, help me to find anything that culd be a solution.

Sorry for my bad english and thanks you for your attention...

P.S. (find some kind of solution):

gtk_builder_add_callback_symbol(builder,"safe_quit",G_CALLBACK(safe_quit));
gtk_builder_add_callback_symbol(builder,"click",G_CALLBACK(click));
gtk_builder_connect_signals (builder, NULL);

Is there any solutions how to connect handlers without using gtk_builder_add_callback_symbol? I mean gtk_builder_connect_signals used to auto-connect signals to handle using GModule to look in application’s symbol table, so what's wrong with my app symbol table that signals can't be connected automatically ?


Solution

  • I had to compile your source to get on it by myself, but it seems that you are mixing C and C++ statements in your program, which causes GCC to compile it as a C++ file, just as if you were using g++ instead of gcc. EDIT: actually it will since you named your file: "main .cpp ".

    In turn, C++ decorates functions prototypes so you can optionally overload them, which will unable pure C libraries to find them back at run time.

    Enclosing your signal header prototypes inside a extern "C" block seems to help:

    extern "C"
    {
    
        //function to quit the app without data corruption
        void safe_quit (GtkWidget* object, gpointer data)
        {
                gtk_main_quit();
        }
        
        void click (GtkButton *button, gpointer label)
        {
                /* установить метке текст */
                gtk_label_set_text ((GtkLabel*)label, "Привет, Хабр!");
        }
    
    }