gnome-control-center/capplets/common/theme-thumbnail.c
Thomas Wood bc8e3ee007 Don't try and open null filenames Reset the gtk_color_scheme after a
2007-03-04  Thomas Wood  <thos@gnome.org>

	* gnome-theme-info.c: (gnome_theme_read_meta_theme): Don't try and open null
	filenames
	* theme-thumbnail.c: (message_from_capplet): Reset the gtk_color_scheme after
	a thumbnail has been generated.

svn path=/trunk/; revision=7359
2007-03-04 18:28:57 +00:00

683 lines
21 KiB
C

#include <unistd.h>
#include <string.h>
#include <metacity-private/util.h>
#include <metacity-private/theme.h>
#include <metacity-private/theme-parser.h>
#include <metacity-private/preview-widget.h>
#include <signal.h>
#include <errno.h>
/* We have to #undef this as metacity #defines these. */
#undef _
#undef N_
#include <libgnomeui/gnome-icon-theme.h>
#include <config.h>
#include "theme-thumbnail.h"
#include "capplet-util.h"
static gint child_pid;
#define ICON_SIZE_WIDTH 150
#define ICON_SIZE_HEIGHT 150
typedef struct
{
gboolean set;
GByteArray *data;
gchar *meta_theme_name;
ThemeThumbnailFunc func;
gpointer user_data;
GDestroyNotify destroy;
GIOChannel *channel;
guint watch_id;
} ThemeThumbnailAsyncData;
static GHashTable *theme_hash = NULL;
static ThemeThumbnailAsyncData async_data;
/* Protocol */
/* Our protocol is pretty simple. The parent process will write four strings
* (separated by a '\000') They are the widget theme, the wm theme, the icon
* theme, and the font string. Then, it will wait for the child to write back
* the data. The parent expects ICON_SIZE_WIDTH * ICON_SIZE_HEIGHT * 4 bytes of
* information. After that, the child is ready for the next theme to render.
*/
enum
{
READY_FOR_THEME,
READING_CONTROL_THEME_NAME,
READING_GTK_COLOR_SCHEME,
READING_WM_THEME_NAME,
READING_ICON_THEME_NAME,
READING_APPLICATION_FONT,
WRITING_PIXBUF_DATA
};
typedef struct
{
gint status;
GByteArray *control_theme_name;
GByteArray *gtk_color_scheme;
GByteArray *wm_theme_name;
GByteArray *icon_theme_name;
GByteArray *application_font;
} ThemeThumbnailData;
static int pipe_to_factory_fd[2];
static int pipe_from_factory_fd[2];
static void
fake_expose_widget (GtkWidget *widget,
GdkPixmap *pixmap,
GdkRectangle *area)
{
GdkWindow *tmp_window;
GdkEventExpose event;
event.type = GDK_EXPOSE;
event.window = pixmap;
event.send_event = FALSE;
event.area = area ? *area : widget->allocation;
event.region = NULL;
event.count = 0;
tmp_window = widget->window;
widget->window = pixmap;
gtk_widget_send_expose (widget, (GdkEvent *) &event);
widget->window = tmp_window;
}
static void
hbox_foreach (GtkWidget *widget,
gpointer data)
{
gtk_widget_realize (widget);
gtk_widget_map (widget);
gtk_widget_ensure_style (widget);
fake_expose_widget (widget, (GdkPixmap *) data, NULL);
}
static void
create_image (ThemeThumbnailData *theme_thumbnail_data,
GdkPixbuf *pixbuf)
{
GtkWidget *window;
GtkWidget *preview;
GtkWidget *align;
GtkWidget *stock_button;
GtkRequisition requisition;
GtkAllocation allocation;
GdkPixmap *pixmap;
GdkVisual *visual;
MetaFrameFlags flags;
MetaTheme *theme = NULL;
GtkSettings *settings;
GtkIconTheme *icon_theme;
GdkPixbuf *folder_icon = NULL;
GtkIconInfo *folder_icon_info;
const gchar *filename;
gchar *example_icon_name;
int width, height;
double scale;
settings = gtk_settings_get_default ();
g_object_set (G_OBJECT (settings),
"gtk-theme-name", (char *) theme_thumbnail_data->control_theme_name->data,
"gtk-font-name", (char *) theme_thumbnail_data->application_font->data,
"gtk-icon-theme-name", (char *) theme_thumbnail_data->icon_theme_name->data,
"gtk-color-scheme", (char *) theme_thumbnail_data->gtk_color_scheme->data,
NULL);
theme = meta_theme_load ((char *) theme_thumbnail_data->wm_theme_name->data, NULL);
flags = META_FRAME_ALLOWS_DELETE |
META_FRAME_ALLOWS_MENU |
META_FRAME_ALLOWS_MINIMIZE |
META_FRAME_ALLOWS_MAXIMIZE |
META_FRAME_ALLOWS_VERTICAL_RESIZE |
META_FRAME_ALLOWS_HORIZONTAL_RESIZE |
META_FRAME_HAS_FOCUS |
META_FRAME_ALLOWS_SHADE |
META_FRAME_ALLOWS_MOVE;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
preview = meta_preview_new ();
gtk_container_add (GTK_CONTAINER (window), preview);
gtk_widget_realize (window);
gtk_widget_realize (preview);
align = gtk_alignment_new (0.0, 0.0, 0.0, 0.0);
gtk_container_add (GTK_CONTAINER (preview), align);
gtk_container_set_border_width (GTK_CONTAINER (align), 5);
stock_button = gtk_button_new_from_stock (GTK_STOCK_OPEN);
gtk_container_add (GTK_CONTAINER (align), stock_button);
gtk_widget_show_all (preview);
gtk_widget_realize (align);
gtk_widget_realize (stock_button);
gtk_widget_realize (GTK_BIN (stock_button)->child);
gtk_widget_map (stock_button);
gtk_widget_map (GTK_BIN (stock_button)->child);
meta_preview_set_frame_flags (META_PREVIEW (preview), flags);
meta_preview_set_theme (META_PREVIEW (preview), theme);
meta_preview_set_title (META_PREVIEW (preview), "");
gtk_window_set_default_size (GTK_WINDOW (window), ICON_SIZE_WIDTH, ICON_SIZE_HEIGHT);
gtk_widget_size_request (window, &requisition);
allocation.x = 0;
allocation.y = 0;
allocation.width = ICON_SIZE_WIDTH;
allocation.height = ICON_SIZE_HEIGHT;
gtk_widget_size_allocate (window, &allocation);
gtk_widget_size_request (window, &requisition);
/* Create a pixmap */
visual = gtk_widget_get_visual (window);
pixmap = gdk_pixmap_new (NULL, ICON_SIZE_WIDTH, ICON_SIZE_HEIGHT, visual->depth);
gdk_drawable_set_colormap (GDK_DRAWABLE (pixmap), gtk_widget_get_colormap (window));
/* Draw the window */
gtk_widget_ensure_style (window);
g_assert (window->style);
g_assert (window->style->font_desc);
fake_expose_widget (window, pixmap, NULL);
fake_expose_widget (preview, pixmap, NULL);
/* we call this again here because the preview sometimes draws into the area
* of the contents, see http://bugzilla.gnome.org/show_bug.cgi?id=351389 */
fake_expose_widget (window, pixmap, &align->allocation);
fake_expose_widget (stock_button, pixmap, NULL);
gtk_container_foreach (GTK_CONTAINER (GTK_BIN (GTK_BIN (stock_button)->child)->child),
hbox_foreach,
pixmap);
fake_expose_widget (GTK_BIN (stock_button)->child, pixmap, NULL);
gdk_pixbuf_get_from_drawable (pixbuf, pixmap, NULL, 0, 0, 0, 0, ICON_SIZE_WIDTH, ICON_SIZE_HEIGHT);
/* Handle the icon theme */
icon_theme = gtk_icon_theme_new ();
gtk_icon_theme_set_custom_theme (icon_theme, (char *) theme_thumbnail_data->icon_theme_name->data);
folder_icon_info = NULL;
/* Get the Example icon name in the theme if specified */
example_icon_name = gtk_icon_theme_get_example_icon_name (icon_theme);
if (example_icon_name != NULL)
folder_icon_info = gtk_icon_theme_lookup_icon (icon_theme, example_icon_name, 48, GTK_ICON_LOOKUP_FORCE_SVG);
g_free (example_icon_name);
/* If an Example is not specified, fall back to using the folder icons in
the order of Icon Nameing Spec, "gnome-fs-directory", and "folder" */
if (folder_icon_info == NULL)
folder_icon_info = gtk_icon_theme_lookup_icon (icon_theme, "x-directory-normal", 48, GTK_ICON_LOOKUP_FORCE_SVG);
if (folder_icon_info == NULL)
folder_icon_info = gtk_icon_theme_lookup_icon (icon_theme, "gnome-fs-directory", 48, GTK_ICON_LOOKUP_FORCE_SVG);
if (folder_icon_info == NULL)
folder_icon_info = gtk_icon_theme_lookup_icon (icon_theme, "folder", 48, GTK_ICON_LOOKUP_FORCE_SVG);
g_object_unref (icon_theme);
if (folder_icon_info != NULL)
{
filename = gtk_icon_info_get_filename (folder_icon_info);
if (filename != NULL)
{
folder_icon = gdk_pixbuf_new_from_file (filename, NULL);
}
gtk_icon_info_free (folder_icon_info);
}
/* render the icon to the thumbnail */
if (folder_icon == NULL)
folder_icon = gtk_widget_render_icon (window,
GTK_STOCK_MISSING_IMAGE,
GTK_ICON_SIZE_DIALOG,
NULL);
/* Some icons don't come back at the requested dimensions, so we need to scale
* them. The width is usually the largest dimension for icons that come at
* irregular sizes, so use this to calculate the scale factor
*/
scale = 48.0 / gdk_pixbuf_get_width (folder_icon);
width = 48;
height = scale * gdk_pixbuf_get_height (folder_icon);
gdk_pixbuf_composite (folder_icon,
pixbuf,
align->allocation.x + align->allocation.width - width - 5,
align->allocation.y + align->allocation.height - height - 5,
width,
height,
align->allocation.x + align->allocation.width - width - 5,
align->allocation.y + align->allocation.height - height - 5,
scale,
scale,
GDK_INTERP_BILINEAR, 255);
g_object_unref (folder_icon);
gtk_widget_destroy (window);
}
static void
handle_bytes (const gchar *buffer,
gint bytes_read,
ThemeThumbnailData *theme_thumbnail_data)
{
const gchar *ptr;
ptr = buffer;
while (bytes_read > 0)
{
char *nil;
switch (theme_thumbnail_data->status)
{
case READY_FOR_THEME:
case READING_CONTROL_THEME_NAME:
theme_thumbnail_data->status = READING_CONTROL_THEME_NAME;
nil = memchr (ptr, '\000', bytes_read);
if (nil == NULL)
{
g_byte_array_append (theme_thumbnail_data->control_theme_name, ptr, bytes_read);
bytes_read = 0;
}
else
{
g_byte_array_append (theme_thumbnail_data->control_theme_name, ptr, nil - ptr + 1);
bytes_read -= (nil - ptr + 1);
ptr = nil + 1;
theme_thumbnail_data->status = READING_GTK_COLOR_SCHEME;
}
break;
case READING_GTK_COLOR_SCHEME:
nil = memchr (ptr, '\000', bytes_read);
if (nil == NULL)
{
g_byte_array_append (theme_thumbnail_data->gtk_color_scheme, ptr, bytes_read);
bytes_read = 0;
}
else
{
g_byte_array_append (theme_thumbnail_data->gtk_color_scheme, ptr, nil - ptr + 1);
bytes_read -= (nil - ptr + 1);
ptr = nil + 1;
theme_thumbnail_data->status = READING_WM_THEME_NAME;
}
break;
case READING_WM_THEME_NAME:
nil = memchr (ptr, '\000', bytes_read);
if (nil == NULL)
{
g_byte_array_append (theme_thumbnail_data->wm_theme_name, ptr, bytes_read);
bytes_read = 0;
}
else
{
g_byte_array_append (theme_thumbnail_data->wm_theme_name, ptr, nil - ptr + 1);
bytes_read -= (nil - ptr + 1);
ptr = nil + 1;
theme_thumbnail_data->status = READING_ICON_THEME_NAME;
}
break;
case READING_ICON_THEME_NAME:
nil = memchr (ptr, '\000', bytes_read);
if (nil == NULL)
{
g_byte_array_append (theme_thumbnail_data->icon_theme_name, ptr, bytes_read);
bytes_read = 0;
}
else
{
g_byte_array_append (theme_thumbnail_data->icon_theme_name, ptr, nil - ptr + 1);
bytes_read -= (nil - ptr + 1);
ptr = nil + 1;
theme_thumbnail_data->status = READING_APPLICATION_FONT;
}
break;
case READING_APPLICATION_FONT:
nil = memchr (ptr, '\000', bytes_read);
if (nil == NULL)
{
g_byte_array_append (theme_thumbnail_data->application_font, ptr, bytes_read);
bytes_read = 0;
}
else
{
g_byte_array_append (theme_thumbnail_data->application_font, ptr, nil - ptr + 1);
bytes_read -= (nil - ptr + 1);
ptr = nil + 1;
theme_thumbnail_data->status = WRITING_PIXBUF_DATA;
}
break;
default:
g_assert_not_reached ();
}
}
}
static gboolean
message_from_capplet (GIOChannel *source,
GIOCondition condition,
gpointer data)
{
gchar buffer[1024];
GIOStatus status;
gsize bytes_read;
GdkPixbuf *pixbuf;
gint i, rowstride;
char *pixels;
ThemeThumbnailData *theme_thumbnail_data;
theme_thumbnail_data = (ThemeThumbnailData *)data;
status = g_io_channel_read_chars (source,
buffer,
1024,
&bytes_read,
NULL);
switch (status)
{
case G_IO_STATUS_NORMAL:
handle_bytes (buffer, bytes_read, theme_thumbnail_data);
if (theme_thumbnail_data->status == WRITING_PIXBUF_DATA)
{
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, ICON_SIZE_WIDTH, ICON_SIZE_HEIGHT);
create_image (theme_thumbnail_data, pixbuf);
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
pixels = gdk_pixbuf_get_pixels (pixbuf);
for (i = 0; i < ICON_SIZE_HEIGHT; i ++)
{
write (pipe_from_factory_fd[1], pixels + (rowstride)*i, ICON_SIZE_WIDTH * gdk_pixbuf_get_n_channels (pixbuf));
}
g_object_unref (pixbuf);
theme_thumbnail_data->status = READY_FOR_THEME;
g_byte_array_set_size (theme_thumbnail_data->control_theme_name, 0);
g_byte_array_set_size (theme_thumbnail_data->gtk_color_scheme, 0);
g_byte_array_set_size (theme_thumbnail_data->wm_theme_name, 0);
g_byte_array_set_size (theme_thumbnail_data->icon_theme_name, 0);
g_byte_array_set_size (theme_thumbnail_data->application_font, 0);
}
return TRUE;
case G_IO_STATUS_AGAIN:
return TRUE;
case G_IO_STATUS_EOF:
case G_IO_STATUS_ERROR:
_exit (0);
default:
g_assert_not_reached ();
}
return TRUE;
}
static gboolean
message_from_child (GIOChannel *source,
GIOCondition condition,
gpointer data)
{
gchar buffer[1024];
GIOStatus status;
gsize bytes_read;
if (async_data.set == FALSE)
return TRUE;
status = g_io_channel_read_chars (source,
buffer,
1024,
&bytes_read,
NULL);
switch (status)
{
case G_IO_STATUS_NORMAL:
g_byte_array_append (async_data.data, buffer, bytes_read);
if (async_data.data->len == ICON_SIZE_WIDTH * ICON_SIZE_HEIGHT * 4)
{
GdkPixbuf *pixbuf;
GdkPixbuf *scaled_pixbuf;
gchar *pixels;
gint i, rowstride;
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, ICON_SIZE_WIDTH, ICON_SIZE_HEIGHT);
pixels = gdk_pixbuf_get_pixels (pixbuf);
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
for (i = 0; i < ICON_SIZE_HEIGHT; i++)
memcpy (pixels + rowstride * i, async_data.data->data + 4 * ICON_SIZE_WIDTH * i, ICON_SIZE_WIDTH * 4);
scaled_pixbuf = gdk_pixbuf_scale_simple (pixbuf, ICON_SIZE_WIDTH/2, ICON_SIZE_HEIGHT/2, GDK_INTERP_BILINEAR);
g_hash_table_insert (theme_hash, g_strdup(async_data.meta_theme_name), scaled_pixbuf);
g_object_unref (pixbuf);
(* async_data.func) (scaled_pixbuf, async_data.user_data);
if (async_data.destroy)
(* async_data.destroy) (async_data.user_data);
/* Clean up async_data */
g_free (async_data.meta_theme_name);
g_source_remove (async_data.watch_id);
g_io_channel_unref (async_data.channel);
/* reset async_data */
async_data.meta_theme_name = NULL;
async_data.channel = NULL;
async_data.func = NULL;
async_data.user_data = NULL;
async_data.destroy = NULL;
async_data.set = FALSE;
g_byte_array_set_size (async_data.data, 0);
}
return TRUE;
case G_IO_STATUS_AGAIN:
return TRUE;
case G_IO_STATUS_EOF:
case G_IO_STATUS_ERROR:
return TRUE;
default:
g_assert_not_reached ();
}
return TRUE;
}
void
theme_thumbnail_invalidate_cache (GnomeThemeMetaInfo *meta_theme_info)
{
gboolean success;
success = g_hash_table_remove (theme_hash, meta_theme_info->name);
printf ("Success is %d\n", success);
}
GdkPixbuf *
generate_theme_thumbnail (GnomeThemeMetaInfo *meta_theme_info,
gboolean clear_cache)
{
GdkPixbuf *retval = NULL;
GdkPixbuf *pixbuf = NULL;
gint i, rowstride;
char *pixels;
if (async_data.set == TRUE)
return NULL;
pixbuf = g_hash_table_lookup (theme_hash, meta_theme_info->name);
if (pixbuf != NULL)
{
if (clear_cache)
g_hash_table_remove (theme_hash, meta_theme_info->name);
else
return pixbuf;
}
if (!pipe_to_factory_fd[1] || !pipe_from_factory_fd[0])
return NULL;
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, ICON_SIZE_WIDTH, ICON_SIZE_HEIGHT);
write (pipe_to_factory_fd[1], meta_theme_info->gtk_theme_name, strlen (meta_theme_info->gtk_theme_name) + 1);
if (meta_theme_info->gtk_color_scheme)
write (pipe_to_factory_fd[1], meta_theme_info->gtk_color_scheme, strlen (meta_theme_info->gtk_color_scheme) + 1);
else
write (pipe_to_factory_fd[1], "", strlen ("") + 1);
write (pipe_to_factory_fd[1], meta_theme_info->metacity_theme_name, strlen (meta_theme_info->metacity_theme_name) + 1);
write (pipe_to_factory_fd[1], meta_theme_info->icon_theme_name, strlen (meta_theme_info->icon_theme_name) + 1);
if (meta_theme_info->application_font == NULL)
write (pipe_to_factory_fd[1], "Sans 10", strlen ("Sans 10") + 1);
else
write (pipe_to_factory_fd[1], meta_theme_info->application_font, strlen (meta_theme_info->application_font) + 1);
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
pixels = gdk_pixbuf_get_pixels (pixbuf);
for (i = 0; i < ICON_SIZE_HEIGHT; i++)
{
gint j = 0;
gint bytes_read;
do
{
bytes_read = read (pipe_from_factory_fd[0], pixels + (rowstride)*i + j, ICON_SIZE_WIDTH * gdk_pixbuf_get_n_channels (pixbuf) - j);
if (bytes_read > 0)
j += bytes_read;
else if (bytes_read == 0)
{
g_warning ("Received EOF while reading thumbnail for gtk: '%s', metacity '%s', icon: '%s', font: '%s'\n",
meta_theme_info->gtk_theme_name,
meta_theme_info->metacity_theme_name,
meta_theme_info->icon_theme_name,
meta_theme_info->application_font ? meta_theme_info->application_font : "Sans 10");
g_object_unref (pixbuf);
close (pipe_to_factory_fd[1]);
pipe_to_factory_fd[1] = 0;
close (pipe_from_factory_fd[0]);
pipe_from_factory_fd[0] = 0;
return NULL;
}
}
while (j < ICON_SIZE_WIDTH * gdk_pixbuf_get_n_channels (pixbuf));
}
retval = gdk_pixbuf_scale_simple (pixbuf, ICON_SIZE_WIDTH/2, ICON_SIZE_HEIGHT/2, GDK_INTERP_BILINEAR);
g_object_unref (pixbuf);
g_hash_table_insert (theme_hash, g_strdup (meta_theme_info->name), retval);
return retval;
}
void
generate_theme_thumbnail_async (GnomeThemeMetaInfo *meta_theme_info,
ThemeThumbnailFunc func,
gpointer user_data,
GDestroyNotify destroy)
{
GdkPixbuf *pixbuf;
g_return_if_fail (async_data.set == FALSE);
pixbuf = g_hash_table_lookup (theme_hash, meta_theme_info->name);
if (pixbuf != NULL)
{
(* func) (pixbuf, user_data);
if (destroy)
(* destroy) (user_data);
return;
}
if (!pipe_to_factory_fd[1] || !pipe_from_factory_fd[0])
{
(* func) (NULL, user_data);
if (destroy)
(* destroy) (user_data);
return;
}
if (async_data.channel == NULL)
{
async_data.channel = g_io_channel_unix_new (pipe_from_factory_fd[0]);
g_io_channel_set_flags (async_data.channel, g_io_channel_get_flags (async_data.channel) |
G_IO_FLAG_NONBLOCK, NULL);
g_io_channel_set_encoding (async_data.channel, NULL, NULL);
async_data.watch_id = g_io_add_watch (async_data.channel, G_IO_IN | G_IO_HUP, message_from_child, NULL);
}
async_data.set = TRUE;
async_data.meta_theme_name = g_strdup (meta_theme_info->name);
async_data.func = func;
async_data.user_data = user_data;
async_data.destroy = destroy;
write (pipe_to_factory_fd[1], meta_theme_info->gtk_theme_name, strlen (meta_theme_info->gtk_theme_name) + 1);
if (meta_theme_info->gtk_color_scheme)
write (pipe_to_factory_fd[1], meta_theme_info->gtk_color_scheme, strlen (meta_theme_info->gtk_color_scheme) + 1);
else
write (pipe_to_factory_fd[1], "", strlen ("") + 1);
write (pipe_to_factory_fd[1], meta_theme_info->metacity_theme_name, strlen (meta_theme_info->metacity_theme_name) + 1);
write (pipe_to_factory_fd[1], meta_theme_info->icon_theme_name, strlen (meta_theme_info->icon_theme_name) + 1);
if (meta_theme_info->application_font == NULL)
write (pipe_to_factory_fd[1], "Sans 10", strlen ("Sans 10") + 1);
else
write (pipe_to_factory_fd[1], meta_theme_info->application_font, strlen (meta_theme_info->application_font) + 1);
}
void
theme_thumbnail_factory_init (int argc, char *argv[])
{
pipe (pipe_to_factory_fd);
pipe (pipe_from_factory_fd);
child_pid = fork ();
if (child_pid == 0)
{
ThemeThumbnailData data;
GIOChannel *channel;
/* Child */
gtk_init (&argc, &argv);
close (pipe_to_factory_fd[1]);
pipe_to_factory_fd[1] = 0;
close (pipe_from_factory_fd[0]);
pipe_from_factory_fd[0] = 0;
data.status = READY_FOR_THEME;
data.control_theme_name = g_byte_array_new ();
data.gtk_color_scheme = g_byte_array_new ();
data.wm_theme_name = g_byte_array_new ();
data.icon_theme_name = g_byte_array_new ();
data.application_font = g_byte_array_new ();
channel = g_io_channel_unix_new (pipe_to_factory_fd[0]);
g_io_channel_set_flags (channel, g_io_channel_get_flags (channel) |
G_IO_FLAG_NONBLOCK, NULL);
g_io_channel_set_encoding (channel, NULL, NULL);
g_io_add_watch (channel, G_IO_IN | G_IO_HUP, message_from_capplet, &data);
g_io_channel_unref (channel);
gtk_main ();
_exit (0);
}
g_assert (child_pid > 0);
/* Parent */
close (pipe_to_factory_fd[0]);
close (pipe_from_factory_fd[1]);
async_data.set = FALSE;
async_data.meta_theme_name = NULL;
async_data.data = g_byte_array_new ();
theme_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
}