2008-03-11 Jens Granseuer <jensgr@gmx.net> Encountering a theme that could not be thumbnailed (e.g. because the metacity theme for a metatheme isn't installed) would make the thumbnailer crash. Since it's not restarted by the appearance capplet this would result in all themes encountered after the broken one not to be thumbnailed either. This change fixes up error handling in the thumbnailer so that the broken theme is simply skipped and processing can continue with the next one. (bug #521009) * theme-thumbnail.c: (create_meta_theme_pixbuf), (create_metacity_theme_pixbuf), (message_from_capplet), (message_from_child), (read_pixbuf), (generate_theme_thumbnail_async), (theme_thumbnail_factory_init): properly handle failed thumbnailing attempts svn path=/trunk/; revision=8576
1232 lines
40 KiB
C
1232 lines
40 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 <libgnomeui/gnome-icon-theme.h>
|
|
|
|
#include "theme-thumbnail.h"
|
|
#include "gtkrc-utils.h"
|
|
#include "capplet-util.h"
|
|
|
|
static gint child_pid;
|
|
|
|
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
|
|
#define ICON_THUMBNAIL_SIZE 48
|
|
|
|
|
|
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, *retval;
|
|
GtkIconInfo *folder_icon_info;
|
|
const gchar *filename;
|
|
gchar *example_icon_name;
|
|
|
|
icon_theme = gtk_icon_theme_new ();
|
|
gtk_icon_theme_set_custom_theme (icon_theme, icon_theme_name);
|
|
|
|
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)
|
|
{
|
|
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);
|
|
}
|
|
|
|
/* 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
|
|
*/
|
|
if (gdk_pixbuf_get_width (folder_icon) != ICON_THUMBNAIL_SIZE) {
|
|
int width, height;
|
|
gdouble scale;
|
|
|
|
scale = ((double) ICON_THUMBNAIL_SIZE) / gdk_pixbuf_get_width (folder_icon);
|
|
width = ICON_THUMBNAIL_SIZE;
|
|
height = scale * gdk_pixbuf_get_height (folder_icon);
|
|
|
|
retval = gdk_pixbuf_scale_simple (folder_icon, width, height, GDK_INTERP_BILINEAR);
|
|
g_object_unref (folder_icon);
|
|
} else {
|
|
retval = folder_icon;
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
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;
|
|
GdkPixbuf *pixbuf;
|
|
gint i, rowstride;
|
|
guchar *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)
|
|
{
|
|
char *type;
|
|
gint width, height;
|
|
type = (char *) 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 = 0;
|
|
} 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 unref the pixbuf */
|
|
(* async_data.func) (pixbuf, async_data.theme_name, async_data.user_data);
|
|
|
|
if (async_data.destroy)
|
|
(* async_data.destroy) (async_data.user_data);
|
|
|
|
/* 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[])
|
|
{
|
|
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.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]);
|
|
async_data.set = FALSE;
|
|
async_data.theme_name = NULL;
|
|
async_data.data = g_byte_array_new ();
|
|
}
|
|
|