Qual é a maneira correta de usar g_signal_connect () em C ++ para listas rápidas de unidade dinâmica?

6

Eu quero fazer meu aplicativo usar listas rápidas de unidade dinâmica. Para criar meu aplicativo, estou usando o C ++ e o QtCreator IDE. Quando uma ação de menu é acionada, eu quero ter acesso a uma função não-estática da minha MainWindow classe para poder atualizar a Interface Gráfica do Usuário que pode ser acessada de dentro das funções 'normais' da MainWindow. / p>

Então, estou construindo minha lista rápida assim (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);

Esta sugestão foi retirada do link

O programa trava imediatamente depois que eu escolho a ação 'Parar' da Lista rápida do Unity. A depuração do programa mostra que não consigo acessar nada relacionado ao MainWindow dentro do on_stopButton_clicked () sem travar. Por exemplo, ele trava ao fazer essa verificação (que é as duas primeiras linhas de código dentro dessa função):

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

Eu também testei muitas outras coisas que encontrei na internet, mas nada funcionou. Uma solução interessante seria usar o gtkmm ( link ), mas Eu não estou acostumado a trabalhar em aplicações GTK (eu trabalho apenas em Qt) e não sei se isso serve para a minha ocasião.

    
por hytromo 25.08.2012 / 20:18

1 resposta

3

Editar: tudo bem, depois de uma quantidade razoável de investigação (que envolveu a execução de valgrind ), finalmente consegui descobrir o que está acontecendo aqui. A assinatura do seu retorno de chamada não está correta.

A assinatura para o método estático deve ser:

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

Observe a adição de DbusmenuMenuitem * e guint . O primeiro é um ponteiro para o item de menu DBus que emite o sinal e o segundo é um timestamp. Ambos devem estar presentes na assinatura, mesmo que você não os use.

g_signal_connect é invocado no tempo de execução e não tem como saber quais parâmetros sua função aceita e simplesmente envia os parâmetros na pilha assumindo que as assinaturas correspondem. (Isso difere do que você provavelmente está acostumado em Qt, onde o MOC (Meta Object Compiler) gera informações suficientes para saber quando você está tentando conectar um sinal a um slot com uma assinatura incompatível.)

    
por Nathan Osman 28.08.2012 / 19:32