Commit c73b9a77 authored by Matthias Clasen's avatar Matthias Clasen Committed by Matthias Clasen

Add GtkAssistant, a widget to construct multi-step wizards. (#115348,

2006-01-18  Matthias Clasen  <mclasen@redhat.com>

        * gtk/gtkassistant.[hc]: Add GtkAssistant, a widget to
        construct multi-step wizards.  (#115348, Martyn Russell,
        Matthias Clasen, Carlos Garnacho Parro)

        * gtk/gtk.symbols:
        * gtk/Makefile.am:
        * gtk/gtk.h: Necessary glue.
parent 4b705d23
2006-01-18 Matthias Clasen <mclasen@redhat.com>
* gtk/gtkassistant.[hc]: Add GtkAssistant, a widget to
construct multi-step wizards. (#115348, Martyn Russell,
Matthias Clasen, Carlos Garnacho Parro)
* gtk/gtk.symbols:
* gtk/Makefile.am:
* gtk/gtk.h: Necessary glue.
2006-01-18 Anders Carlsson <andersca@imendio.com>
* gdk/quartz/gdkevents-quartz.c:
......
2006-01-18 Matthias Clasen <mclasen@redhat.com>
* gtk/gtkassistant.[hc]: Add GtkAssistant, a widget to
construct multi-step wizards. (#115348, Martyn Russell,
Matthias Clasen, Carlos Garnacho Parro)
* gtk/gtk.symbols:
* gtk/Makefile.am:
* gtk/gtk.h: Necessary glue.
2006-01-18 Anders Carlsson <andersca@imendio.com>
* gdk/quartz/gdkevents-quartz.c:
......
2006-01-18 Matthias Clasen <mclasen@redhat.com>
* gtk/gtk-sections.txt:
* gtk/gtk-docs.sgml:
* gtk/gtk.types: Add GtkAssistant docs
2006-01-16 Matthias Clasen <mclasen@redhat.com>
* gtk/gtk-sections.txt: Add gtk_radio_action_set_current_value
2006-01-14 Matthias Clasen <mclasen@redhat.com>
* gtk/Makefile.am (HTML_IMAGES):
......
......@@ -9,6 +9,7 @@
<!ENTITY GtkAlignment SYSTEM "xml/gtkalignment.xml">
<!ENTITY GtkArrow SYSTEM "xml/gtkarrow.xml">
<!ENTITY GtkAspectFrame SYSTEM "xml/gtkaspectframe.xml">
<!ENTITY GtkAssistant SYSTEM "xml/gtkassistant.xml">
<!ENTITY GtkButtonBox SYSTEM "xml/gtkbbox.xml">
<!ENTITY GtkBin SYSTEM "xml/gtkbin.xml">
<!ENTITY GtkBox SYSTEM "xml/gtkbox.xml">
......@@ -348,6 +349,7 @@ that is, GUI components such as <link linkend="GtkButton">GtkButton</link> or
&GtkWindow;
&GtkWindowGroup;
&GtkAboutDialog;
&GtkAssistant;
</chapter>
<chapter id="DisplayWidgets">
......
......@@ -283,6 +283,46 @@ gtk_alignment_get_type
GtkAlignmentPrivate
</SECTION>
<SECTION>
<FILE>gtkassistant</FILE>
<TITLE>GtkAssistant</TITLE>
GtkAssistant
gtk_assistant_new
gtk_assistant_get_current_page
gtk_assistant_set_current_page
gtk_assistant_get_n_pages
gtk_assistant_get_nth_page
gtk_assistant_prepend_page
gtk_assistant_append_page
gtk_assistant_insert_page
GtkAssistantPageFunc
gtk_assistant_set_forward_page_func
GtkAssistantPageType
gtk_assistant_set_page_type
gtk_assistant_get_page_type
gtk_assistant_set_page_title
gtk_assistant_get_page_title
gtk_assistant_set_page_header_image
gtk_assistant_get_page_header_image
gtk_assistant_set_page_side_image
gtk_assistant_get_page_side_image
gtk_assistant_set_page_complete
gtk_assistant_get_page_complete
gtk_assistant_add_action_widget
gtk_assistant_remove_action_widget
<SUBSECTION Standard>
GtkAssistantClass
GTK_TYPE_ASSISTANT
GTK_ASSISTANT
GTK_ASSISTANT_CLASS
GTK_IS_ASSISTANT
GTK_IS_ASSISTANT_CLASS
GTK_ASSISTANT_GET_CLASS
<SUBSECTION Private>
gtk_assistant_get_type
</SECTION>
<SECTION>
<FILE>gtkarrow</FILE>
<TITLE>GtkArrow</TITLE>
......
......@@ -11,6 +11,7 @@ gtk_adjustment_get_type
gtk_alignment_get_type
gtk_arrow_get_type
gtk_aspect_frame_get_type
gtk_assistant_get_type
gtk_bin_get_type
gtk_box_get_type
gtk_button_box_get_type
......
......@@ -122,6 +122,7 @@ gtk_public_h_sources = \
gtkalignment.h \
gtkarrow.h \
gtkaspectframe.h \
gtkassistant.h \
gtkbbox.h \
gtkbin.h \
gtkbindings.h \
......@@ -337,6 +338,7 @@ gtk_c_sources = \
gtkalignment.c \
gtkarrow.c \
gtkaspectframe.c \
gtkassistant.c \
gtkbbox.c \
gtkbin.c \
gtkbindings.c \
......
......@@ -40,6 +40,7 @@
#include <gtk/gtkalignment.h>
#include <gtk/gtkarrow.h>
#include <gtk/gtkaspectframe.h>
#include <gtk/gtkassistant.h>
#include <gtk/gtkbbox.h>
#include <gtk/gtkbin.h>
#include <gtk/gtkbindings.h>
......
......@@ -209,6 +209,34 @@ gtk_alignment_set_padding
#endif
#endif
#if IN_HEADER(__GTK_ASSISTANT_H__)
#if IN_FILE(__GTK_ASSISTANT_C__)
gtk_assistant_get_type G_GNUC_CONST
gtk_assistant_new
gtk_assistant_get_current_page
gtk_assistant_set_current_page
gtk_assistant_get_n_pages
gtk_assistant_get_nth_page
gtk_assistant_prepend_page
gtk_assistant_append_page
gtk_assistant_insert_page
gtk_assistant_set_forward_page_func
gtk_assistant_set_page_type
gtk_assistant_get_page_type
gtk_assistant_set_page_title
gtk_assistant_get_page_title
gtk_assistant_set_page_header_image
gtk_assistant_get_page_header_image
gtk_assistant_set_page_side_image
gtk_assistant_get_page_side_image
gtk_assistant_set_page_complete
gtk_assistant_get_page_complete
gtk_assistant_add_action_widget
gtk_assistant_remove_action_widget
#endif
#endif
#if IN_HEADER(__GTK_TYPE_BUILTINS_H__)
#if IN_FILE(__GTK_TYPE_BUILTINS_C__)
gtk_pack_direction_get_type G_GNUC_CONST
......
/*
* GTK - The GIMP Toolkit
* Copyright (C) 1999 Red Hat, Inc.
* Copyright (C) 2002 Anders Carlsson <andersca@gnu.org>
* Copyright (C) 2003 Matthias Clasen <mclasen@redhat.com>
* Copyright (C) 2005 Carlos Garnacho Parro <carlosg@gnome.org>
*
* All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser 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.
*/
#include <config.h>
#include "gtkassistant.h"
#include "gtkbutton.h"
#include "gtkhbox.h"
#include "gtkimage.h"
#include "gtklabel.h"
#include "gtksizegroup.h"
#include "gtkstock.h"
#include "gtkintl.h"
#include "gtkprivate.h"
#include "gtkalias.h"
#define GTK_ASSISTANT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_TYPE_ASSISTANT, GtkAssistantPrivate))
#define HEADER_SPACING 12
typedef struct _GtkAssistantPage GtkAssistantPage;
struct _GtkAssistantPage
{
GtkWidget *page;
GtkAssistantPageType type;
gboolean complete;
GtkWidget *title;
GdkPixbuf *header_image;
GdkPixbuf *sidebar_image;
};
typedef struct _GtkAssistantPrivate GtkAssistantPrivate;
struct _GtkAssistantPrivate
{
GtkWidget *header_image;
GtkWidget *sidebar_image;
GtkWidget *action_area;
GList *pages;
GtkAssistantPage *current_page;
GSList *visited_pages;
GtkSizeGroup *size_group;
GtkAssistantPageFunc forward_function;
gpointer forward_function_data;
GDestroyNotify forward_data_destroy;
};
static void gtk_assistant_class_init (GtkAssistantClass *class);
static void gtk_assistant_init (GtkAssistant *assistant);
static void gtk_assistant_destroy (GtkObject *object);
static void gtk_assistant_style_set (GtkWidget *widget,
GtkStyle *old_style);
static void gtk_assistant_size_request (GtkWidget *widget,
GtkRequisition *requisition);
static void gtk_assistant_size_allocate (GtkWidget *widget,
GtkAllocation *allocation);
static void gtk_assistant_map (GtkWidget *widget);
static void gtk_assistant_unmap (GtkWidget *widget);
static gboolean gtk_assistant_delete_event (GtkWidget *widget,
GdkEventAny *event);
static gboolean gtk_assistant_expose (GtkWidget *widget,
GdkEventExpose *event);
static void gtk_assistant_add (GtkContainer *container,
GtkWidget *page);
static void gtk_assistant_remove (GtkContainer *container,
GtkWidget *page);
static void gtk_assistant_forall (GtkContainer *container,
gboolean include_internals,
GtkCallback callback,
gpointer callback_data);
static void gtk_assistant_set_child_property (GtkContainer *container,
GtkWidget *child,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void gtk_assistant_get_child_property (GtkContainer *container,
GtkWidget *child,
guint property_id,
GValue *value,
GParamSpec *pspec);
enum
{
CHILD_PROP_0,
CHILD_PROP_PAGE_TYPE,
CHILD_PROP_PAGE_TITLE,
CHILD_PROP_PAGE_HEADER_IMAGE,
CHILD_PROP_PAGE_SIDEBAR_IMAGE,
CHILD_PROP_PAGE_COMPLETE
};
enum
{
CANCEL,
PREPARE,
APPLY,
CLOSE,
LAST_SIGNAL
};
static guint signals [LAST_SIGNAL] = { 0 };
G_DEFINE_TYPE (GtkAssistant, gtk_assistant, GTK_TYPE_WINDOW);
static void
gtk_assistant_class_init (GtkAssistantClass *class)
{
GObjectClass *gobject_class;
GtkObjectClass *object_class;
GtkWidgetClass *widget_class;
GtkContainerClass *container_class;
gobject_class = (GObjectClass *) class;
object_class = (GtkObjectClass *) class;
widget_class = (GtkWidgetClass *) class;
container_class = (GtkContainerClass *) class;
object_class->destroy = gtk_assistant_destroy;
widget_class->style_set = gtk_assistant_style_set;
widget_class->size_request = gtk_assistant_size_request;
widget_class->size_allocate = gtk_assistant_size_allocate;
widget_class->map = gtk_assistant_map;
widget_class->unmap = gtk_assistant_unmap;
widget_class->delete_event = gtk_assistant_delete_event;
widget_class->expose_event = gtk_assistant_expose;
container_class->add = gtk_assistant_add;
container_class->remove = gtk_assistant_remove;
container_class->forall = gtk_assistant_forall;
container_class->set_child_property = gtk_assistant_set_child_property;
container_class->get_child_property = gtk_assistant_get_child_property;
/**
* GtkAssistant::cancel:
* @assistant: the #GtkAssistant
* @page: the current page
*
* The ::cancel signal is emitted when then the cancel button is clicked.
*
* Since: 2.10
*/
signals[CANCEL] =
g_signal_new (I_("cancel"),
G_TYPE_FROM_CLASS (gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GtkAssistantClass, cancel),
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
/**
* GtkAssistant::prepare:
* @assistant: the #GtkAssistant
* @page: the current page
*
* The ::prepared signal is emitted when a new page is set as the assistant's
* current page, before making the new page visible. A handler for this signal
* can do any preparation which are necessary before showing @page.
*
* Since: 2.10
*/
signals[PREPARE] =
g_signal_new (I_("prepare"),
G_TYPE_FROM_CLASS (gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GtkAssistantClass, prepare),
NULL, NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE, 1, GTK_TYPE_WIDGET);
/**
* GtkAssistant::apply:
* @assistant: the @GtkAssistant
* @page: the current page
*
* The ::apply signal is emitted when the apply button is clicked. The default
* behavior of the #GtkAssistant is to switch to the page after the current page,
* unless the current page is the last one.
*
* A handler for the ::apply signal should carry out the actions for which the
* wizard has collected data. If the action takes a long time to complete, you
* might consider to put a page displaying the progress of the operation after the
* confirmation page with the apply button.
*
* Return value: %TRUE to suppress the default behavior
*
* Since: 2.10
*/
signals[APPLY] =
g_signal_new (I_("apply"),
G_TYPE_FROM_CLASS (gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GtkAssistantClass, apply),
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
/**
* GtkAssistant::close:
* @assistant: the #GtkAssistant
* @page: the current page
*
* The ::close signal is emitted when the close button is clicked.
*
* Since: 2.10
*/
signals[CLOSE] =
g_signal_new (I_("close"),
G_TYPE_FROM_CLASS (gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GtkAssistantClass, close),
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
gtk_widget_class_install_style_property (widget_class,
g_param_spec_int ("header-padding",
P_("Header Padding"),
P_("Number of pixels around the header."),
0,
G_MAXINT,
6,
GTK_PARAM_READABLE));
gtk_widget_class_install_style_property (widget_class,
g_param_spec_int ("content-padding",
P_("Content Padding"),
P_("Number of pixels around the content pages."),
0,
G_MAXINT,
1,
GTK_PARAM_READABLE));
/**
* GtkAssistant:page-type:
*
* The type of the assistant page.
*
* Since: 2.10
*/
gtk_container_class_install_child_property (container_class,
CHILD_PROP_PAGE_TYPE,
g_param_spec_enum ("page-type",
P_("Page type"),
P_("The type of the assistant page"),
GTK_TYPE_ASSISTANT_PAGE_TYPE,
GTK_ASSISTANT_PAGE_CONTENT,
GTK_PARAM_READWRITE));
/**
* GtkAssistant:title:
*
* The title that is displayed in the page header.
*
* If title and header-image are both %NULL, no header is displayed.
*
* Since: 2.10
*/
gtk_container_class_install_child_property (container_class,
CHILD_PROP_PAGE_TITLE,
g_param_spec_string ("title",
P_("Page title"),
P_("The title of the assistant page"),
NULL,
GTK_PARAM_READWRITE));
/**
* GtkAssistant:header-image:
*
* The image that is displayed next to the title in the page header.
*
* If title and header-image are both %NULL, no header is displayed.
*
* Since: 2.10
*/
gtk_container_class_install_child_property (container_class,
CHILD_PROP_PAGE_HEADER_IMAGE,
g_param_spec_object ("header-image",
P_("Header image"),
P_("Header image for the assistant page"),
GDK_TYPE_PIXBUF,
GTK_PARAM_READWRITE));
/**
* GtkAssistant:header-image:
*
* The image that is displayed next to the page.
*
* Set this to %NULL to make the sidebar disappear.
*
* Since: 2.10
*/
gtk_container_class_install_child_property (container_class,
CHILD_PROP_PAGE_SIDEBAR_IMAGE,
g_param_spec_object ("sidebar-image",
P_("Sidebar image"),
P_("Sidebar image for the assistant page"),
GDK_TYPE_PIXBUF,
GTK_PARAM_READWRITE));
/**
* GtkAssistant:complete:
*
* Setting the "complete" child property to %TRUE marks a page as complete
* (i.e.: all the required fields are filled out). GTK+ uses this information
* to control the sensitivity of the navigation buttons.
*
* Since: 2.10
**/
gtk_container_class_install_child_property (container_class,
CHILD_PROP_PAGE_COMPLETE,
g_param_spec_boolean ("complete",
P_("Page complete"),
P_("Whether all required fields on the page have been filled out"),
FALSE,
G_PARAM_READWRITE));
g_type_class_add_private (gobject_class, sizeof (GtkAssistantPrivate));
}
static gint
default_forward_function (gint current_page, gpointer data)
{
GtkAssistant *assistant;
GtkAssistantPrivate *priv;
GtkAssistantPage *page_info;
GList *page_node;
assistant = GTK_ASSISTANT (data);
priv = GTK_ASSISTANT_GET_PRIVATE (assistant);
page_node = g_list_nth (priv->pages, ++current_page);
if (!page_node)
return -1;
page_info = (GtkAssistantPage *) page_node->data;
while (!GTK_WIDGET_VISIBLE (page_info->page))
{
page_node = page_node->next;
page_info = (GtkAssistantPage *) page_node->data;
current_page++;
}
return current_page;
}
static void
compute_last_button_state (GtkAssistant *assistant)
{
GtkAssistantPrivate *priv;
GtkAssistantPage *page_info;
gint count, page_num, n_pages;
priv = GTK_ASSISTANT_GET_PRIVATE (assistant);
count = 0;
page_num = gtk_assistant_get_current_page (assistant);
n_pages = gtk_assistant_get_n_pages (assistant);
page_info = g_list_nth_data (priv->pages, page_num);
while ((page_num > 0 && page_num < n_pages) &&
(page_info->type == GTK_ASSISTANT_PAGE_CONTENT) &&
(page_info->complete))
{
page_num = (priv->forward_function) (page_num, priv->forward_function_data);
page_info = g_list_nth_data (priv->pages, page_num);
count++;
}
if (count > 1)
gtk_widget_show (assistant->last);
else
gtk_widget_hide (assistant->last);
}
static void
_set_assistant_header_image (GtkAssistant *assistant)
{
GtkAssistantPrivate *priv;
priv = GTK_ASSISTANT_GET_PRIVATE (assistant);
gtk_image_set_from_pixbuf (GTK_IMAGE (priv->header_image),
priv->current_page->header_image);
}
static void
_set_assistant_sidebar_image (GtkAssistant *assistant)
{
GtkAssistantPrivate *priv;
priv = GTK_ASSISTANT_GET_PRIVATE (assistant);
gtk_image_set_from_pixbuf (GTK_IMAGE (priv->sidebar_image),
priv->current_page->sidebar_image);
if (priv->current_page->sidebar_image)
gtk_widget_show (priv->sidebar_image);
else
gtk_widget_hide (priv->sidebar_image);
}
static void
_set_assistant_buttons_state (GtkAssistant *assistant)
{
GtkAssistantPrivate *priv;
priv = GTK_ASSISTANT_GET_PRIVATE (assistant);
switch (priv->current_page->type)
{
case GTK_ASSISTANT_PAGE_INTRO:
gtk_widget_set_sensitive (assistant->cancel, TRUE);
gtk_widget_set_sensitive (assistant->forward, priv->current_page->complete);
gtk_widget_show (assistant->cancel);
gtk_widget_show (assistant->forward);
gtk_widget_hide (assistant->back);
gtk_widget_hide (assistant->apply);
gtk_widget_hide (assistant->close);
compute_last_button_state (assistant);
break;
case GTK_ASSISTANT_PAGE_CONFIRM:
gtk_widget_set_sensitive (assistant->cancel, TRUE);
gtk_widget_set_sensitive (assistant->back, TRUE);
gtk_widget_set_sensitive (assistant->apply, priv->current_page->complete);
gtk_widget_show (assistant->cancel);
gtk_widget_show (assistant->back);
gtk_widget_show (assistant->apply);
gtk_widget_hide (assistant->forward);
gtk_widget_hide (assistant->close);
gtk_widget_hide (assistant->last);
break;
case GTK_ASSISTANT_PAGE_CONTENT:
gtk_widget_set_sensitive (assistant->cancel, TRUE);
gtk_widget_set_sensitive (assistant->back, TRUE);
gtk_widget_set_sensitive (assistant->forward, priv->current_page->complete);
gtk_widget_show (assistant->cancel);
gtk_widget_show (assistant->back);
gtk_widget_show (assistant->forward);
gtk_widget_hide (assistant->apply);
gtk_widget_hide (assistant->close);
compute_last_button_state (assistant);
break;
case GTK_ASSISTANT_PAGE_SUMMARY:
gtk_widget_set_sensitive (assistant->close, TRUE);
gtk_widget_show (assistant->close);
gtk_widget_hide (assistant->cancel);
gtk_widget_hide (assistant->back);
gtk_widget_hide (assistant->forward);
gtk_widget_hide (assistant->apply);
gtk_widget_hide (assistant->last);
break;
case GTK_ASSISTANT_PAGE_PROGRESS:
gtk_widget_set_sensitive (assistant->cancel, priv->current_page->complete);
gtk_widget_set_sensitive (assistant->back, priv->current_page->complete);
gtk_widget_set_sensitive (assistant->forward, priv->current_page->complete);
gtk_widget_show (assistant->cancel);
gtk_widget_show (assistant->back);
gtk_widget_show (assistant->forward);
gtk_widget_hide (assistant->apply);
gtk_widget_hide (assistant->close);
gtk_widget_hide (assistant->last);
break;
default:
g_assert_not_reached ();
}
/* this is quite general, we don't want to
* go back if it's the first page */
if (!priv->visited_pages)
gtk_widget_hide (assistant->back);
}
static void
_set_current_page (GtkAssistant *assistant,
GtkAssistantPage *page)
{
GtkAssistantPrivate *priv;
GtkAssistantPage *old_page;
priv = GTK_ASSISTANT_GET_PRIVATE (assistant);
if (priv->current_page &&
GTK_WIDGET_DRAWABLE (priv->current_page->page))
old_page = priv->current_page;
else
old_page = NULL;
priv->current_page = page;
_set_assistant_buttons_state (assistant);
_set_assistant_header_image (assistant);
_set_assistant_sidebar_image (assistant);
g_signal_emit (assistant, signals [PREPARE], 0, priv->current_page->page);
if (GTK_WIDGET_VISIBLE (priv->current_page->page) && GTK_WIDGET_MAPPED (assistant))
{
gtk_widget_map (priv->current_page->page);
gtk_widget_map (priv->current_page->title);
}
if (old_page && GTK_WIDGET_MAPPED (old_page->page))
{
gtk_widget_unmap (old_page->page);
gtk_widget_unmap (old_page->title);
}
gtk_widget_queue_resize (GTK_WIDGET (assistant));
}
static gint
compute_next_step (GtkAssistant *assistant)
{
GtkAssistantPrivate *priv;
GtkAssistantPage *page_info;
gint current_page, n_pages, next_page;
priv = GTK_ASSISTANT_GET_PRIVATE (assistant);
current_page = gtk_assistant_get_current_page (assistant);
page_info = priv->current_page;
n_pages = gtk_assistant_get_n_pages (assistant);
next_page = (priv->forward_function) (current_page,
priv->forward_function_data);
if (next_page >= 0 && next_page < n_pages)
{
priv->visited_pages = g_slist_prepend (priv->visited_pages, page_info);
_set_current_page (assistant, g_list_nth_data (priv->pages, next_page));
return TRUE;
}
return FALSE;
}
static void
on_assistant_close (GtkWidget *widget, GtkAssistant *assistant)
{
GtkAssistantPrivate *priv;
priv = GTK_ASSISTANT_GET_PRIVATE (assistant);
g_signal_emit (assistant, signals [CLOSE], 0, NULL);
}