"Fossies" - the Fresh Open Source Software archive 
Member "gentoo-0.19.13/src/dialog.c" of archive gentoo-0.19.13.tar.gz:
/*
** 1999-03-13 - A (new) module for dealing with user dialogs. The old one was written during
** my first week of GTK+ programming (back in May 1998, if you really care), and
** that had started to show a little too much. Hopefully, this is cleaner.
** 1999-06-19 - Since the initial cleanliness quickly wore down due to (I guess) bad design,
** I did a complete rewrite and redesign. This new shiny version features clear
** separation of dialogs into synchronous and asynchronous versions. The former
** are way (way) more useful.
** 2002-02-08 - Added window grouping. Very nice, keeps the number of icons in Window Maker
** down. :)
*/
#include "gentoo.h"
#include <stdio.h>
#include <gdk/gdkkeysyms.h>
#include "dialog.h"
#include "window.h"
struct Dialog {
GtkWidget *dlg; /* The GtkDialog widget used to display the dialog. */
gint last_button;
gint button;
DlgAsyncFunc func; /* Used in asynchronous dialogs only. */
gpointer user; /* This, too. */
gboolean stay_open; /* This, on the other hand, only for synchronous ones. */
};
static struct {
GtkWindow *main_window;
GdkWindow *group_window;
GtkWindowPosition window_pos;
} the_state;
#define DLG_BUTTON_SIZE (32) /* Max length of a single button label. */
/* ----------------------------------------------------------------------------------------- */
/* 2002-02-08 - Set the module's internal group pointer. All dialogs have their windows
** set as being part of the group defined by that window. Very handy.
*/
void dlg_group_set(GdkWindow *group_window)
{
the_state.group_window = group_window;
}
void dlg_position_set(GtkWindowPosition pos)
{
the_state.window_pos = pos;
}
/* 2009-03-25 - Sets the main window, all dialogs are then made transient to this window.
** I think this replaces the "group" concept used with GDK windows.
*/
void dlg_main_window_set(GtkWindow *win)
{
the_state.main_window = win;
}
/* ----------------------------------------------------------------------------------------- */
/* 2004-11-22 - Add buttons by splitting <buttons> on vertical bar (pipe) character. Far simpler
* than when using GTK+ 1.2, keyboard acceleration now done by GtkDialog.
*/
static gint add_buttons(GtkWidget *dlg, const char *buttons)
{
gchar label[DLG_BUTTON_SIZE], *ptr;
gint response = 0;
while(*buttons)
{
for(ptr = label; (ptr - label) < (sizeof label - 1) && *buttons && *buttons != '|';)
*ptr++ = *buttons++;
*ptr = '\0';
if(*buttons == '|')
buttons++;
gtk_dialog_add_button(GTK_DIALOG(dlg), label, response++);
}
return response - 1;
}
/* ----------------------------------------------------------------------------------------- */
/* 1999-06-19 - Close dialog down in response to some event, and report it as if button <button> was clicked. */
static void sync_close(Dialog *dlg, gint button)
{
dlg->button = button;
if(!dlg->stay_open)
gtk_widget_hide(dlg->dlg);
}
/* 2004-11-22 - Response-handler for synchronous dialog. */
static void evt_sync_response(GtkWidget *wid, gint response, void *user)
{
sync_close(user, response >= 0 ? response : -1);
}
/* 2004-11-22 - Keyboard handler, so we can cancel through Escape. */
static gboolean evt_sync_key_pressed(GtkWidget *wid, GdkEventKey *evt, gpointer user)
{
Dialog *dlg = user;
if(evt->keyval == GDK_Escape)
gtk_dialog_response(GTK_DIALOG(dlg->dlg), dlg->last_button);
else
return FALSE;
return TRUE;
}
/* 1999-06-19 - Create a new, synchronous dialog box. Creates and initializes the auxilary data as well as the
** actual dialog window, with action buttons and stuff. Note that this window, when displayed by
** dlg_dialog_sync_wait(), will be modal, and hang around (at least in memory) until you call
** dlg_dialog_sync_destroy().
*/
Dialog * dlg_dialog_sync_new(GtkWidget *body, const gchar *title, const gchar *buttons)
{
Dialog *dlg;
if(buttons == NULL)
buttons = _("_OK|_Cancel");
dlg = g_malloc(sizeof *dlg);
dlg->dlg = win_dialog_open(GTK_WIDGET(the_state.main_window));
gtk_window_set_position(GTK_WINDOW(dlg->dlg), the_state.window_pos);
g_signal_connect(GTK_OBJECT(dlg->dlg), "key_press_event", G_CALLBACK(evt_sync_key_pressed), dlg);
g_signal_connect(GTK_OBJECT(dlg->dlg), "response", G_CALLBACK(evt_sync_response), dlg);
dlg->stay_open = FALSE;
if(title != NULL)
win_window_set_title(GTK_WIDGET(dlg->dlg), title);
if(body != NULL)
{
GtkWidget *vbox;
vbox = gtk_vbox_new(FALSE, 0);
gtk_container_set_border_width(GTK_CONTAINER(vbox), 5);
gtk_box_pack_start(GTK_BOX(vbox), body, TRUE, TRUE, 0);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg->dlg)->vbox), vbox, TRUE, TRUE, 0);
gtk_widget_show_all(vbox);
}
dlg->last_button = add_buttons(dlg->dlg, buttons);
gtk_dialog_set_default_response(GTK_DIALOG(dlg->dlg), 0);
return dlg;
}
/* 1999-06-19 - Create a synchronous dialog whose body is a plain text label. Extremely sugary. */
Dialog * dlg_dialog_sync_new_simple(const gchar *body, const gchar *title, const gchar *buttons)
{
return dlg_dialog_sync_new(gtk_label_new(body), title, buttons);
}
/* 1999-06-19 - This (bulkily-named) function is very handy for simple confirm dialogs. */
gint dlg_dialog_sync_new_simple_wait(const gchar *body, const gchar *title, const gchar *buttons)
{
Dialog *dlg;
gint ret;
dlg = dlg_dialog_sync_new_simple(body, title, buttons);
ret = dlg_dialog_sync_wait(dlg);
dlg_dialog_sync_destroy(dlg);
return ret;
}
/* 2009-12-29 - Adds a widget to the dialog's action area. */
void dlg_dialog_sync_action_add(Dialog *dlg, GtkWidget *wid)
{
if(dlg != NULL && wid != NULL)
{
gtk_box_pack_end(GTK_BOX(GTK_DIALOG(dlg->dlg)->action_area), wid, TRUE, TRUE, 0);
gtk_widget_show_all(wid);
}
}
/* 2002-08-20 - Make the dialog stay open until destroyed. Used only by the generic command module,
** but on the other hand that module is kind of important.
*/
void dlg_dialog_sync_stay_open(Dialog *dlg)
{
dlg->stay_open = TRUE;
}
/* 1999-06-19 - Display a previously created dialog, and wait for the user to click one of its buttons. Then
** return the index (counting from zero which is the leftmost button) of the button that was
** clicked.
*/
gint dlg_dialog_sync_wait(Dialog *dlg)
{
if(dlg != NULL)
{
gtk_widget_realize(dlg->dlg);
gtk_dialog_run(GTK_DIALOG(dlg->dlg));
return dlg->button;
}
return -1;
}
/* 1999-06-19 - Close a synchronous dialog as if <button> was clicked. */
void dlg_dialog_sync_close(Dialog *dlg, gint button)
{
if(dlg != NULL)
sync_close(dlg, button);
}
/* 1999-06-19 - Destroy a synchronous dialog. Don't expect to be able to access body widgets after calling this. */
void dlg_dialog_sync_destroy(Dialog *dlg)
{
gtk_widget_destroy(dlg->dlg);
g_free(dlg);
}
/* ----------------------------------------------------------------------------------------- */
/* 1999-06-19 - Execute the close-down policy of the asynchronous dialog. */
static void async_close(Dialog *dlg, gint button)
{
dlg->button = button;
if((dlg->button > -2 ) && (dlg->func != NULL))
dlg->func(dlg->button, dlg->user);
gtk_widget_destroy(dlg->dlg);
g_free(dlg);
}
/* 1999-06-19 - User pressed a key in an asynchronous dialog. */
static gboolean evt_async_key_pressed(GtkWidget *wid, GdkEventKey *evt, gpointer user)
{
Dialog *dlg = user;
if(evt->keyval == GDK_Escape)
{
async_close(dlg, dlg->last_button);
return TRUE;
}
return FALSE;
}
/* 1999-06-19 - User clicked one of the action buttons in an asynchronous dialog. */
static void evt_async_response(GtkWidget *wid, gint response, gpointer user)
{
async_close(user, response > 0 ? response : -1);
}
/* 1999-06-19 - Create, and immediately display, an asynchronous dialog. The supplied callback will be called
** as the user clicks a button (or closes the window). At that point, the dialog (and any user-
** supplied body widgets) are still around.
*/
Dialog * dlg_dialog_async_new(GtkWidget *body, const gchar *title, const gchar *buttons, DlgAsyncFunc func, gpointer user)
{
Dialog *dlg;
if(buttons == NULL)
buttons = _("_OK|_Cancel");
dlg = g_malloc(sizeof *dlg);
dlg->func = func;
dlg->user = user;
dlg->dlg = win_dialog_open(GTK_WIDGET(the_state.main_window));
gtk_window_set_position(>K_DIALOG(dlg->dlg)->window, the_state.window_pos);
g_signal_connect(G_OBJECT(dlg->dlg), "key_press_event", G_CALLBACK(evt_async_key_pressed), dlg);
g_signal_connect(G_OBJECT(dlg->dlg), "response", G_CALLBACK(evt_async_response), dlg);
if(title != NULL)
win_window_set_title(GTK_WIDGET(>K_DIALOG(dlg->dlg)->window), title);
gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(dlg->dlg)->vbox), 5);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg->dlg)->vbox), body, TRUE, TRUE, 0);
dlg->last_button = add_buttons(dlg->dlg, buttons);
gtk_widget_realize(dlg->dlg);
gtk_widget_show_all(dlg->dlg);
return dlg;
}
/* 1999-06-19 - A simple sugary wrapper for text-only dialogs. */
Dialog * dlg_dialog_async_new_simple(const gchar *body, const gchar *title, const gchar *buttons, DlgAsyncFunc func, gpointer user)
{
return dlg_dialog_async_new(gtk_label_new(body), title, buttons, func, user);
}
/* 1999-06-19 - Provide a simple error reporting dialog. */
Dialog * dlg_dialog_async_new_error(const gchar *body)
{
return dlg_dialog_async_new_simple(body, _("Error"), _("OK"), NULL, NULL);
}
/* 1999-06-19 - Close an asynchronous dialog, as if button <button> was clicked. */
void dlg_dialog_async_close(Dialog *dlg, gint button)
{
async_close(dlg, button);
}
/* 1999-06-19 - Close an asynchronous dialog, but do not call the user's callback. */
void dlg_dialog_async_close_silent(Dialog *dlg)
{
async_close(dlg, -2);
}
/* ----------------------------------------------------------------------------------------- */
/* 2011-09-28 - Return the GtkDialog, which can be useful sometimes. */
GtkDialog * dlg_dialog_get_dialog(const Dialog *dlg)
{
return dlg != NULL ? GTK_DIALOG(dlg->dlg) : NULL;
}
static void evt_entry_changed(GtkWidget *entry, gpointer user)
{
const gchar *text = gtk_entry_get_text(GTK_ENTRY(entry));
dlg_dialog_set_positive_enabled(user, *text != '\0');
}
/* 2010-06-13 - Make the dialog track the state of a GtkEntry, and only enable the "OK" button if entry is non-empty. */
void dlg_dialog_track_entry(Dialog *dlg, GtkWidget *entry)
{
if(dlg == NULL)
return;
g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK(evt_entry_changed), dlg);
/* Make sure it's synchronized initially, too. */
evt_entry_changed(entry, dlg);
}
/* 2010-09-05 - Happy birthday, me! Enable/disable the "positive" (=OK) button on the fly. */
void dlg_dialog_set_positive_enabled(Dialog *dlg, gboolean enabled)
{
if(dlg == NULL)
return;
gtk_dialog_set_response_sensitive(GTK_DIALOG(dlg->dlg), DLG_POSITIVE, enabled);
}