more of this dialog stuff
- From: Havoc Pennington <hp redhat com>
- To: gtk-devel-list gnome org
- Subject: more of this dialog stuff
- Date: 28 Jun 2000 14:23:42 -0400
Hi,
OK here is what I have now. I'd like to have
gtk_window_get_accel_group(), then the button names you pass in can
have a uline and the accelerator for that will be auto-installed.
(if there's no gtk_window_get_accel_group() then GtkDialog will keep a
private accel group for this).
Changes since the last GtkDialog iteration a long time ago:
- GtkWidget **zero_on_destroy argument removed from constructors,
because Owen was strongly opposed to it. Rationale: these are
supposed to be easy-to-use constructors, so 4 args is too many.
People can always use gtk_widget_destroyed().
- gtk_dialog_run() now returns if "action" is emitted
- no default actions (such as hiding the dialog) for button clicks;
button clicks emit "action" but nothing else
- Escape key synthesizes a delete_event
- button names can contain a uline to parse
- the destroy-transient-with-parent functionality is moved to
GtkWindow (off by default for both GtkWindow and GtkDialog),
rationale is that if set_transient_for is in GtkWindow then
this feature should be as well.
Maybe some other stuff I don't remember, it was a long time ago we
discussed this. ;-)
Anyway, header and implementation appended.
Havoc
/* GTK - The GIMP Toolkit
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/*
* Modified by the GTK+ Team and others 1997-1999. See the AUTHORS
* file for a list of people on the GTK+ Team. See the ChangeLog
* files for a list of changes. These files are distributed with
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/
#ifndef __GTK_DIALOG_H__
#define __GTK_DIALOG_H__
#include <gdk/gdk.h>
#include <gtk/gtkwindow.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* Parameters for dialog construction */
typedef enum
{
GTK_DIALOG_MODAL, /* call gtk_window_set_modal(win, TRUE) */
GTK_DIALOG_DESTROY_WITH_PARENT /* call gtk_window_set_destroy_with_parent () */
} GtkDialogFlags;
/* Convenience enum to use for action_id's. Positive values are
totally user-interpreted. GTK will sometimes return GTK_ACTION_NONE
if no action_id is available.
Typical usage is:
if (gtk_dialog_run(dialog) == GTK_ACTION_ACCEPT)
blah();
*/
typedef enum
{
/* GTK returns this if an action widget has no action_id,
or the dialog gets destroyed with no action */
GTK_ACTION_NONE = 0,
/* GTK won't return these unless you pass them in
as the action for an action widget */
GTK_ACTION_REJECT = 1,
GTK_ACTION_ACCEPT = 2
} GtkActionType;
#define GTK_TYPE_DIALOG (gtk_dialog_get_type ())
#define GTK_DIALOG(obj) (GTK_CHECK_CAST ((obj), GTK_TYPE_DIALOG, GtkDialog))
#define GTK_DIALOG_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GTK_TYPE_DIALOG, GtkDialogClass))
#define GTK_IS_DIALOG(obj) (GTK_CHECK_TYPE ((obj), GTK_TYPE_DIALOG))
#define GTK_IS_DIALOG_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GTK_TYPE_DIALOG))
#define GTK_DIALOG_GET_CLASS(obj) (GTK_CHECK_GET_CLASS ((obj), GTK_TYPE_DIALOG, GtkDialogClass))
typedef struct _GtkDialog GtkDialog;
typedef struct _GtkDialogClass GtkDialogClass;
struct _GtkDialog
{
GtkWindow window;
GtkWidget *vbox;
GtkWidget *action_area;
};
struct _GtkDialogClass
{
GtkWindowClass parent_class;
void (* action) (GtkDialog *dialog, gint action_id);
};
GtkType gtk_dialog_get_type (void);
GtkWidget* gtk_dialog_new (void);
GtkWidget* gtk_dialog_new_empty (const gchar *title,
GtkWindow *parent,
GtkDialogFlags flags);
GtkWidget* gtk_dialog_new_with_buttons (const gchar *title,
GtkWindow *parent,
GtkDialogFlags flags,
const gchar *first_button_text,
gint first_action_id,
...);
void gtk_dialog_add_action_widget (GtkDialog *dialog,
GtkWidget *widget,
gint action_id);
void gtk_dialog_add_button (GtkDialog *dialog,
const gchar *button_text,
gint action_id);
void gtk_dialog_add_buttons (GtkDialog *dialog,
const gchar *first_button_text,
gint first_action_id,
...);
/* Emit action signal */
void gtk_dialog_action (GtkDialog *dialog,
gint action_id);
/* Returns action_id */
gint gtk_dialog_run (GtkDialog *dialog);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __GTK_DIALOG_H__ */
/* GTK - The GIMP Toolkit
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/*
* Modified by the GTK+ Team and others 1997-1999. See the AUTHORS
* file for a list of people on the GTK+ Team. See the ChangeLog
* files for a list of changes. These files are distributed with
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/
#include "gtkbutton.h"
#include "gtkdialog.h"
#include "gtkhbbox.h"
#include "gtkhseparator.h"
#include "gtkvbox.h"
#include "gtksignal.h"
#include "gdkkeysyms.h"
#include "gtkmain.h"
static void gtk_dialog_class_init (GtkDialogClass *klass);
static void gtk_dialog_init (GtkDialog *dialog);
static gint gtk_dialog_key_press (GtkWidget *widget,
GdkEventKey *key);
static void gtk_dialog_add_buttons_valist(GtkDialog *dialog,
const gchar *first_button_text,
gint first_action_id,
va_list args);
enum {
ACTION,
LAST_SIGNAL
};
static gpointer parent_class;
static guint dialog_signals[LAST_SIGNAL];
GtkType
gtk_dialog_get_type (void)
{
static GtkType dialog_type = 0;
if (!dialog_type)
{
static const GtkTypeInfo dialog_info =
{
"GtkDialog",
sizeof (GtkDialog),
sizeof (GtkDialogClass),
(GtkClassInitFunc) gtk_dialog_class_init,
(GtkObjectInitFunc) gtk_dialog_init,
/* reserved_1 */ NULL,
/* reserved_2 */ NULL,
(GtkClassInitFunc) NULL,
};
dialog_type = gtk_type_unique (GTK_TYPE_WINDOW, &dialog_info);
}
return dialog_type;
}
static void
gtk_dialog_class_init (GtkDialogClass *class)
{
GtkObjectClass *object_class;
GtkWidgetClass *widget_class;
object_class = (GtkObjectClass*) class;
widget_class = (GtkWidgetClass*) class;
parent_class = g_type_class_peek_parent (class);
dialog_signals[ACTION] =
gtk_signal_new ("action",
GTK_RUN_LAST,
GTK_CLASS_TYPE (object_class),
GTK_SIGNAL_OFFSET (GtkDialogClass, action),
gtk_marshal_NONE__INT,
GTK_TYPE_NONE, 1,
GTK_TYPE_INT);
gtk_object_class_add_signals (object_class, dialog_signals, LAST_SIGNAL);
widget_class->key_press_event = gtk_dialog_key_press;
}
static void
gtk_dialog_init (GtkDialog *dialog)
{
GtkWidget *separator;
dialog->vbox = gtk_vbox_new (FALSE, 0);
gtk_container_add (GTK_CONTAINER (dialog), dialog->vbox);
gtk_widget_show (dialog->vbox);
dialog->action_area = gtk_hbutton_box_new ();
gtk_container_set_border_width (GTK_CONTAINER (dialog->action_area), 10);
gtk_box_pack_end (GTK_BOX (dialog->vbox), dialog->action_area, FALSE, TRUE, 0);
gtk_widget_show (dialog->action_area);
separator = gtk_hseparator_new ();
gtk_box_pack_end (GTK_BOX (dialog->vbox), separator, FALSE, TRUE, 0);
gtk_widget_show (separator);
}
static gint
gtk_dialog_key_press (GtkWidget *widget,
GdkEventKey *key)
{
GdkEventAny event = { GDK_DELETE, widget->window, FALSE };
if (GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, key))
return TRUE;
if (key->keyval != GDK_Escape)
return FALSE;
g_object_ref (G_OBJECT (event.window));
gtk_main_do_event ((GdkEvent*)&event);
g_object_unref (G_OBJECT (event.window));
return TRUE;
}
GtkWidget*
gtk_dialog_new (void)
{
return GTK_WIDGET (gtk_type_new (GTK_TYPE_DIALOG));
}
GtkWidget*
gtk_dialog_new_empty (const gchar *title,
GtkWindow *parent,
GtkDialogFlags flags)
{
GtkDialog *dialog;
dialog = GTK_DIALOG (g_type_create_instance (GTK_TYPE_DIALOG));
if (title)
gtk_window_set_title (GTK_WINDOW (dialog), title);
if (parent)
gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);
if (flags & GTK_DIALOG_MODAL)
gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
if (flags & GTK_DIALOG_DESTROY_WITH_PARENT)
gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE);
return GTK_WIDGET (dialog);
}
GtkWidget*
gtk_dialog_new_with_buttons (const gchar *title,
GtkWindow *parent,
GtkDialogFlags flags,
const gchar *first_button_text,
gint first_action_id,
...)
{
GtkDialog *dialog;
va_list args;
dialog = GTK_DIALOG (gtk_dialog_new_empty (title, parent, flags));
va_start (args, first_action_id);
gtk_dialog_add_buttons_valist (dialog,
first_button_text, first_action_id,
args);
va_end (args);
return GTK_WIDGET (dialog);
}
typedef struct _ActionData ActionData;
struct _ActionData
{
gint action_id;
};
static ActionData*
get_action_data (GtkWidget *widget)
{
ActionData *ad = gtk_object_get_data (GTK_OBJECT (widget),
"___gtk_dialog_action_data");
if (ad == NULL)
{
ad = g_new (ActionData, 1);
gtk_object_set_data_full (GTK_OBJECT (widget),
"___gtk_dialog_action_data",
ad,
g_free);
}
return ad;
}
static void
action_widget_activated (GtkWidget *widget, GtkDialog *dialog)
{
ActionData *ad;
gint action_id;
g_return_if_fail (GTK_IS_DIALOG (dialog));
action_id = GTK_ACTION_NONE;
ad = get_action_data (widget);
if (ad != NULL)
action_id = ad->action_id;
gtk_dialog_action (dialog, action_id);
}
static void
connect_action_widget (GtkDialog *dialog, GtkWidget *child)
{
if (GTK_WIDGET_GET_CLASS (child)->activate_signal != 0)
{
const gchar* name =
gtk_signal_name (GTK_WIDGET_GET_CLASS (child)->activate_signal != 0);
gtk_signal_connect_while_alive (GTK_OBJECT (child),
name,
GTK_SIGNAL_FUNC (action_widget_activated),
dialog,
GTK_OBJECT (dialog));
}
else
g_warning ("Only 'activatable' widgets can be packed into the action area of a GtkDialog");
}
void
gtk_dialog_add_action_widget (GtkDialog *dialog,
GtkWidget *widget,
gint action_id)
{
ActionData *ad;
g_return_if_fail (GTK_IS_DIALOG (dialog));
g_return_if_fail (GTK_IS_WIDGET (widget));
ad = get_action_data (widget);
ad->action_id = action_id;
connect_action_widget (dialog, widget);
gtk_box_pack_end (GTK_BOX (dialog->action_area),
widget,
FALSE, TRUE, 5);
}
void
gtk_dialog_add_button (GtkDialog *dialog,
const gchar *button_text,
gint action_id)
{
g_return_if_fail (GTK_IS_DIALOG (dialog));
g_return_if_fail (button_text != NULL);
gtk_dialog_add_action_widget (dialog,
gtk_button_new_stock (button_text, NULL),
action_id);
}
static void
gtk_dialog_add_buttons_valist(GtkDialog *dialog,
const gchar *first_button_text,
gint first_action_id,
va_list args)
{
const gchar* text;
gint action_id;
text = first_button_text;
action_id = first_action_id;
while (text != NULL)
{
gtk_dialog_add_button (dialog, text, action_id);
text = va_arg (args, gchar*);
if (text == NULL)
break;
action_id = va_arg (args, int);
}
}
void
gtk_dialog_add_buttons (GtkDialog *dialog,
const gchar *first_button_text,
gint first_action_id,
...)
{
va_list args;
va_start (args, first_action_id);
gtk_dialog_add_buttons_valist (dialog,
first_button_text, first_action_id,
args);
va_end (args);
}
void
gtk_dialog_action (GtkDialog *dialog,
gint action_id)
{
g_return_if_fail (dialog != NULL);
g_return_if_fail (GTK_IS_DIALOG (dialog));
gtk_signal_emit (GTK_OBJECT (dialog),
dialog_signals[ACTION],
action_id);
}
typedef struct {
GtkDialog *dialog;
gint action_id;
GMainLoop *loop;
guint action_handler;
guint destroy_handler;
guint delete_handler;
} RunInfo;
static void
run_destroy_handler (GtkDialog *dialog, gpointer data)
{
RunInfo *ri = data;
if (ri->loop != NULL)
{
g_main_quit (ri->loop);
g_main_destroy (ri->loop);
ri->loop = NULL;
}
}
static void
run_action_handler (GtkDialog *dialog,
gint action_id,
gpointer data)
{
RunInfo *ri;
ri = data;
ri->action_id = action_id;
run_destroy_handler (dialog, data);
}
static gint
run_delete_handler (GtkDialog *dialog,
GdkEventAny *event,
gpointer data)
{
run_destroy_handler (dialog, data);
return TRUE; /* Do not destroy */
}
gint
gtk_dialog_run (GtkDialog *dialog)
{
RunInfo ri = { NULL, GTK_ACTION_NONE, NULL, 0, 0 };
gboolean was_modal;
g_return_val_if_fail (dialog != NULL, -1);
g_return_val_if_fail (GTK_IS_DIALOG (dialog), -1);
gtk_object_ref (GTK_OBJECT (dialog));
was_modal = GTK_WINDOW (dialog)->modal;
if (!was_modal)
gtk_window_set_modal(GTK_WINDOW (dialog),TRUE);
ri.action_handler =
gtk_signal_connect (GTK_OBJECT (dialog),
"action",
GTK_SIGNAL_FUNC (run_action_handler),
&ri);
ri.destroy_handler =
gtk_signal_connect (GTK_OBJECT (dialog),
"destroy",
GTK_SIGNAL_FUNC (run_destroy_handler),
&ri);
ri.delete_handler =
gtk_signal_connect (GTK_OBJECT (dialog),
"delete_event",
GTK_SIGNAL_FUNC (run_delete_handler),
&ri);
ri.loop = g_main_new(FALSE);
g_main_run(ri.loop);
g_assert(ri.loop == NULL);
if (!GTK_OBJECT_DESTROYED (dialog))
{
if (!was_modal)
gtk_window_set_modal(GTK_WINDOW(dialog), FALSE);
gtk_signal_disconnect (GTK_OBJECT (dialog), ri.destroy_handler);
gtk_signal_disconnect (GTK_OBJECT (dialog), ri.action_handler);
gtk_signal_disconnect (GTK_OBJECT (dialog), ri.delete_handler);
}
gtk_object_unref (GTK_OBJECT (dialog));
return ri.action_id;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]