diff options
author | Christian Persch <chpe@cvs.gnome.org> | 2005-10-02 21:56:48 +0800 |
---|---|---|
committer | Christian Persch <chpe@src.gnome.org> | 2005-10-02 21:56:48 +0800 |
commit | a2bbf31b11386534161bdaf16fdec29cbd685673 (patch) | |
tree | a02af9189584dbf50c7ba7e7a72fbd03bb06ff32 /lib | |
parent | 456c0769c5dccb2c8ce312031219624e6edddc5c (diff) | |
download | gsoc2013-epiphany-a2bbf31b11386534161bdaf16fdec29cbd685673.tar gsoc2013-epiphany-a2bbf31b11386534161bdaf16fdec29cbd685673.tar.gz gsoc2013-epiphany-a2bbf31b11386534161bdaf16fdec29cbd685673.tar.bz2 gsoc2013-epiphany-a2bbf31b11386534161bdaf16fdec29cbd685673.tar.lz gsoc2013-epiphany-a2bbf31b11386534161bdaf16fdec29cbd685673.tar.xz gsoc2013-epiphany-a2bbf31b11386534161bdaf16fdec29cbd685673.tar.zst gsoc2013-epiphany-a2bbf31b11386534161bdaf16fdec29cbd685673.zip |
Don't include config.h here.
2005-10-02 Christian Persch <chpe@cvs.gnome.org>
* lib/ephy-debug.h:
Don't include config.h here.
* lib/widgets/ephy-spinner.c: (ephy_spinner_cache_data_unload),
(ephy_spinner_cache_data_load), (ephy_spinner_cache_data_new),
(ephy_spinner_cache_data_free), (ephy_spinner_cache_get_images),
(ephy_spinner_cache_init), (ephy_spinner_cache_finalize),
(ephy_spinner_load_images), (ephy_spinner_init),
(bump_spinner_frame_cb), (ephy_spinner_start),
(ephy_spinner_set_timeout), (ephy_spinner_finalize),
(ephy_spinner_screen_changed), (ephy_spinner_class_init):
Make spinner multihead safe.
* lib/widgets/testspinner.c:
Add a tiny spinner test program.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/ephy-debug.h | 2 | ||||
-rw-r--r-- | lib/widgets/ephy-spinner.c | 233 | ||||
-rw-r--r-- | lib/widgets/testiconentry.c | 20 | ||||
-rw-r--r-- | lib/widgets/testspinner.c | 165 |
4 files changed, 362 insertions, 58 deletions
diff --git a/lib/ephy-debug.h b/lib/ephy-debug.h index 2c49158a7..6c494e165 100644 --- a/lib/ephy-debug.h +++ b/lib/ephy-debug.h @@ -21,8 +21,6 @@ #ifndef EPHY_DEBUG_H #define EPHY_DEBUG_H -#include "config.h" - #include <glib.h> G_BEGIN_DECLS diff --git a/lib/widgets/ephy-spinner.c b/lib/widgets/ephy-spinner.c index 34876cf95..5d6ff5916 100644 --- a/lib/widgets/ephy-spinner.c +++ b/lib/widgets/ephy-spinner.c @@ -28,10 +28,12 @@ * $Id$ */ +#ifndef COMPILING_TESTSPINNER #include "config.h" +#include "ephy-debug.h" +#endif #include "ephy-spinner.h" -#include "ephy-debug.h" #include <gdk-pixbuf/gdk-pixbuf.h> #include <gtk/gtkicontheme.h> @@ -50,16 +52,6 @@ typedef struct _EphySpinnerCache EphySpinnerCache; typedef struct _EphySpinnerCacheClass EphySpinnerCacheClass; typedef struct _EphySpinnerCachePrivate EphySpinnerCachePrivate; -typedef struct _EphySpinnerImages EphySpinnerImages; - -struct _EphySpinnerImages -{ - GtkIconSize size; - int width; - int height; - GdkPixbuf *quiescent_pixbuf; - GList *images; -}; struct _EphySpinnerCacheClass { @@ -76,12 +68,28 @@ struct _EphySpinnerCache #define EPHY_SPINNER_CACHE_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EPHY_TYPE_SPINNER_CACHE, EphySpinnerCachePrivate)) -struct _EphySpinnerCachePrivate +typedef struct { + GtkIconSize size; + int width; + int height; + GdkPixbuf *quiescent_pixbuf; + GList *images; +} EphySpinnerImages; + +typedef struct +{ + GdkScreen *screen; GtkIconTheme *icon_theme; EphySpinnerImages *originals; /* List of EphySpinnerImages scaled to different sizes */ GList *images; +} EphySpinnerCacheData; + +struct _EphySpinnerCachePrivate +{ + /* Hash table of GdkScreen -> EphySpinnerCacheData */ + GHashTable *hash; }; static void ephy_spinner_cache_class_init (EphySpinnerCacheClass *klass); @@ -146,11 +154,15 @@ ephy_spinner_images_copy (EphySpinnerImages *images) } static void -ephy_spinner_cache_unload (EphySpinnerCache *cache) +ephy_spinner_cache_data_unload (EphySpinnerCacheData *data) { - g_list_foreach (cache->priv->images, (GFunc) ephy_spinner_images_free, NULL); - cache->priv->images = NULL; - cache->priv->originals = NULL; + g_return_if_fail (data != NULL); + + LOG ("EphySpinnerDataCache unload for screen %p", data->screen); + + g_list_foreach (data->images, (GFunc) ephy_spinner_images_free, NULL); + data->images = NULL; + data->originals = NULL; } static GdkPixbuf * @@ -176,7 +188,7 @@ extract_frame (GdkPixbuf *grid_pixbuf, } static void -ephy_spinner_cache_load (EphySpinnerCache *cache) +ephy_spinner_cache_data_load (EphySpinnerCacheData *data) { EphySpinnerImages *images; GdkPixbuf *icon_pixbuf, *pixbuf; @@ -184,14 +196,16 @@ ephy_spinner_cache_load (EphySpinnerCache *cache) int grid_width, grid_height, x, y, size, h, w; const char *icon; - LOG ("EphySpinnerCache loading"); + g_return_if_fail (data != NULL); + + LOG ("EphySpinnerCacheData loading for screen %p", data->screen); - ephy_spinner_cache_unload (cache); + ephy_spinner_cache_data_unload (data); START_PROFILER ("loading spinner animation") /* Load the animation */ - icon_info = gtk_icon_theme_lookup_icon (cache->priv->icon_theme, + icon_info = gtk_icon_theme_lookup_icon (data->icon_theme, "gnome-spinner", -1, 0); if (icon_info == NULL) { @@ -219,8 +233,8 @@ ephy_spinner_cache_load (EphySpinnerCache *cache) grid_height = gdk_pixbuf_get_height (icon_pixbuf); images = g_new (EphySpinnerImages, 1); - cache->priv->images = g_list_prepend (NULL, images); - cache->priv->originals = images; + data->images = g_list_prepend (NULL, images); + data->originals = images; images->size = GTK_ICON_SIZE_INVALID; images->width = images->height = size; @@ -250,7 +264,7 @@ ephy_spinner_cache_load (EphySpinnerCache *cache) g_object_unref (icon_pixbuf); /* Load the rest icon */ - icon_info = gtk_icon_theme_lookup_icon (cache->priv->icon_theme, + icon_info = gtk_icon_theme_lookup_icon (data->icon_theme, "gnome-spinner-rest", -1, 0); if (icon_info == NULL) { @@ -286,6 +300,39 @@ ephy_spinner_cache_load (EphySpinnerCache *cache) STOP_PROFILER ("loading spinner animation") } +static EphySpinnerCacheData * +ephy_spinner_cache_data_new (GdkScreen *screen) +{ + EphySpinnerCacheData *data; + + data = g_new0 (EphySpinnerCacheData, 1); + + data->screen = screen; + data->icon_theme = gtk_icon_theme_get_for_screen (screen); + g_signal_connect_swapped (data->icon_theme, "changed", + G_CALLBACK (ephy_spinner_cache_data_load), + data); + + ephy_spinner_cache_data_load (data); + + return data; +} + +static void +ephy_spinner_cache_data_free (EphySpinnerCacheData *data) +{ + g_return_if_fail (data != NULL); + g_return_if_fail (data->icon_theme != NULL); + + g_signal_handlers_disconnect_by_func + (data->icon_theme, + G_CALLBACK (ephy_spinner_cache_data_load), data); + + ephy_spinner_cache_data_unload (data); + + g_free (data); +} + static int compare_size (gconstpointer images_ptr, gconstpointer size_ptr) @@ -327,21 +374,33 @@ scale_to_size (GdkPixbuf *pixbuf, static EphySpinnerImages * ephy_spinner_cache_get_images (EphySpinnerCache *cache, + GdkScreen *screen, GtkIconSize size) { + EphySpinnerCachePrivate *priv = cache->priv; + EphySpinnerCacheData *data; EphySpinnerImages *images; + GtkSettings *settings; GdkPixbuf *pixbuf, *scaled_pixbuf; GList *element, *l; int h, w; - LOG ("Getting animation images at size %d", size); + LOG ("Getting animation images at size %d for screen %p", size, screen); - if (cache->priv->images == NULL || cache->priv->originals == NULL) + data = g_hash_table_lookup (priv->hash, screen); + if (data == NULL) { + data = ephy_spinner_cache_data_new (screen); + g_hash_table_insert (priv->hash, screen, data); + } + + if (data->images == NULL || data->originals == NULL) + { + /* Load failed, but don't try endlessly again! */ return NULL; } - element = g_list_find_custom (cache->priv->images, + element = g_list_find_custom (data->images, GINT_TO_POINTER (size), (GCompareFunc) compare_size); if (element != NULL) @@ -349,9 +408,10 @@ ephy_spinner_cache_get_images (EphySpinnerCache *cache, return ephy_spinner_images_copy ((EphySpinnerImages *) element->data); } - if (!gtk_icon_size_lookup_for_settings (gtk_settings_get_default (), size, &w, &h)) + settings = gtk_settings_get_for_screen (screen); + if (!gtk_icon_size_lookup_for_settings (settings, size, &w, &h)) { - g_warning ("Failed to lookup icon size\n"); + g_warning ("Failed to look up icon size\n"); return NULL; } @@ -363,7 +423,7 @@ ephy_spinner_cache_get_images (EphySpinnerCache *cache, START_PROFILER ("scaling spinner animation") - for (l = cache->priv->originals->images; l != NULL; l = l->next) + for (l = data->originals->images; l != NULL; l = l->next) { pixbuf = (GdkPixbuf *) l->data; scaled_pixbuf = scale_to_size (pixbuf, w, h); @@ -373,10 +433,10 @@ ephy_spinner_cache_get_images (EphySpinnerCache *cache, images->images = g_list_reverse (images->images); images->quiescent_pixbuf = - scale_to_size (cache->priv->originals->quiescent_pixbuf, w, h); + scale_to_size (data->originals->quiescent_pixbuf, w, h); /* store in cache */ - cache->priv->images = g_list_prepend (cache->priv->images, images); + data->images = g_list_prepend (data->images, images); STOP_PROFILER ("scaling spinner animation") @@ -386,29 +446,26 @@ ephy_spinner_cache_get_images (EphySpinnerCache *cache, static void ephy_spinner_cache_init (EphySpinnerCache *cache) { - cache->priv = EPHY_SPINNER_CACHE_GET_PRIVATE (cache); + EphySpinnerCachePrivate *priv; - LOG ("EphySpinnerCache initialising"); + priv = cache->priv = EPHY_SPINNER_CACHE_GET_PRIVATE (cache); - /* FIXME: icon theme is per-screen, not global */ - cache->priv->icon_theme = gtk_icon_theme_get_default (); - g_signal_connect_swapped (cache->priv->icon_theme, "changed", - G_CALLBACK (ephy_spinner_cache_load), cache); + LOG ("EphySpinnerCache initialising"); - ephy_spinner_cache_load (cache); + priv->hash = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, + (GDestroyNotify) ephy_spinner_cache_data_free); } static void ephy_spinner_cache_finalize (GObject *object) { EphySpinnerCache *cache = EPHY_SPINNER_CACHE (object); + EphySpinnerCachePrivate *priv = cache->priv; LOG ("EphySpinnerCache finalising"); - g_signal_handlers_disconnect_by_func - (cache->priv->icon_theme, G_CALLBACK(ephy_spinner_cache_load), cache); - - ephy_spinner_cache_unload (cache); + g_hash_table_destroy (priv->hash); G_OBJECT_CLASS (cache_parent_class)->finalize (object); } @@ -460,6 +517,7 @@ struct _EphySpinnerDetails GtkIconSize size; EphySpinnerImages *images; GList *current_image; + guint timeout; guint timer_task; guint spinning : 1; }; @@ -507,7 +565,10 @@ ephy_spinner_load_images (EphySpinner *spinner) START_PROFILER ("ephy_spinner_load_images") details->images = - ephy_spinner_cache_get_images (details->cache, details->size); + ephy_spinner_cache_get_images + (details->cache, + gtk_widget_get_screen (GTK_WIDGET (spinner)), + details->size); if (details->images != NULL) { @@ -539,6 +600,7 @@ icon_theme_changed_cb (GtkIconTheme *icon_theme, static void ephy_spinner_init (EphySpinner *spinner) { + EphySpinnerDetails *details = spinner->details; GtkWidget *widget = GTK_WIDGET (spinner); gtk_widget_set_events (widget, @@ -546,17 +608,12 @@ ephy_spinner_init (EphySpinner *spinner) | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK); - spinner->details = EPHY_SPINNER_GET_PRIVATE (spinner); - - spinner->details->cache = ephy_spinner_cache_ref (); - spinner->details->size = GTK_ICON_SIZE_INVALID; - spinner->details->spinning = FALSE; - - /* FIXME: multihead */ - spinner->details->icon_theme = gtk_icon_theme_get_default (); - g_signal_connect (spinner->details->icon_theme, "changed", - G_CALLBACK (icon_theme_changed_cb), spinner); + details = spinner->details = EPHY_SPINNER_GET_PRIVATE (spinner); + details->cache = ephy_spinner_cache_ref (); + details->size = GTK_ICON_SIZE_INVALID; + details->spinning = FALSE; + details->timeout = SPINNER_TIMEOUT; } static GdkPixbuf * @@ -652,7 +709,7 @@ bump_spinner_frame_cb (EphySpinner *spinner) frame = spinner->details->current_image; - if (g_list_next (frame) != NULL) + if (frame->next != NULL) { frame = frame->next; } @@ -694,7 +751,7 @@ ephy_spinner_start (EphySpinner *spinner) } spinner->details->timer_task = - g_timeout_add (SPINNER_TIMEOUT, + g_timeout_add (details->timeout, (GSourceFunc) bump_spinner_frame_cb, spinner); } @@ -756,6 +813,32 @@ ephy_spinner_set_size (EphySpinner *spinner, } } +/* + * ephy_spinner_set_timeout: + * @spinner: a #EphySpinner + * @timeout: time delay between updates to the spinner. + * + * Sets the timeout delay for spinner updates. + **/ +static void +ephy_spinner_set_timeout (EphySpinner *spinner, + guint timeout) +{ + EphySpinnerDetails *details = spinner->details; + + if (timeout != details->timeout) + { + ephy_spinner_stop (spinner); + + details->timeout = timeout; + + if (details->spinning) + { + ephy_spinner_start (spinner); + } + } +} + static void ephy_spinner_size_request (GtkWidget *widget, GtkRequisition *requisition) @@ -813,7 +896,7 @@ ephy_spinner_finalize (GObject *object) EphySpinner *spinner = EPHY_SPINNER (object); g_signal_handlers_disconnect_by_func - (spinner->details->icon_theme, + (spinner->details->icon_theme, G_CALLBACK (icon_theme_changed_cb), spinner); ephy_spinner_remove_update_callback (spinner); @@ -825,6 +908,43 @@ ephy_spinner_finalize (GObject *object) } static void +ephy_spinner_screen_changed (GtkWidget *widget, + GdkScreen *old_screen) +{ + EphySpinner *spinner = EPHY_SPINNER (widget); + EphySpinnerDetails *details = spinner->details; + GdkScreen *screen; + + if (GTK_WIDGET_CLASS (parent_class)->screen_changed) + { + GTK_WIDGET_CLASS (parent_class)->screen_changed (widget, old_screen); + } + + screen = gtk_widget_get_screen (widget); + + /* FIXME: this seems to be happening when then spinner is destroyed!? */ + if (old_screen == screen) return; + + /* We'll get mapped again on the new screen, but not unmapped from + * the old screen, so remove timeout here. + */ + ephy_spinner_remove_update_callback (spinner); + + ephy_spinner_unload_images (spinner); + + if (old_screen != NULL) + { + g_signal_handlers_disconnect_by_func + (gtk_icon_theme_get_for_screen (old_screen), + G_CALLBACK (icon_theme_changed_cb), spinner); + } + + details->icon_theme = gtk_icon_theme_get_for_screen (screen); + g_signal_connect (details->icon_theme, "changed", + G_CALLBACK (icon_theme_changed_cb), spinner); +} + +static void ephy_spinner_class_init (EphySpinnerClass *class) { GObjectClass *object_class = G_OBJECT_CLASS (class); @@ -838,6 +958,7 @@ ephy_spinner_class_init (EphySpinnerClass *class) widget_class->size_request = ephy_spinner_size_request; widget_class->map = ephy_spinner_map; widget_class->unmap = ephy_spinner_unmap; + widget_class->screen_changed = ephy_spinner_screen_changed; g_type_class_add_private (object_class, sizeof (EphySpinnerDetails)); } diff --git a/lib/widgets/testiconentry.c b/lib/widgets/testiconentry.c index 622f3ef07..fe593b943 100644 --- a/lib/widgets/testiconentry.c +++ b/lib/widgets/testiconentry.c @@ -1,3 +1,23 @@ +/* + * Copyright (C) 2005 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id$ + */ + #include <glib.h> #include <gtk/gtk.h> #include <gtk/gtkstock.h> diff --git a/lib/widgets/testspinner.c b/lib/widgets/testspinner.c new file mode 100644 index 000000000..69c12c0ad --- /dev/null +++ b/lib/widgets/testspinner.c @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2005 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id$ + */ + +#include <glib.h> +#include <gtk/gtk.h> + +#define COMPILING_TESTSPINNER +#define LOG(msg, args...) G_STMT_START { } G_STMT_END +#define START_PROFILER(name) +#define STOP_PROFILER(name) + +#include "ephy-spinner.c" + +#define MOVE_TIMEOUT 211 /* ms */ + +static void start_or_stop (GtkToggleButton *button, EphySpinner *spinner) +{ + if (gtk_toggle_button_get_active (button)) + { + ephy_spinner_start (spinner); + } + else + { + ephy_spinner_stop (spinner); + } +} + +static void add_spinner (GtkTable *table, + int row, + GtkIconSize size, + const char *sizename, + guint interval, + gboolean start) +{ + GtkWidget *label, *frame, *spinner, *button, *spinbutton; + char *text; + + text = g_strdup_printf ("%s size:", sizename); + label = gtk_label_new (text); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.0); + gtk_table_attach_defaults (table, label, 0, 1, row, row + 1); + g_free (text); + + frame = gtk_frame_new (NULL); + gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN); + gtk_table_attach (table, frame, 1, 2, row, row + 1, GTK_SHRINK, GTK_SHRINK, 0, 0); + + spinner = ephy_spinner_new (); + ephy_spinner_set_size (EPHY_SPINNER (spinner), size); + gtk_container_add (GTK_CONTAINER (frame), spinner); + + button = gtk_check_button_new_with_label ("Spin"); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), start); + start_or_stop (GTK_TOGGLE_BUTTON (button), EPHY_SPINNER (spinner)); + g_signal_connect (button, "toggled", G_CALLBACK (start_or_stop), spinner); + gtk_table_attach_defaults (table, button, 2, 3, row, row + 1); +} + +static void move_window (GtkWindow *window) +{ + GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (window)); + GdkDisplay *display = gdk_screen_get_display (screen); + gint number_of_screens = gdk_display_get_n_screens (display); + gint screen_num = gdk_screen_get_number (screen); + + if ((screen_num + 1) < number_of_screens) + { + gtk_window_set_screen (window, gdk_display_get_screen (display, screen_num + 1)); + } + else + { + gtk_window_set_screen (window, gdk_display_get_screen (display, 0)); + } +} + +static gboolean +move_true (GtkWindow *window) +{ + move_window (window); + return TRUE; +} + +static void +start_or_stop_repeated_moves (GtkWindow *window) +{ + static guint timeout = 0; + + if (timeout == 0) + { + timeout = g_timeout_add (MOVE_TIMEOUT, (GSourceFunc) move_true, window); + } + else + { + g_source_remove (timeout); + timeout = 0; + } +} + +int main(int argc, char **argv) +{ + GtkWidget *window, *vbox, *widget; + GtkTable *table; + GtkTooltips *tips; + int row = 0; + + gtk_init (&argc, &argv); + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_container_set_border_width (GTK_CONTAINER (window), 12); + + vbox = gtk_vbox_new (FALSE, 6); + gtk_container_add (GTK_CONTAINER (window), vbox); + + widget = gtk_table_new (5, 3, FALSE); + gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0); + + table = GTK_TABLE (widget); + gtk_table_set_row_spacings (table, 6); + gtk_table_set_col_spacings (table,12); + + add_spinner (table, row++, GTK_ICON_SIZE_INVALID, "Native", 0, FALSE); + add_spinner (table, row++, GTK_ICON_SIZE_MENU, "Menu", 0, FALSE); + add_spinner (table, row++, GTK_ICON_SIZE_SMALL_TOOLBAR, "Small toolbar", 0, FALSE); + add_spinner (table, row++, GTK_ICON_SIZE_LARGE_TOOLBAR, "Large toolbar", 0, FALSE); + add_spinner (table, row++, GTK_ICON_SIZE_BUTTON, "Button", 0, FALSE); + add_spinner (table, row++, GTK_ICON_SIZE_DND, "Drag-and-drop", 0, FALSE); + add_spinner (table, row++, GTK_ICON_SIZE_DIALOG, "Dialog", 0, FALSE); + + widget = gtk_button_new_with_label ("Move to next screen"); + g_signal_connect_swapped (widget, "clicked", G_CALLBACK (move_window), window); + gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0); + + widget = gtk_toggle_button_new_with_label ("Move repeatedly to next screen"); + g_signal_connect_swapped (widget, "toggled", G_CALLBACK (start_or_stop_repeated_moves), window); + gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0); + + widget = gtk_button_new_with_label ("Quit"); + g_signal_connect_swapped (widget, "clicked", G_CALLBACK (gtk_widget_destroy), window); + gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0); + + gtk_widget_show_all (window); + + g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL); + + gtk_main (); + + return 0; +} |