Whole document tree
    

Whole document tree

Using GnomeDialog directly

9.5. Using GnomeDialog directly

GnomeDialog provides a common look and feel for all Gnome dialogs. It allows the user to control the look and feel to some extent; and it lets the programmer get look and feel issues right with a minimum of effort. GnomeDialog is meant to have reasonable defaults; it is not a blank slate like GtkDialog.

A GnomeDialog is a window that pops up and is fairly rapidly dismissed; the GIMP Layers Dialog, for example, is not a dialog in this sense. There is no Gnome standard widget for persistent dialogs at this time.

GnomeDialog has a large number of functions, but almost all of them are special-purpose and rarely used. In practice you need only a few.

9.5.1. Creating a dialog

Here's a basic usage example, showing a callback and dialog creation:

            void dialog_clicked_cb(GnomeDialog * dialog, gint button_number, 
                                    gpointer data)
            {
              switch (button_number) {
                case 0: /* OK button */
          	  g_print(_("OK was clicked.\n"));
                  break;
                case 1: /* "My Button Name" */
	          g_print(_("My Button Name was clicked.\n"));
                  break;
                case 2: /* Cancel Button */
	          g_print(_("Cancel clicked\n"));
                  break;
	        default:
                  g_assert_not_reached();
              };
              gnome_dialog_close(dialog);
            }
	
	    GtkWidget * label;
            GtkWidget * dialog;

	    label  = gtk_label_new(_("Dialog contents"));

            dialog = gnome_dialog_new(_("My Title"), GNOME_STOCK_BUTTON_OK,
                                      _("My Button Name"), 
	                              GNOME_STOCK_BUTTON_CANCEL, 
                                      NULL); 
                 
	    gtk_box_pack_start(GNOME_DIALOG(dialog)->vbox,
                               label, TRUE, TRUE, GNOME_PAD);

	    gtk_signal_connect(GTK_OBJECT(dialog), "clicked",
                               GTK_SIGNAL_FUNC(dialog_clicked_cb),
                               NULL);

            gtk_widget_show(dialog);
	

This example creates a dialog with a label inside it; the dialog has three buttons: a stock OK button, a custom "My Button Name" button, and a stock Cancel button. The list of button arguments is NULL-terminated. The dialog is titled "My Title." Notice the _() macro, which translates the strings into the user's native language.

The buttons you create are numbered in order starting from 0; the clicked callback receives this number. In the callback (or wherever it makes sense in your program), you should close the dialog with gnome_dialog_close(), if you want the dialog to go away.

Buttons appear in the dialog in the same order they are passed to gnome_dialog_new(). That is, the first button argument will be the leftmost button. Gnome conventionally puts OK before Cancel and Yes before No. The last button in the list will be the default button. Normally you want Cancel/No to be the default, since those actions are the least destructive. However, you can change the default with gnome_dialog_set_default().

For a dialog that simply displays a message, like this one, you would normally use GnomeMessageBox or some of Gnome's convenience functions instead of creating your own. Useful GnomeDialog subclasses include GnomeMessageBox, GnomePropertyBox, and GnomeAbout.

9.5.2. Closing the dialog

GnomeDialog has a close signal, which you can send with gnome_dialog_close(). This signal bundles together the various causes and effects of dialog closure.

There are many reasons a dialog can close: the most common are clicking a button and deleting it with a window manager decoration. Most applications define their own reasons; for example, if the parent window of the dialog closes, the application may call gnome_dialog_close().

Likewise, there are two common meanings of "close a dialog" from the programmer's perspective. The most popular is gtk_widget_destroy() — get rid of the dialog completely. However, if a dialog is expensive to create, you may want to create it only once, then call gtk_widget_hide() to close it, and gtk_widget_show() to pop it up again. The close signal can cause either of these effects.

The close signal allows you to invoke a callback regardless of the reason the dialog was closed. It frees you from worrying about delete_event, and if you later add a new way to close the dialog, there's no need to special case it in your dialog code. You can also change the default effect of closing a dialog (hide or destroy) without changing all your code.

If you connect a callback to the close signal, it must return a boolean value. If the callback returns FALSE, the dialog is closed. If the callback returns TRUE, the close is halted; the dialog remains on the screen. For example, if the user enters invalid data and clicks OK, you might detect the invalid data in your callback, display an error, and return TRUE.

9.5.3. Dialog options

GnomeDialog has a number of options to customize its default behavior. Also keep in mind the GtkWindow functions, especially gtk_window_set_modal(). Remember not to override any user preferences for dialogs: for example, you should not call gtk_window_position, or force particular coordinates on the dialog.

The close signal can either hide or destroy the dialog. By default, close destroys the dialog. If you pass TRUE to this function, it hides instead.

Set the default button. If the user presses enter, the default button is clicked. By default, the highest-numbered button is the default (the last button given in gnome_dialog_new()).

Sets the sensitivity of a button, using gtk_widget_set_sensitive(). By default all buttons are sensitive.

Dialogs have a "parent" window, often the main application window. For now, the only effect of telling the dialog its parent is to center the dialog over the parent window, if the user has requested that behavior. In the future it may have other effects (possibly setting some window manager hints to keep the dialog on top of its parent?).

It is unclear that this function still works, and it may not fit into the new GtkAccelGroup scheme properly. It still takes only a character argument instead of a keysym.

If/when it works, it sets an accelerator which clicks one of the dialog buttons. Eventually there should probably be some indication of this on the button. But things are broken.

This is a poorly-named convenience function to save you typing; it calls gnome_dialog_close() any time the clicked signal is emitted. In effect it creates this callback:

	  void 
          dialog_clicked(GtkWidget * dialog, gint button, 
	                 gpointer data)
	  {
            gnome_dialog_close(GNOME_DIALOG(dialog));
          }
	

A GtkEditable such as an entry or a text widget normally interferes with the enter key accelerator (which clicks the dialog's default button). Often users want to type in the entry, then press return to close the dialog; this function enables that behavior.

9.5.4. Modal dialogs

First off: modal dialogs are bad. Don't use them unless it actually makes sense to do so, or you're adding Gnome support to legacy code that requires it. It is really trivial to do proper callbacks instead, and less confusing for the user.

With the lecture out of the way, basically all you have to do to create a modal dialog is call gtk_window_set_modal(). If you want to be truly lazy, and write truly unextensible, ugly, gratuitously yucky code, or you have to support legacy program structure, you can use the gnome_dialog_run():

This function sets the dialog modal and blocks until the user clicks a button; it then returns the dialog to its original modalness. It returns the number of the button that was clicked, or -1 if the user hit the window manager's delete decoration or there was an error. It also shows the dialog if it is not visible.

You must be sure the dialog gets closed after the function returns. You can do this by calling gnome_dialog_set_close() before entering gnome_dialog_run(), or you can just call gnome_dialog_close() manually after you get a response.

It is important to be careful here: gnome_dialog_close() destroys the dialog by default. Thus it's not safe to call twice. And by default, if the user clicks the window manager's delete decoration, it will be called. So you must not close the dialog again in that case.

There are two easy solutions: use gnome_dialog_set_close() to ensure destruction in all cases; or change close behavior to "hide" with gnome_dialog_close_hides(), then destroy the dialog with gtk_widget_destroy() after gnome_dialog_run() returns.

One caveat: gnome_dialog_run() has to perform some cleanup to remove its internal callbacks and reset the dialog to non-modal if necessary. This means it must guess whether the dialog was destroyed when clicked (or deleted by the window manager). Right now it does not do this reliably (probably it should connect a callback to GtkObject::destroy to be sure - patches accepted). So it is probably best to have close hide the dialog, then destroy the dialog yourself with gtk_widget_destroy().