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]