3

I am having trouble figuring out how to write signal handlers in my C code for the message dialogs that I am creating in GLADE. If I were not using GLADE, the signal handler would include the necessary information to construct the message dialog itself. For example, an "are you sure you want to quit?" message dialog would have the form:

void show_question(GtkWidget *widget, gpointer window) {

  GtkWidget *dialog;
  dialog = gtk_message_dialog_new(GTK_WINDOW(window),
          GTK_DIALOG_DESTROY_WITH_PARENT,
          GTK_MESSAGE_QUESTION,
          GTK_BUTTONS_YES_NO,
          "Are you sure to quit?");
  gtk_window_set_title(GTK_WINDOW(dialog), "Question");
  gtk_dialog_run(GTK_DIALOG(dialog));
  gtk_widget_destroy(dialog);
}

Likewise, an "about window" would have the form:

void show_about(GtkWidget *widget, gpointer data) {

  GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file("battery.png", NULL);

  GtkWidget *dialog = gtk_about_dialog_new();
  gtk_about_dialog_set_name(GTK_ABOUT_DIALOG(dialog), "Battery");
  gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(dialog), "0.9"); 
  gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(dialog), "(c) Jan Bodnar");
  gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(dialog), "Battery is a simple tool for battery checking.");
  gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(dialog), "http://www.batteryhq.net");
  gtk_about_dialog_set_logo(GTK_ABOUT_DIALOG(dialog), pixbuf);
  g_object_unref(pixbuf), pixbuf = NULL;
  gtk_dialog_run(GTK_DIALOG (dialog));
  gtk_widget_destroy(dialog);
}

Now that I am fully creating these windows within GLADE, I am not sure what form the signal handler should take (in C) in order to connect, say, clicking Help -> About to the about window created in GLADE, or connecting clicking File -> Quit with the "are you sure you want to quit" message dialog created in GLADE. I am new to both GTK+ and Glade and I can't seem to find anything that has been of use in resolving this. Any help would be greatly appreciated.

EDIT: Below is an example glade XML file that consists of two top level windows. The first is the main window with a single box containing a menu bar. The second is an about dialog. What I am looking for is help in writing the signal handler that will open the about window after clicking File -> About in the menu bar.

<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.18.3 -->
<interface>
  <requires lib="gtk+" version="3.12"/>
  <object class="GtkWindow" id="window1">
    <property name="can_focus">False</property>
    <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" id="menubar1">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <child>
              <object class="GtkMenuItem" id="menuitem1">
                <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" id="menu1">
                    <property name="visible">True</property>
                    <property name="can_focus">False</property>
                    <child>
                      <object class="GtkImageMenuItem" id="imagemenuitem1">
                        <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" id="imagemenuitem2">
                        <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" id="imagemenuitem3">
                        <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" id="imagemenuitem4">
                        <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" id="separatormenuitem1">
                        <property name="visible">True</property>
                        <property name="can_focus">False</property>
                      </object>
                    </child>
                    <child>
                      <object class="GtkImageMenuItem" id="imagemenuitem5">
                        <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" id="menuitem2">
                <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" id="menu2">
                    <property name="visible">True</property>
                    <property name="can_focus">False</property>
                    <child>
                      <object class="GtkImageMenuItem" id="imagemenuitem6">
                        <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" id="imagemenuitem7">
                        <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" id="imagemenuitem8">
                        <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" id="imagemenuitem9">
                        <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" id="menuitem3">
                <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" id="menuitem4">
                <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" id="menu3">
                    <property name="visible">True</property>
                    <property name="can_focus">False</property>
                    <child>
                      <object class="GtkImageMenuItem" id="imagemenuitem10">
                        <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>
      </object>
    </child>
  </object>
  <object class="GtkAboutDialog" id="window_about">
    <property name="can_focus">False</property>
    <property name="type_hint">dialog</property>
    <property name="program_name">Glade</property>
    <property name="logo_icon_name">image-missing</property>
    <child internal-child="vbox">
      <object class="GtkBox" id="aboutdialog-vbox1">
        <property name="can_focus">False</property>
        <property name="orientation">vertical</property>
        <property name="spacing">2</property>
        <child internal-child="action_area">
          <object class="GtkButtonBox" id="aboutdialog-action_area1">
            <property name="can_focus">False</property>
            <property name="layout_style">end</property>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">False</property>
            <property name="position">0</property>
          </packing>
        </child>
        <child>
          <placeholder/>
        </child>
      </object>
    </child>
  </object>
</interface>
2
  • You're not planning on trying to display things like message dialogs from within a signal handler, are you? The only functions that can safely be called from within a signal handler are async-signal-safe functions. Commented Jan 9, 2018 at 22:16
  • I'm not trying to do that. It seems as though that is what is happening with the functions defined above. I'm just looking for clarification on how the signal handlers should be constructed given the Glade XML file having predefined the message dialog windows. Commented Jan 10, 2018 at 0:12

2 Answers 2

4

If understood correctly, instead of creating the dialogs programmatically, you want to create the dialogs via glade.

By using glade you must use GtkBuilder.

Let's say you create a simple Yes, No dialog with glade (yesno_dialog.ui):

<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.20.2 -->
<interface>
  <requires lib="gtk+" version="3.20"/>
  <object class="GtkDialog" id="dialog1">
    <property name="can_focus">False</property>
    <property name="modal">True</property>
    <property name="default_width">275</property>
    <property name="default_height">130</property>
    <property name="type_hint">dialog</property>
    <child internal-child="vbox">
      <object class="GtkBox">
        <property name="can_focus">False</property>
        <property name="orientation">vertical</property>
        <property name="spacing">2</property>
        <child internal-child="action_area">
          <object class="GtkButtonBox">
            <property name="can_focus">False</property>
            <property name="hexpand">True</property>
            <property name="layout_style">spread</property>
            <child>
              <object class="GtkButton" id="button1">
                <property name="label">gtk-yes</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="receives_default">True</property>
                <property name="use_stock">True</property>
              </object>
              <packing>
                <property name="expand">True</property>
                <property name="fill">True</property>
                <property name="position">0</property>
              </packing>
            </child>
            <child>
              <object class="GtkButton" id="button2">
                <property name="label">gtk-no</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="receives_default">True</property>
                <property name="use_stock">True</property>
              </object>
              <packing>
                <property name="expand">True</property>
                <property name="fill">True</property>
                <property name="position">1</property>
              </packing>
            </child>
          </object>
          <packing>
            <property name="expand">True</property>
            <property name="fill">True</property>
            <property name="position">0</property>
          </packing>
        </child>
        <child>
          <object class="GtkLabel">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="halign">center</property>
            <property name="valign">center</property>
            <property name="hexpand">True</property>
            <property name="vexpand">True</property>
            <property name="label" translatable="yes">Are you sure to quit?</property>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">1</property>
          </packing>
        </child>
      </object>
    </child>
    <action-widgets>
      <action-widget response="1">button1</action-widget>
      <action-widget response="2">button2</action-widget>
    </action-widgets>
    <child>
      <placeholder/>
    </child>
  </object>
</interface>

Which should look like this:

enter image description here

Notice the response_id as 1 for later reference.

Let's test a simple window with a button which will trigger a dialog via its clicked signal handler / callback:

#include <gtk/gtk.h>

void on_button_clicked (GtkButton *button, gpointer user_data) {
   int response;
   GtkWidget  *dialog;
   GtkBuilder *builder;

   g_return_if_fail (user_data != NULL);

   builder = gtk_builder_new_from_file("yesno_dialog.ui");

   dialog = GTK_WIDGET(gtk_builder_get_object (builder, "dialog1"));
   gtk_window_set_transient_for (GTK_WINDOW(dialog), GTK_WINDOW(user_data));

   gtk_widget_show_all(dialog);

   response = gtk_dialog_run(GTK_DIALOG(dialog));

   gtk_widget_destroy(dialog);

   g_object_unref(G_OBJECT(builder));

   g_print ("Response is %s\n", response == 1 ? "Yes" : "No");
}


int main(int argc, char *argv[]) {
   GtkWidget *button;
   GtkWidget *window;

   gtk_init(&argc,&argv);

   button = gtk_button_new_with_label("Press for dialog");
   window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

   gtk_container_add(GTK_CONTAINER(window), button);

   g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(on_button_clicked), window);
   g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);

   gtk_widget_show_all(window);

   gtk_main();

   return 0;
}

When you construct a dialog programmatically with standard response ids then you can use the predefined enumerators to check the response. Using glade, even though we've defined Stock buttons, we must define (user-defined) response ids so that the gtk_dialog_run functions understands that the user has chosen a response.

Compiling with:

gcc -o dialog main.c `pkg-config --cflags --libs gtk+-3.0`

Should result in something similar to this:

enter image description here

Sign up to request clarification or add additional context in comments.

9 Comments

Jose, I appreciate the thorough response, however this did not answer the original question. Please see the edit to the original question for clarification. Thanks!
@LeighK The example can be applied to your goal. The basic step here is to retrieve the auto-instantiated Widgets from the Glade XML definition via GtkBuilder. The GtkBuilder function, get_object, allows you to get the glade widgets by name. So in your callback, you can pass the builder object or the dialog. Later i can try to complement my answer.
Jose, I just ran your example and it seems that you are indeed correct. However, there are some differences. First, I am used to seeing the GtkBuilder being referenced in main. You do not reference it in main, but rather within the "on_button_clicked" signal handler (and then unreference it). I imagine I can reference it both in main and within the signal handler I am interested in writing though?
The biggest issue is that your "on_button_clicked" signal handler is being fed a pointer to the GtkButton you created in main. In my case, it needs to be linked to the GtkImageMenuItem "gtk-about." I am not sure how this would be done. Aside from that caveat, I suspect the signal handler you have written would do the job.
@LeighK It's straightforward. You simply must understand the "Gtk" framework. Care to join the Gtk chat so that we can try and aid you, by fully understand the problem and elaborate on the answer. Chat: chat.stackoverflow.com/rooms/160557/gtk
|
2

After discussions with @Jose Fonte, the solution to my question is the following:

// Signal Handler for Clicking File -> Quit
void file_quit_clicked (__attribute__((unused)) GtkMenuItem *item, gpointer user_data) 
{
    GtkBuilder *builder = (GtkBuilder *) user_data;

    GtkDialog *dialog = GTK_DIALOG(gtk_builder_get_object(builder, "quit_dialog"));

    gtk_widget_show_all(GTK_WIDGET(dialog));

    // This switch statement and gtk_widget_hide is needed so that the dialog window can be closed 
    // and reopened again without causing errors (i.e. if the user clicks "no" when asked "are you
    // sure you want to quit." Without these, the window errors out the second time opened.
    gint result = gtk_dialog_run (dialog);
    switch (result)
    {
        case GTK_RESPONSE_ACCEPT:
           // do_application_specific_something (); - Nothing Required
           break;
        default:
           // do_nothing_since_dialog_was_cancelled (); - Nothing Required
           break;
    }
    gtk_widget_hide(GTK_WIDGET(dialog));

}

with the following snippet inserted into the main function:

    // So the "Are you sure you want to quit?" Dialog Box is hidden after clicking "x"
    GtkDialog *quit_dialog = GTK_DIALOG(gtk_builder_get_object(builder, "quit_dialog"));
    gtk_widget_hide_on_delete (GTK_WIDGET(quit_dialog));

2 Comments

gint result = gtk_dialog_run (GTK_DIALOG (dialog)); does not need the GTK_DIALOG() macro as it was defined as a GtkDialog. I'll edit the answer to reflect that.
Good deal Jose. Many thanks for all of your assistance with working out the solution!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.