theme-thumbnail-engine.c: In function 'message_from_capplet': theme-thumbnail-engine.c:642: warning: 'pixels' may be used uninitialized in this function theme-thumbnail-engine.c:641: warning: 'rowstride' may be used uninitialized in this function These are actually false positives but no warnings is good (bug #590990).
1215 lines
39 KiB
C
1215 lines
39 KiB
C
#include <config.h>
|
|
#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>
|
|
#include <math.h>
|
|
|
|
/* We have to #undef this as metacity #defines these. */
|
|
#undef _
|
|
#undef N_
|
|
|
|
#include <glib.h>
|
|
|
|
#include "theme-thumbnail.h"
|
|
#include "gtkrc-utils.h"
|
|
#include "capplet-util.h"
|
|
|
|
typedef struct
|
|
{
|
|
gboolean set;
|
|
gint thumbnail_width;
|
|
gint thumbnail_height;
|
|
GByteArray *data;
|
|
gchar *theme_name;
|
|
ThemeThumbnailFunc func;
|
|
gpointer user_data;
|
|
GDestroyNotify destroy;
|
|
GIOChannel *channel;
|
|
guint watch_id;
|
|
} ThemeThumbnailAsyncData;
|
|
|
|
|
|
static ThemeThumbnailAsyncData async_data;
|
|
|
|
/* Protocol */
|
|
|
|
/* Our protocol is pretty simple. The parent process will write several strings
|
|
* (separated by a '\000'). They are the widget theme, the wm theme, the icon
|
|
* theme, etc. 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_TYPE,
|
|
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 *type;
|
|
GByteArray *control_theme_name;
|
|
GByteArray *gtk_color_scheme;
|
|
GByteArray *wm_theme_name;
|
|
GByteArray *icon_theme_name;
|
|
GByteArray *application_font;
|
|
} ThemeThumbnailData;
|
|
|
|
typedef struct
|
|
{
|
|
gchar *thumbnail_type;
|
|
gpointer theme_info;
|
|
ThemeThumbnailFunc func;
|
|
gpointer user_data;
|
|
GDestroyNotify destroy;
|
|
} ThemeQueueItem;
|
|
|
|
static GList *theme_queue = NULL;
|
|
|
|
static int pipe_to_factory_fd[2];
|
|
static int pipe_from_factory_fd[2];
|
|
|
|
#define THUMBNAIL_TYPE_META "meta"
|
|
#define THUMBNAIL_TYPE_GTK "gtk"
|
|
#define THUMBNAIL_TYPE_METACITY "metacity"
|
|
#define THUMBNAIL_TYPE_ICON "icon"
|
|
|
|
#define META_THUMBNAIL_SIZE 128
|
|
#define GTK_THUMBNAIL_SIZE 96
|
|
#define METACITY_THUMBNAIL_WIDTH 120
|
|
#define METACITY_THUMBNAIL_HEIGHT 60
|
|
|
|
|
|
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)
|
|
{
|
|
if (GTK_WIDGET_VISIBLE (widget)) {
|
|
gtk_widget_realize (widget);
|
|
gtk_widget_map (widget);
|
|
gtk_widget_ensure_style (widget);
|
|
fake_expose_widget (widget, (GdkPixmap *) data, NULL);
|
|
}
|
|
}
|
|
|
|
static void
|
|
pixbuf_apply_mask_region (GdkPixbuf *pixbuf, GdkRegion *region)
|
|
{
|
|
gint nchannels, rowstride, w, h;
|
|
guchar *pixels, *p;
|
|
|
|
g_return_if_fail (pixbuf);
|
|
g_return_if_fail (region);
|
|
|
|
nchannels = gdk_pixbuf_get_n_channels (pixbuf);
|
|
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
|
|
pixels = gdk_pixbuf_get_pixels (pixbuf);
|
|
|
|
|
|
/* we need an alpha channel ... */
|
|
if (!gdk_pixbuf_get_has_alpha (pixbuf) || nchannels != 4)
|
|
return;
|
|
|
|
for (w = 0; w < gdk_pixbuf_get_width (pixbuf); ++w)
|
|
for (h = 0; h < gdk_pixbuf_get_height (pixbuf); ++h)
|
|
{
|
|
if (!gdk_region_point_in (region, w, h))
|
|
{
|
|
p = pixels + h * rowstride + w * nchannels;
|
|
if (G_BYTE_ORDER == G_BIG_ENDIAN)
|
|
p[0] = 0x0;
|
|
else
|
|
p[3] = 0x0;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
static GdkPixbuf *
|
|
create_folder_icon (char *icon_theme_name)
|
|
{
|
|
GtkIconTheme *icon_theme;
|
|
GdkPixbuf *folder_icon = NULL;
|
|
GtkIconInfo *folder_icon_info;
|
|
gchar *example_icon_name;
|
|
const gchar *icon_names[5];
|
|
gint i;
|
|
|
|
icon_theme = gtk_icon_theme_new ();
|
|
gtk_icon_theme_set_custom_theme (icon_theme, icon_theme_name);
|
|
|
|
i = 0;
|
|
/* 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)
|
|
icon_names[i++] = example_icon_name;
|
|
icon_names[i++] = "x-directory-normal";
|
|
icon_names[i++] = "gnome-fs-directory";
|
|
icon_names[i++] = "folder";
|
|
icon_names[i++] = NULL;
|
|
|
|
folder_icon_info = gtk_icon_theme_choose_icon (icon_theme, icon_names, 48, GTK_ICON_LOOKUP_FORCE_SIZE);
|
|
if (folder_icon_info != NULL)
|
|
{
|
|
folder_icon = gtk_icon_info_load_icon (folder_icon_info, NULL);
|
|
gtk_icon_info_free (folder_icon_info);
|
|
}
|
|
|
|
g_object_unref (icon_theme);
|
|
g_free (example_icon_name);
|
|
|
|
/* render the icon to the thumbnail */
|
|
if (folder_icon == NULL)
|
|
{
|
|
GtkWidget *dummy;
|
|
dummy = gtk_label_new ("");
|
|
|
|
folder_icon = gtk_widget_render_icon (dummy,
|
|
GTK_STOCK_MISSING_IMAGE,
|
|
GTK_ICON_SIZE_DIALOG,
|
|
NULL);
|
|
|
|
gtk_widget_destroy (dummy);
|
|
}
|
|
|
|
return folder_icon;
|
|
}
|
|
|
|
static GdkPixbuf *
|
|
create_meta_theme_pixbuf (ThemeThumbnailData *theme_thumbnail_data)
|
|
{
|
|
GtkWidget *window;
|
|
GtkWidget *preview;
|
|
GtkWidget *vbox;
|
|
GtkWidget *align;
|
|
GtkWidget *box;
|
|
GtkWidget *stock_button;
|
|
GtkWidget *checkbox;
|
|
GtkWidget *radio;
|
|
|
|
GtkRequisition requisition;
|
|
GtkAllocation allocation;
|
|
GdkPixmap *pixmap;
|
|
GdkVisual *visual;
|
|
MetaFrameFlags flags;
|
|
MetaTheme *theme;
|
|
GdkPixbuf *pixbuf, *icon;
|
|
int icon_width, icon_height;
|
|
GdkRegion *region;
|
|
|
|
g_object_set (gtk_settings_get_default (),
|
|
"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);
|
|
if (theme == NULL)
|
|
return NULL;
|
|
|
|
/* Represent the icon theme */
|
|
icon = create_folder_icon ((char *) theme_thumbnail_data->icon_theme_name->data);
|
|
icon_width = gdk_pixbuf_get_width (icon);
|
|
icon_height = gdk_pixbuf_get_height (icon);
|
|
|
|
/* Create a fake window */
|
|
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);
|
|
vbox = gtk_vbox_new (FALSE, 6);
|
|
gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
|
|
gtk_container_add (GTK_CONTAINER (preview), vbox);
|
|
align = gtk_alignment_new (0, 0, 0.0, 0.0);
|
|
gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 0);
|
|
stock_button = gtk_button_new_from_stock (GTK_STOCK_OPEN);
|
|
gtk_container_add (GTK_CONTAINER (align), stock_button);
|
|
box = gtk_hbox_new (FALSE, 0);
|
|
gtk_box_pack_start (GTK_BOX (vbox), box, FALSE, FALSE, 0);
|
|
checkbox = gtk_check_button_new ();
|
|
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbox), TRUE);
|
|
gtk_box_pack_start (GTK_BOX (box), checkbox, FALSE, FALSE, 0);
|
|
radio = gtk_radio_button_new (NULL);
|
|
gtk_box_pack_start (GTK_BOX (box), radio, FALSE, FALSE, 0);
|
|
|
|
gtk_widget_show_all (preview);
|
|
gtk_widget_realize (stock_button);
|
|
gtk_widget_realize (GTK_BIN (stock_button)->child);
|
|
gtk_widget_realize (checkbox);
|
|
gtk_widget_realize (radio);
|
|
gtk_widget_map (stock_button);
|
|
gtk_widget_map (GTK_BIN (stock_button)->child);
|
|
gtk_widget_map (checkbox);
|
|
gtk_widget_map (radio);
|
|
|
|
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), META_THUMBNAIL_SIZE, META_THUMBNAIL_SIZE);
|
|
|
|
gtk_widget_size_request (window, &requisition);
|
|
allocation.x = 0;
|
|
allocation.y = 0;
|
|
allocation.width = META_THUMBNAIL_SIZE;
|
|
allocation.height = META_THUMBNAIL_SIZE;
|
|
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, META_THUMBNAIL_SIZE, META_THUMBNAIL_SIZE, 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, &vbox->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);
|
|
fake_expose_widget (checkbox, pixmap, NULL);
|
|
fake_expose_widget (radio, pixmap, NULL);
|
|
|
|
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, META_THUMBNAIL_SIZE, META_THUMBNAIL_SIZE);
|
|
gdk_pixbuf_get_from_drawable (pixbuf, pixmap, NULL, 0, 0, 0, 0, META_THUMBNAIL_SIZE, META_THUMBNAIL_SIZE);
|
|
|
|
/* Add the icon theme to the pixbuf */
|
|
gdk_pixbuf_composite (icon, pixbuf,
|
|
vbox->allocation.x + vbox->allocation.width - icon_width - 5,
|
|
vbox->allocation.y + vbox->allocation.height - icon_height - 5,
|
|
icon_width, icon_height,
|
|
vbox->allocation.x + vbox->allocation.width - icon_width - 5,
|
|
vbox->allocation.y + vbox->allocation.height - icon_height - 5,
|
|
1.0, 1.0, GDK_INTERP_BILINEAR, 255);
|
|
region = meta_preview_get_clip_region (META_PREVIEW (preview),
|
|
META_THUMBNAIL_SIZE, META_THUMBNAIL_SIZE);
|
|
pixbuf_apply_mask_region (pixbuf, region);
|
|
gdk_region_destroy (region);
|
|
|
|
g_object_unref (icon);
|
|
gtk_widget_destroy (window);
|
|
meta_theme_free (theme);
|
|
|
|
return pixbuf;
|
|
}
|
|
|
|
static GdkPixbuf *
|
|
create_gtk_theme_pixbuf (ThemeThumbnailData *theme_thumbnail_data)
|
|
{
|
|
GtkSettings *settings;
|
|
GtkWidget *window, *vbox, *box, *stock_button, *checkbox, *radio;
|
|
GtkRequisition requisition;
|
|
GtkAllocation allocation;
|
|
GdkVisual *visual;
|
|
GdkPixmap *pixmap;
|
|
GdkPixbuf *pixbuf, *retval;
|
|
gint width, height;
|
|
|
|
settings = gtk_settings_get_default ();
|
|
g_object_set (settings, "gtk-theme-name", (char *) theme_thumbnail_data->control_theme_name->data,
|
|
"gtk-color-scheme", (char *) theme_thumbnail_data->gtk_color_scheme->data,
|
|
NULL);
|
|
|
|
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
|
|
vbox = gtk_vbox_new (FALSE, 0);
|
|
gtk_container_add (GTK_CONTAINER (window), vbox);
|
|
box = gtk_hbox_new (FALSE, 6);
|
|
gtk_container_set_border_width (GTK_CONTAINER (box), 6);
|
|
gtk_box_pack_start (GTK_BOX (vbox), box, FALSE, FALSE, 0);
|
|
stock_button = gtk_button_new_from_stock (GTK_STOCK_OPEN);
|
|
gtk_box_pack_start (GTK_BOX (box), stock_button, FALSE, FALSE, 0);
|
|
checkbox = gtk_check_button_new ();
|
|
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbox), TRUE);
|
|
gtk_box_pack_start (GTK_BOX (box), checkbox, FALSE, FALSE, 0);
|
|
radio = gtk_radio_button_new_from_widget (NULL);
|
|
gtk_box_pack_start (GTK_BOX (box), radio, FALSE, FALSE, 0);
|
|
|
|
gtk_widget_show_all (vbox);
|
|
gtk_widget_realize (stock_button);
|
|
gtk_widget_realize (GTK_BIN (stock_button)->child);
|
|
gtk_widget_realize (checkbox);
|
|
gtk_widget_realize (radio);
|
|
gtk_widget_map (stock_button);
|
|
gtk_widget_map (GTK_BIN (stock_button)->child);
|
|
gtk_widget_map (checkbox);
|
|
gtk_widget_map (radio);
|
|
|
|
gtk_widget_size_request (window, &requisition);
|
|
allocation.x = 0;
|
|
allocation.y = 0;
|
|
allocation.width = requisition.width;
|
|
allocation.height = requisition.height;
|
|
gtk_widget_size_allocate (window, &allocation);
|
|
gtk_widget_size_request (window, &requisition);
|
|
|
|
/* Draw the window */
|
|
gtk_widget_ensure_style (window);
|
|
g_assert (window->style);
|
|
g_assert (window->style->font_desc);
|
|
|
|
gtk_window_get_size (GTK_WINDOW (window), &width, &height);
|
|
|
|
visual = gtk_widget_get_visual (window);
|
|
pixmap = gdk_pixmap_new (NULL, width, height, visual->depth);
|
|
gdk_drawable_set_colormap (GDK_DRAWABLE (pixmap), gtk_widget_get_colormap (window));
|
|
|
|
fake_expose_widget (window, pixmap, NULL);
|
|
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);
|
|
fake_expose_widget (checkbox, pixmap, NULL);
|
|
fake_expose_widget (radio, pixmap, NULL);
|
|
|
|
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, width, height);
|
|
gdk_pixbuf_get_from_drawable (pixbuf, pixmap, NULL, 0, 0, 0, 0, width, height);
|
|
|
|
retval = gdk_pixbuf_scale_simple (pixbuf,
|
|
GTK_THUMBNAIL_SIZE,
|
|
(int) GTK_THUMBNAIL_SIZE * (((double) height) / ((double) width)),
|
|
GDK_INTERP_BILINEAR);
|
|
g_object_unref (pixbuf);
|
|
gtk_widget_destroy (window);
|
|
|
|
return retval;
|
|
}
|
|
|
|
static GdkPixbuf *
|
|
create_metacity_theme_pixbuf (ThemeThumbnailData *theme_thumbnail_data)
|
|
{
|
|
GtkWidget *window, *preview, *dummy;
|
|
MetaFrameFlags flags;
|
|
MetaTheme *theme;
|
|
GtkRequisition requisition;
|
|
GtkAllocation allocation;
|
|
GdkVisual *visual;
|
|
GdkPixmap *pixmap;
|
|
GdkPixbuf *pixbuf, *retval;
|
|
GdkRegion *region;
|
|
|
|
theme = meta_theme_load ((char *) theme_thumbnail_data->wm_theme_name->data, NULL);
|
|
if (theme == NULL)
|
|
return 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);
|
|
gtk_window_set_default_size (GTK_WINDOW (window), (int) METACITY_THUMBNAIL_WIDTH * 1.2, (int) METACITY_THUMBNAIL_HEIGHT * 1.2);
|
|
|
|
preview = meta_preview_new ();
|
|
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_container_add (GTK_CONTAINER (window), preview);
|
|
|
|
dummy = gtk_label_new ("");
|
|
gtk_container_add (GTK_CONTAINER (preview), dummy);
|
|
|
|
gtk_widget_realize (window);
|
|
gtk_widget_realize (preview);
|
|
gtk_widget_realize (dummy);
|
|
gtk_widget_show_all (preview);
|
|
gtk_widget_map (dummy);
|
|
|
|
gtk_widget_size_request (window, &requisition);
|
|
allocation.x = 0;
|
|
allocation.y = 0;
|
|
allocation.width = (int) METACITY_THUMBNAIL_WIDTH * 1.2;
|
|
allocation.height = (int) METACITY_THUMBNAIL_HEIGHT * 1.2;
|
|
gtk_widget_size_allocate (window, &allocation);
|
|
gtk_widget_size_request (window, &requisition);
|
|
|
|
/* Draw the window */
|
|
gtk_widget_ensure_style (window);
|
|
g_assert (window->style);
|
|
g_assert (window->style->font_desc);
|
|
|
|
/* Create a pixmap */
|
|
visual = gtk_widget_get_visual (window);
|
|
pixmap = gdk_pixmap_new (NULL, (int) METACITY_THUMBNAIL_WIDTH * 1.2, (int) METACITY_THUMBNAIL_HEIGHT * 1.2, visual->depth);
|
|
gdk_drawable_set_colormap (GDK_DRAWABLE (pixmap), gtk_widget_get_colormap (window));
|
|
|
|
fake_expose_widget (window, pixmap, NULL);
|
|
fake_expose_widget (preview, pixmap, NULL);
|
|
fake_expose_widget (window, pixmap, &dummy->allocation);
|
|
|
|
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, (int) METACITY_THUMBNAIL_WIDTH * 1.2, (int) METACITY_THUMBNAIL_HEIGHT * 1.2);
|
|
gdk_pixbuf_get_from_drawable (pixbuf, pixmap, NULL, 0, 0, 0, 0, (int) METACITY_THUMBNAIL_WIDTH * 1.2, (int) METACITY_THUMBNAIL_HEIGHT * 1.2);
|
|
|
|
region = meta_preview_get_clip_region (META_PREVIEW (preview),
|
|
METACITY_THUMBNAIL_WIDTH * 1.2, METACITY_THUMBNAIL_HEIGHT * 1.2);
|
|
pixbuf_apply_mask_region (pixbuf, region);
|
|
gdk_region_destroy (region);
|
|
|
|
|
|
retval = gdk_pixbuf_scale_simple (pixbuf,
|
|
METACITY_THUMBNAIL_WIDTH,
|
|
METACITY_THUMBNAIL_HEIGHT,
|
|
GDK_INTERP_BILINEAR);
|
|
g_object_unref (pixbuf);
|
|
|
|
gtk_widget_destroy (window);
|
|
meta_theme_free (theme);
|
|
return retval;
|
|
}
|
|
|
|
static GdkPixbuf *
|
|
create_icon_theme_pixbuf (ThemeThumbnailData *theme_thumbnail_data)
|
|
{
|
|
return create_folder_icon ((char *) theme_thumbnail_data->icon_theme_name->data);
|
|
}
|
|
|
|
|
|
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:
|
|
theme_thumbnail_data->status = READING_TYPE;
|
|
/* fall through */
|
|
case READING_TYPE:
|
|
nil = memchr (ptr, '\000', bytes_read);
|
|
if (nil == NULL)
|
|
{
|
|
g_byte_array_append (theme_thumbnail_data->type, ptr, bytes_read);
|
|
bytes_read = 0;
|
|
}
|
|
else
|
|
{
|
|
g_byte_array_append (theme_thumbnail_data->type, ptr, nil - ptr + 1);
|
|
bytes_read -= (nil - ptr + 1);
|
|
ptr = nil + 1;
|
|
theme_thumbnail_data->status = READING_CONTROL_THEME_NAME;
|
|
}
|
|
break;
|
|
|
|
case 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;
|
|
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)
|
|
{
|
|
GdkPixbuf *pixbuf = NULL;
|
|
gint i, rowstride;
|
|
guchar *pixels;
|
|
gint width, height;
|
|
const gchar *type = (const gchar *) theme_thumbnail_data->type->data;
|
|
|
|
if (!strcmp (type, THUMBNAIL_TYPE_META))
|
|
pixbuf = create_meta_theme_pixbuf (theme_thumbnail_data);
|
|
else if (!strcmp (type, THUMBNAIL_TYPE_GTK))
|
|
pixbuf = create_gtk_theme_pixbuf (theme_thumbnail_data);
|
|
else if (!strcmp (type, THUMBNAIL_TYPE_METACITY))
|
|
pixbuf = create_metacity_theme_pixbuf (theme_thumbnail_data);
|
|
else if (!strcmp (type, THUMBNAIL_TYPE_ICON))
|
|
pixbuf = create_icon_theme_pixbuf (theme_thumbnail_data);
|
|
else
|
|
g_assert_not_reached ();
|
|
|
|
if (pixbuf == NULL) {
|
|
width = height = rowstride = 0;
|
|
pixels = NULL;
|
|
} else {
|
|
width = gdk_pixbuf_get_width (pixbuf);
|
|
height = gdk_pixbuf_get_height (pixbuf);
|
|
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
|
|
pixels = gdk_pixbuf_get_pixels (pixbuf);
|
|
}
|
|
|
|
/* Write the pixbuf's size */
|
|
write (pipe_from_factory_fd[1], &width, sizeof (width));
|
|
write (pipe_from_factory_fd[1], &height, sizeof (height));
|
|
|
|
for (i = 0; i < height; i++)
|
|
{
|
|
write (pipe_from_factory_fd[1], pixels + rowstride * i, width * gdk_pixbuf_get_n_channels (pixbuf));
|
|
}
|
|
|
|
if (pixbuf)
|
|
g_object_unref (pixbuf);
|
|
g_byte_array_set_size (theme_thumbnail_data->type, 0);
|
|
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);
|
|
theme_thumbnail_data->status = READY_FOR_THEME;
|
|
}
|
|
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 void
|
|
generate_next_in_queue (void)
|
|
{
|
|
ThemeQueueItem *item;
|
|
|
|
if (theme_queue == NULL)
|
|
return;
|
|
|
|
item = theme_queue->data;
|
|
theme_queue = g_list_delete_link (theme_queue, g_list_first (theme_queue));
|
|
|
|
if (!strcmp (item->thumbnail_type, THUMBNAIL_TYPE_META))
|
|
generate_meta_theme_thumbnail_async ((GnomeThemeMetaInfo *) item->theme_info,
|
|
item->func,
|
|
item->user_data,
|
|
item->destroy);
|
|
else if (!strcmp (item->thumbnail_type, THUMBNAIL_TYPE_GTK))
|
|
generate_gtk_theme_thumbnail_async ((GnomeThemeInfo *) item->theme_info,
|
|
item->func,
|
|
item->user_data,
|
|
item->destroy);
|
|
else if (!strcmp (item->thumbnail_type, THUMBNAIL_TYPE_METACITY))
|
|
generate_metacity_theme_thumbnail_async ((GnomeThemeInfo *) item->theme_info,
|
|
item->func,
|
|
item->user_data,
|
|
item->destroy);
|
|
else if (!strcmp (item->thumbnail_type, THUMBNAIL_TYPE_ICON))
|
|
generate_icon_theme_thumbnail_async ((GnomeThemeIconInfo *) item->theme_info,
|
|
item->func,
|
|
item->user_data,
|
|
item->destroy);
|
|
|
|
g_free (item);
|
|
}
|
|
|
|
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;
|
|
|
|
if (condition == G_IO_HUP)
|
|
return FALSE;
|
|
|
|
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, (guchar *) buffer, bytes_read);
|
|
|
|
if (async_data.thumbnail_width == -1 && async_data.data->len >= 2 * sizeof (gint))
|
|
{
|
|
async_data.thumbnail_width = *((gint *) async_data.data->data);
|
|
async_data.thumbnail_height = *(((gint *) async_data.data->data) + 1);
|
|
g_byte_array_remove_range (async_data.data, 0, 2 * sizeof (gint));
|
|
}
|
|
|
|
if (async_data.thumbnail_width >= 0 && async_data.data->len == async_data.thumbnail_width * async_data.thumbnail_height * 4)
|
|
{
|
|
GdkPixbuf *pixbuf = NULL;
|
|
|
|
if (async_data.thumbnail_width > 0) {
|
|
gchar *pixels;
|
|
gint i, rowstride;
|
|
|
|
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, async_data.thumbnail_width, async_data.thumbnail_height);
|
|
pixels = (gchar *) gdk_pixbuf_get_pixels (pixbuf);
|
|
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
|
|
|
|
for (i = 0; i < async_data.thumbnail_height; ++i)
|
|
memcpy (pixels + rowstride * i, async_data.data->data + 4 * async_data.thumbnail_width * i, async_data.thumbnail_width * 4);
|
|
}
|
|
|
|
/* callback function needs to ref the pixbuf if it wants to keep it */
|
|
(* async_data.func) (pixbuf, async_data.theme_name, async_data.user_data);
|
|
|
|
if (async_data.destroy)
|
|
(* async_data.destroy) (async_data.user_data);
|
|
|
|
if (pixbuf)
|
|
g_object_unref (pixbuf);
|
|
|
|
/* Clean up async_data */
|
|
g_free (async_data.theme_name);
|
|
g_source_remove (async_data.watch_id);
|
|
g_io_channel_unref (async_data.channel);
|
|
|
|
/* reset async_data */
|
|
async_data.thumbnail_width = -1;
|
|
async_data.thumbnail_height = -1;
|
|
async_data.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);
|
|
|
|
generate_next_in_queue ();
|
|
}
|
|
return TRUE;
|
|
|
|
case G_IO_STATUS_AGAIN:
|
|
return TRUE;
|
|
|
|
case G_IO_STATUS_EOF:
|
|
case G_IO_STATUS_ERROR:
|
|
return FALSE;
|
|
|
|
default:
|
|
g_assert_not_reached ();
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
send_thumbnail_request (gchar *thumbnail_type,
|
|
gchar *gtk_theme_name,
|
|
gchar *gtk_color_scheme,
|
|
gchar *metacity_theme_name,
|
|
gchar *icon_theme_name,
|
|
gchar *application_font)
|
|
{
|
|
write (pipe_to_factory_fd[1], thumbnail_type, strlen (thumbnail_type) + 1);
|
|
|
|
if (gtk_theme_name)
|
|
write (pipe_to_factory_fd[1], gtk_theme_name, strlen (gtk_theme_name) + 1);
|
|
else
|
|
write (pipe_to_factory_fd[1], "", 1);
|
|
|
|
if (gtk_color_scheme)
|
|
write (pipe_to_factory_fd[1], gtk_color_scheme, strlen (gtk_color_scheme) + 1);
|
|
else
|
|
write (pipe_to_factory_fd[1], "", 1);
|
|
|
|
if (metacity_theme_name)
|
|
write (pipe_to_factory_fd[1], metacity_theme_name, strlen (metacity_theme_name) + 1);
|
|
else
|
|
write (pipe_to_factory_fd[1], "", 1);
|
|
|
|
if (icon_theme_name)
|
|
write (pipe_to_factory_fd[1], icon_theme_name, strlen (icon_theme_name) + 1);
|
|
else
|
|
write (pipe_to_factory_fd[1], "", 1);
|
|
|
|
if (application_font)
|
|
write (pipe_to_factory_fd[1], application_font, strlen (application_font) + 1);
|
|
else
|
|
write (pipe_to_factory_fd[1], "Sans 10", strlen ("Sans 10") + 1);
|
|
|
|
}
|
|
|
|
static GdkPixbuf *
|
|
read_pixbuf (void)
|
|
{
|
|
gint bytes_read, i, j = 0;
|
|
gint size[2];
|
|
GdkPixbuf *pixbuf;
|
|
gint rowstride;
|
|
guchar *pixels;
|
|
|
|
do
|
|
{
|
|
bytes_read = read (pipe_from_factory_fd[0], ((guint8*) size) + j, 2 * sizeof (gint));
|
|
if (bytes_read == 0)
|
|
goto eof;
|
|
j += bytes_read;
|
|
}
|
|
while (j < 2 * sizeof (gint));
|
|
|
|
if (size[0] <= 0 || size[1] <= 0)
|
|
return NULL;
|
|
|
|
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, size[0], size[1]);
|
|
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
|
|
pixels = gdk_pixbuf_get_pixels (pixbuf);
|
|
|
|
for (i = 0; i < size[1]; i++)
|
|
{
|
|
j = 0;
|
|
|
|
do
|
|
{
|
|
bytes_read = read (pipe_from_factory_fd[0], pixels + rowstride * i + j, size[0] * gdk_pixbuf_get_n_channels (pixbuf) - j);
|
|
|
|
if (bytes_read > 0)
|
|
j += bytes_read;
|
|
else if (bytes_read == 0)
|
|
{
|
|
g_object_unref (pixbuf);
|
|
goto eof;
|
|
}
|
|
}
|
|
while (j < size[0] * gdk_pixbuf_get_n_channels (pixbuf));
|
|
}
|
|
|
|
return pixbuf;
|
|
|
|
eof:
|
|
g_warning ("Received EOF while reading thumbnail");
|
|
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;
|
|
}
|
|
|
|
static GdkPixbuf *
|
|
generate_theme_thumbnail (gchar *thumbnail_type,
|
|
gchar *gtk_theme_name,
|
|
gchar *gtk_color_scheme,
|
|
gchar *metacity_theme_name,
|
|
gchar *icon_theme_name,
|
|
gchar *application_font)
|
|
{
|
|
if (async_data.set || !pipe_to_factory_fd[1] || !pipe_from_factory_fd[0])
|
|
return NULL;
|
|
|
|
send_thumbnail_request (thumbnail_type,
|
|
gtk_theme_name,
|
|
gtk_color_scheme,
|
|
metacity_theme_name,
|
|
icon_theme_name,
|
|
application_font);
|
|
|
|
return read_pixbuf ();
|
|
}
|
|
|
|
GdkPixbuf *
|
|
generate_meta_theme_thumbnail (GnomeThemeMetaInfo *theme_info)
|
|
{
|
|
return generate_theme_thumbnail (THUMBNAIL_TYPE_META,
|
|
theme_info->gtk_theme_name,
|
|
theme_info->gtk_color_scheme,
|
|
theme_info->metacity_theme_name,
|
|
theme_info->icon_theme_name,
|
|
theme_info->application_font);
|
|
}
|
|
|
|
GdkPixbuf *
|
|
generate_gtk_theme_thumbnail (GnomeThemeInfo *theme_info)
|
|
{
|
|
gchar *scheme;
|
|
|
|
scheme = gtkrc_get_color_scheme_for_theme (theme_info->name);
|
|
|
|
return generate_theme_thumbnail (THUMBNAIL_TYPE_GTK,
|
|
theme_info->name,
|
|
scheme,
|
|
NULL,
|
|
NULL,
|
|
NULL);
|
|
g_free (scheme);
|
|
}
|
|
|
|
GdkPixbuf *
|
|
generate_metacity_theme_thumbnail (GnomeThemeInfo *theme_info)
|
|
{
|
|
return generate_theme_thumbnail (THUMBNAIL_TYPE_METACITY,
|
|
NULL,
|
|
NULL,
|
|
theme_info->name,
|
|
NULL,
|
|
NULL);
|
|
}
|
|
|
|
GdkPixbuf *
|
|
generate_icon_theme_thumbnail (GnomeThemeIconInfo *theme_info)
|
|
{
|
|
return generate_theme_thumbnail (THUMBNAIL_TYPE_ICON,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
theme_info->name,
|
|
NULL);
|
|
}
|
|
|
|
static void
|
|
generate_theme_thumbnail_async (gpointer theme_info,
|
|
gchar *theme_name,
|
|
gchar *thumbnail_type,
|
|
gchar *gtk_theme_name,
|
|
gchar *gtk_color_scheme,
|
|
gchar *metacity_theme_name,
|
|
gchar *icon_theme_name,
|
|
gchar *application_font,
|
|
ThemeThumbnailFunc func,
|
|
gpointer user_data,
|
|
GDestroyNotify destroy)
|
|
{
|
|
if (async_data.set)
|
|
{
|
|
ThemeQueueItem *item;
|
|
|
|
item = g_new0 (ThemeQueueItem, 1);
|
|
item->thumbnail_type = thumbnail_type;
|
|
item->theme_info = theme_info;
|
|
item->func = func;
|
|
item->user_data = user_data;
|
|
item->destroy = destroy;
|
|
|
|
theme_queue = g_list_append (theme_queue, item);
|
|
return;
|
|
}
|
|
|
|
if (!pipe_to_factory_fd[1] || !pipe_from_factory_fd[0])
|
|
{
|
|
(* func) (NULL, theme_name, 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.thumbnail_width = -1;
|
|
async_data.thumbnail_height = -1;
|
|
async_data.theme_name = g_strdup (theme_name);
|
|
async_data.func = func;
|
|
async_data.user_data = user_data;
|
|
async_data.destroy = destroy;
|
|
|
|
send_thumbnail_request (thumbnail_type,
|
|
gtk_theme_name,
|
|
gtk_color_scheme,
|
|
metacity_theme_name,
|
|
icon_theme_name,
|
|
application_font);
|
|
}
|
|
|
|
void
|
|
generate_meta_theme_thumbnail_async (GnomeThemeMetaInfo *theme_info,
|
|
ThemeThumbnailFunc func,
|
|
gpointer user_data,
|
|
GDestroyNotify destroy)
|
|
{
|
|
generate_theme_thumbnail_async (theme_info,
|
|
theme_info->name,
|
|
THUMBNAIL_TYPE_META,
|
|
theme_info->gtk_theme_name,
|
|
theme_info->gtk_color_scheme,
|
|
theme_info->metacity_theme_name,
|
|
theme_info->icon_theme_name,
|
|
theme_info->application_font,
|
|
func, user_data, destroy);
|
|
}
|
|
|
|
void
|
|
generate_gtk_theme_thumbnail_async (GnomeThemeInfo *theme_info,
|
|
ThemeThumbnailFunc func,
|
|
gpointer user_data,
|
|
GDestroyNotify destroy)
|
|
{
|
|
gchar *scheme;
|
|
|
|
scheme = gtkrc_get_color_scheme_for_theme (theme_info->name);
|
|
|
|
generate_theme_thumbnail_async (theme_info,
|
|
theme_info->name,
|
|
THUMBNAIL_TYPE_GTK,
|
|
theme_info->name,
|
|
scheme,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
func, user_data, destroy);
|
|
g_free (scheme);
|
|
}
|
|
|
|
void
|
|
generate_metacity_theme_thumbnail_async (GnomeThemeInfo *theme_info,
|
|
ThemeThumbnailFunc func,
|
|
gpointer user_data,
|
|
GDestroyNotify destroy)
|
|
{
|
|
generate_theme_thumbnail_async (theme_info,
|
|
theme_info->name,
|
|
THUMBNAIL_TYPE_METACITY,
|
|
NULL,
|
|
NULL,
|
|
theme_info->name,
|
|
NULL,
|
|
NULL,
|
|
func, user_data, destroy);
|
|
}
|
|
|
|
void
|
|
generate_icon_theme_thumbnail_async (GnomeThemeIconInfo *theme_info,
|
|
ThemeThumbnailFunc func,
|
|
gpointer user_data,
|
|
GDestroyNotify destroy)
|
|
{
|
|
generate_theme_thumbnail_async (theme_info,
|
|
theme_info->name,
|
|
THUMBNAIL_TYPE_ICON,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
theme_info->name,
|
|
NULL,
|
|
func, user_data, destroy);
|
|
}
|
|
|
|
void
|
|
theme_thumbnail_factory_init (int argc, char *argv[])
|
|
{
|
|
#ifndef __APPLE__
|
|
gint child_pid;
|
|
#endif
|
|
|
|
pipe (pipe_to_factory_fd);
|
|
pipe (pipe_from_factory_fd);
|
|
|
|
/* Apple's CoreFoundation classes must not be used from forked
|
|
* processes. Since freetype (and thus GTK) uses them, we simply
|
|
* disable the thumbnailer on MacOS for now. That means no thumbs
|
|
* until the thumbnailing process is rewritten, but at least we won't
|
|
* make apps crash. */
|
|
#ifndef __APPLE__
|
|
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.type = g_byte_array_new ();
|
|
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]);
|
|
#endif /* __APPLE__ */
|
|
|
|
async_data.set = FALSE;
|
|
async_data.theme_name = NULL;
|
|
async_data.data = g_byte_array_new ();
|
|
}
|