#include #include #include #include #include #include #include #include #include /* We have to #undef this as metacity #defines these. */ #undef _ #undef N_ #include #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 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 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; int width, height; gdouble scale; 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 */ scale = 48.0 / gdk_pixbuf_get_width (folder_icon); width = 48; 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); return retval; } 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; GdkPixbuf *icon; int width, height; 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 = create_folder_icon ((char *) theme_thumbnail_data->icon_theme_name->data); width = gdk_pixbuf_get_width (icon); height = gdk_pixbuf_get_height (icon); gdk_pixbuf_composite (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, 1.0, 1.0, GDK_INTERP_BILINEAR, 255); g_object_unref (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_object_unref (pixbuf); /* allbak function needs to unref the 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; } GdkPixbuf * generate_theme_thumbnail (GnomeThemeMetaInfo *meta_theme_info) { GdkPixbuf *retval = NULL; GdkPixbuf *pixbuf; gint i, rowstride; char *pixels; if (async_data.set || !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], "", 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); return retval; } void generate_theme_thumbnail_async (GnomeThemeMetaInfo *meta_theme_info, ThemeThumbnailFunc func, gpointer user_data, GDestroyNotify destroy) { g_return_if_fail (async_data.set == FALSE); 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], "", 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 (); } /* Functions for specific types of themes */ GdkPixbuf * generate_gtk_theme_thumbnail (GnomeThemeInfo *info) { GdkDisplayManager *manager; GdkDisplay *display, *default_display; GdkScreen *screen; GObject *settings; GtkWidget *window, *vbox, *box, *stock_button, *checkbox, *radio; GtkRequisition requisition; GtkAllocation allocation; GdkVisual *visual; GdkPixmap *pixmap; GdkPixbuf *pixbuf, *ret; gint width, height; display = gdk_display_open (gdk_get_display_arg_name ()); screen = gdk_display_get_default_screen (display); settings = G_OBJECT (gtk_settings_get_for_screen (screen)); g_object_set (settings, "gtk-theme-name", info->name, NULL); manager = gdk_display_manager_get (); default_display = gdk_display_manager_get_default_display (manager); gdk_display_manager_set_default_display (manager, display); 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 = ICON_SIZE_WIDTH; allocation.height = ICON_SIZE_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); /* Create a pixmap */ 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); gdk_display_flush (display); gtk_widget_destroy (window); 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); ret = gdk_pixbuf_scale_simple (pixbuf, 96, (int) 96.0 * (((double) height) / ((double) width)), GDK_INTERP_BILINEAR); g_object_unref (pixbuf); gdk_display_manager_set_default_display (manager, default_display); gdk_display_close (display); return ret; } GdkPixbuf * generate_metacity_theme_thumbnail (GnomeThemeInfo *info) { GtkWidget *window, *preview, *dummy; MetaFrameFlags flags; MetaTheme *theme; GtkRequisition requisition; GtkAllocation allocation; GdkVisual *visual; GdkPixmap *pixmap; GdkPixbuf *pixbuf, *ret; theme = meta_theme_load (info->name, 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), ICON_SIZE_WIDTH, ICON_SIZE_WIDTH / 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 = ICON_SIZE_WIDTH; allocation.height = ICON_SIZE_WIDTH / 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, ICON_SIZE_WIDTH, ICON_SIZE_WIDTH / 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); pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, ICON_SIZE_WIDTH, ICON_SIZE_WIDTH / 2); gdk_pixbuf_get_from_drawable (pixbuf, pixmap, NULL, 0, 0, 0, 0, ICON_SIZE_WIDTH, ICON_SIZE_WIDTH / 2); ret = gdk_pixbuf_scale_simple (pixbuf, 96, 48, GDK_INTERP_BILINEAR); g_object_unref (pixbuf); gtk_widget_destroy (window); return ret; } GdkPixbuf * generate_icon_theme_thumbnail (GnomeThemeIconInfo *info) { return create_folder_icon (info->name); }