web-dev-qa-db-fra.com

Quelle est la bonne façon d'utiliser g_signal_connect () en C ++ pour les listes rapides d'unités dynamiques?

Je souhaite que mon application utilise des listes rapides d'unité dynamiques. Pour construire mon application, j'utilise C++ et l'IDE QtCreator. Quand une action de menu est déclenchée, je veux pouvoir accéder à une fonction non statique de ma classe MainWindow afin de pouvoir mettre à jour l'interface graphique utilisateur à laquelle on peut accéder depuis les fonctions "normales" de MainWindow. .

Donc, je construis ma liste rapide comme ceci (mainwindow.cpp):

void MainWindow::enable_unity_quicklist(){
    Unity_Menu = dbusmenu_menuitem_new();

    dbusmenu_menuitem_property_set_bool (Unity_Menu, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);

    Unity_Stop = dbusmenu_menuitem_new();
    dbusmenu_menuitem_property_set(Unity_Stop, DBUSMENU_MENUITEM_PROP_LABEL, "Stop");

    dbusmenu_menuitem_child_append (Unity_Menu, Unity_Stop);

    g_signal_connect (Unity_Stop, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(&fake_callback), (gpointer)this);

    if(!unity_entry)
        unity_entry = unity_launcher_entry_get_for_desktop_id("myapp.desktop");

    unity_launcher_entry_set_quicklist(unity_entry, Unity_Menu);

    dbusmenu_menuitem_property_set_bool(Unity_Menu, DBUSMENU_MENUITEM_PROP_VISIBLE, true);
    dbusmenu_menuitem_property_set_bool(Unity_Stop, DBUSMENU_MENUITEM_PROP_VISIBLE, true);
}

void MainWindow::fake_callback(gpointer data){
    MainWindow* m = (MainWindow*)data;
    m->on_stopButton_clicked();
}

void MainWindow::on_stopButton_clicked(){
   //stopping the process...
}

mainwindow.h:

private slots:
   void enable_unity_quicklist();
   void on_stopButton_clicked();
public slots:
   static void fake_callback(gpointer data);

Cette suggestion provient de http://old.nabble.com/Using-g_signal_connect-in-class-td18461823.html

Le programme se bloque immédiatement après que j'ai choisi l'action "Arrêter" dans la liste rapide d'Unity. Le débogage du programme montre que je ne peux accéder à aucun élément lié à MainWindow à l’intérieur de on_stopButton_clicked () sans planter. Par exemple, il se bloque lors de cette vérification (qui correspond aux deux premières lignes de code dans cette fonction):

if (!ui->stopButton->isEnabled())
        return;

J'ai également testé beaucoup d'autres choses que j'ai trouvées sur Internet, mais rien d'entre elles n'a fonctionné. Une solution intéressante serait d’utiliser gtkmm ( http://developer.gnome.org/gtkmm-tutorial/stable/sec-connecting-signal-handlers.html.en ) mais je ne suis pas habitué à tous travaillent sur des applications GTK (je travaille uniquement en Qt) et je ne sais pas si cela convient à mon occasion.

6
hytromo

Edit: OK, après de nombreuses recherches (qui ont nécessité l'exécution de valgrind), j'ai finalement réussi à comprendre ce qui se passe ici. La signature de votre rappel n'est pas correcte.

La signature de la méthode statique doit être:

void MainWindow::fake_callback(DbusmenuMenuitem *, guint, gpointer data)
{
    //...
}

Notez l'ajout de DbusmenuMenuitem * et guint. Le premier est un pointeur sur l'élément de menu DBus émettant le signal et le second est un horodatage. Les deux doivent être présents dans la signature même si vous ne les utilisez pas.

g_signal_connect est appelé à l'exécution et n'a aucun moyen de savoir quels paramètres sont acceptés par votre fonction. Il ne fait que pousser aveuglément les paramètres sur la pile en supposant que les signatures correspondent. (Cela diffère de ce à quoi vous êtes probablement habitué dans Qt où le compilateur de méta-objets (MOC) génère suffisamment d'informations pour savoir quand vous essayez de connecter un signal à un emplacement avec une signature incompatible.)

3
Nathan Osman