summaryrefslogtreecommitdiff
path: root/capplets/common/theme-thumbnail.c
diff options
context:
space:
mode:
Diffstat (limited to 'capplets/common/theme-thumbnail.c')
-rw-r--r--capplets/common/theme-thumbnail.c623
1 files changed, 0 insertions, 623 deletions
diff --git a/capplets/common/theme-thumbnail.c b/capplets/common/theme-thumbnail.c
deleted file mode 100644
index aa94b9671..000000000
--- a/capplets/common/theme-thumbnail.c
+++ /dev/null
@@ -1,623 +0,0 @@
-#include <unistd.h>
-#include <string.h>
-#include <metacity-private/util.h>
-#include <metacity-private/theme.h>
-#include <metacity-private/theme-parser.h>
-#include <metacity-private/preview-widget.h>
-#include <signal.h>
-#include <errno.h>
-
-/* We have to #undef this as metacity #defines these. */
-#undef _
-#undef N_
-
-#include <libgnomeui/gnome-icon-theme.h>
-#include <config.h>
-
-#include "theme-thumbnail.h"
-#include "capplet-util.h"
-
-static gint child_pid;
-#define ICON_SIZE_WIDTH 150
-#define ICON_SIZE_HEIGHT 150
-
-typedef struct
-{
- gboolean set;
- GByteArray *data;
- gchar *meta_theme_name;
- ThemeThumbnailFunc func;
- gpointer user_data;
- GDestroyNotify destroy;
- GIOChannel *channel;
- guint watch_id;
-} ThemeThumbnailAsyncData;
-
-
-GHashTable *theme_hash = NULL;
-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_WM_THEME_NAME,
- READING_ICON_THEME_NAME,
- READING_APPLICATION_FONT,
- WRITING_PIXBUF_DATA
-};
-
-typedef struct
-{
- gint status;
- GByteArray *control_theme_name;
- GByteArray *wm_theme_name;
- GByteArray *icon_theme_name;
- GByteArray *application_font;
-} ThemeThumbnailData;
-
-int pipe_to_factory_fd[2];
-int pipe_from_factory_fd[2];
-
-static void
-fake_expose_widget (GtkWidget *widget,
- GdkPixmap *pixmap)
-{
- GdkWindow *tmp_window;
- GdkEventExpose event;
-
- event.type = GDK_EXPOSE;
- event.window = pixmap;
- event.send_event = FALSE;
- event.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);
-}
-
-static void
-create_image (ThemeThumbnailData *theme_thumbnail_data,
- GdkPixbuf *pixbuf)
-{
- GtkWidget *window;
- GtkWidget *preview;
- GtkWidget *align;
- GtkWidget *stock_button;
-
- GtkRequisition requisition;
- GtkAllocation allocation;
- GdkPixmap *pixmap;
- GdkVisual *visual;
- MetaFrameFlags flags;
- MetaTheme *theme = NULL;
- GtkSettings *settings;
- GtkIconTheme *icon_theme;
- GdkPixbuf *folder_icon;
- GtkIconInfo *folder_icon_info;
- const gchar *filename;
-
- 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,
- 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);
- fake_expose_widget (preview, pixmap);
- fake_expose_widget (stock_button, pixmap);
- 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);
-
-
- gdk_pixbuf_get_from_drawable (pixbuf, pixmap, NULL, 0, 0, 0, 0, ICON_SIZE_WIDTH, ICON_SIZE_HEIGHT);
-
- /* Handle the icon theme */
- icon_theme = gtk_icon_theme_new ();
- gtk_icon_theme_set_custom_theme (icon_theme, (char *) theme_thumbnail_data->icon_theme_name->data);
-
- /* Have to try both "folder" and "gnome-fs-directory" seems themes seem to use either name */
- folder_icon_info = gtk_icon_theme_lookup_icon (icon_theme, "folder", 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);
- }
-
- g_object_unref (icon_theme);
-
- filename = gtk_icon_info_get_filename (folder_icon_info);
-
- if (filename != NULL)
- {
- folder_icon = gdk_pixbuf_new_from_file (filename, NULL);
- }
- else
- {
- folder_icon = NULL;
- }
-
- gtk_icon_info_free (folder_icon_info);
-
- /* render the icon to the thumbnail */
- if (folder_icon)
- {
- gdk_pixbuf_composite (folder_icon,
- pixbuf,
- align->allocation.x + align->allocation.width - gdk_pixbuf_get_width (folder_icon) - 5,
- align->allocation.y + align->allocation.height - gdk_pixbuf_get_height (folder_icon) - 5,
- gdk_pixbuf_get_width (folder_icon),
- gdk_pixbuf_get_height (folder_icon),
- align->allocation.x + align->allocation.width - gdk_pixbuf_get_width (folder_icon) - 5,
- align->allocation.y + align->allocation.height - gdk_pixbuf_get_height (folder_icon) - 5,
- 1.0, 1.0, GDK_INTERP_BILINEAR, 255);
- g_object_unref (folder_icon);
- }
-}
-
-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_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->wm_theme_name, 0);
- g_byte_array_set_size (theme_thumbnail_data->icon_theme_name, 0);
- g_byte_array_set_size (theme_thumbnail_data->application_font, 0);
- }
- return TRUE;
- case G_IO_STATUS_AGAIN:
- return TRUE;
- case G_IO_STATUS_EOF:
- case G_IO_STATUS_ERROR:
- _exit (0);
- default:
- g_assert_not_reached ();
- }
-
- return TRUE;
-}
-
-static gboolean
-message_from_child (GIOChannel *source,
- GIOCondition condition,
- gpointer data)
-{
-
- gchar buffer[1024];
- GIOStatus status;
- gsize bytes_read;
-
- if (async_data.set == FALSE)
- return TRUE;
-
- status = g_io_channel_read_chars (source,
- buffer,
- 1024,
- &bytes_read,
- NULL);
- switch (status)
- {
- case G_IO_STATUS_NORMAL:
- g_byte_array_append (async_data.data, buffer, bytes_read);
- if (async_data.data->len == ICON_SIZE_WIDTH * ICON_SIZE_HEIGHT * 4)
- {
- GdkPixbuf *pixbuf;
- GdkPixbuf *scaled_pixbuf;
- gchar *pixels;
- gint i, rowstride;
-
- pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, ICON_SIZE_WIDTH, ICON_SIZE_HEIGHT);
- pixels = gdk_pixbuf_get_pixels (pixbuf);
- rowstride = gdk_pixbuf_get_rowstride (pixbuf);
- for (i = 0; i < ICON_SIZE_HEIGHT; i++)
- memcpy (pixels + rowstride * i, async_data.data->data + 4 * ICON_SIZE_WIDTH * i, ICON_SIZE_WIDTH * 4);
-
- scaled_pixbuf = gdk_pixbuf_scale_simple (pixbuf, ICON_SIZE_WIDTH/2, ICON_SIZE_HEIGHT/2, GDK_INTERP_BILINEAR);
- g_hash_table_insert (theme_hash, g_strdup(async_data.meta_theme_name), scaled_pixbuf);
- g_object_unref (pixbuf);
-
- (* async_data.func) (scaled_pixbuf, async_data.user_data);
- if (async_data.destroy)
- (* async_data.destroy) (async_data.user_data);
-
- /* Clean up async_data */
- g_free (async_data.meta_theme_name);
- g_source_remove (async_data.watch_id);
- g_io_channel_unref (async_data.channel);
-
- /* reset async_data */
- async_data.meta_theme_name = NULL;
- async_data.channel = NULL;
- async_data.func = NULL;
- async_data.user_data = NULL;
- async_data.destroy = NULL;
- async_data.set = FALSE;
- g_byte_array_set_size (async_data.data, 0);
- }
- return TRUE;
- case G_IO_STATUS_AGAIN:
- return TRUE;
-
- case G_IO_STATUS_EOF:
- case G_IO_STATUS_ERROR:
- return TRUE;
- default:
- g_assert_not_reached ();
- }
-
- return TRUE;
-}
-
-void
-theme_thumbnail_invalidate_cache (GnomeThemeMetaInfo *meta_theme_info)
-{
- gboolean success;
-
- success = g_hash_table_remove (theme_hash, meta_theme_info->name);
- printf ("Success is %d\n", success);
-}
-
-GdkPixbuf *
-generate_theme_thumbnail (GnomeThemeMetaInfo *meta_theme_info,
- gboolean clear_cache)
-{
- GdkPixbuf *retval = NULL;
- GdkPixbuf *pixbuf = NULL;
- gint i, rowstride;
- char *pixels;
-
- g_return_val_if_fail (async_data.set == FALSE, NULL);
-
- pixbuf = g_hash_table_lookup (theme_hash, meta_theme_info->name);
- if (pixbuf != NULL)
- {
- if (clear_cache)
- g_hash_table_remove (theme_hash, meta_theme_info->name);
- else
- return pixbuf;
- }
-
- if (!pipe_to_factory_fd[1] || !pipe_from_factory_fd[0])
- return NULL;
-
- pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, ICON_SIZE_WIDTH, ICON_SIZE_HEIGHT);
- write (pipe_to_factory_fd[1], meta_theme_info->gtk_theme_name, strlen (meta_theme_info->gtk_theme_name) + 1);
- write (pipe_to_factory_fd[1], meta_theme_info->metacity_theme_name, strlen (meta_theme_info->metacity_theme_name) + 1);
- write (pipe_to_factory_fd[1], meta_theme_info->icon_theme_name, strlen (meta_theme_info->icon_theme_name) + 1);
- if (meta_theme_info->application_font == NULL)
- write (pipe_to_factory_fd[1], "Sans 10", strlen ("Sans 10") + 1);
- else
- write (pipe_to_factory_fd[1], meta_theme_info->application_font, strlen (meta_theme_info->application_font) + 1);
-
- rowstride = gdk_pixbuf_get_rowstride (pixbuf);
- pixels = gdk_pixbuf_get_pixels (pixbuf);
-
- for (i = 0; i < ICON_SIZE_HEIGHT; i++)
- {
- gint j = 0;
- gint bytes_read;
-
- do
- {
- bytes_read = read (pipe_from_factory_fd[0], pixels + (rowstride)*i + j, ICON_SIZE_WIDTH * gdk_pixbuf_get_n_channels (pixbuf) - j);
- if (bytes_read > 0)
- j += bytes_read;
- else if (bytes_read == 0)
- {
- g_warning ("Received EOF while reading thumbnail for gtk: '%s', metacity '%s', icon: '%s', font: '%s'\n",
- meta_theme_info->gtk_theme_name,
- meta_theme_info->metacity_theme_name,
- meta_theme_info->icon_theme_name,
- meta_theme_info->application_font ? meta_theme_info->application_font : "Sans 10");
- g_object_unref (pixbuf);
- close (pipe_to_factory_fd[1]);
- pipe_to_factory_fd[1] = 0;
- close (pipe_from_factory_fd[0]);
- pipe_from_factory_fd[0] = 0;
- return NULL;
- }
- }
- while (j < ICON_SIZE_WIDTH * gdk_pixbuf_get_n_channels (pixbuf));
- }
-
- retval = gdk_pixbuf_scale_simple (pixbuf, ICON_SIZE_WIDTH/2, ICON_SIZE_HEIGHT/2, GDK_INTERP_BILINEAR);
- g_object_unref (pixbuf);
-
- g_hash_table_insert (theme_hash, g_strdup (meta_theme_info->name), retval);
- return retval;
-}
-
-void
-generate_theme_thumbnail_async (GnomeThemeMetaInfo *meta_theme_info,
- ThemeThumbnailFunc func,
- gpointer user_data,
- GDestroyNotify destroy)
-{
- GdkPixbuf *pixbuf;
-
- g_return_if_fail (async_data.set == FALSE);
-
- pixbuf = g_hash_table_lookup (theme_hash, meta_theme_info->name);
- if (pixbuf != NULL)
- {
- (* func) (pixbuf, user_data);
- if (destroy)
- (* destroy) (user_data);
- return;
- }
-
- if (!pipe_to_factory_fd[1] || !pipe_from_factory_fd[0])
- {
- (* func) (NULL, user_data);
- if (destroy)
- (* destroy) (user_data);
- return;
- }
-
- if (async_data.channel == NULL)
- {
- async_data.channel = g_io_channel_unix_new (pipe_from_factory_fd[0]);
- g_io_channel_set_flags (async_data.channel, g_io_channel_get_flags (async_data.channel) |
- G_IO_FLAG_NONBLOCK, NULL);
- g_io_channel_set_encoding (async_data.channel, NULL, NULL);
- async_data.watch_id = g_io_add_watch (async_data.channel, G_IO_IN | G_IO_HUP, message_from_child, NULL);
- }
-
-
- async_data.set = TRUE;
- async_data.meta_theme_name = g_strdup (meta_theme_info->name);
- async_data.func = func;
- async_data.user_data = user_data;
- async_data.destroy = destroy;
-
- write (pipe_to_factory_fd[1], meta_theme_info->gtk_theme_name, strlen (meta_theme_info->gtk_theme_name) + 1);
- 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.wm_theme_name = g_byte_array_new ();
- data.icon_theme_name = g_byte_array_new ();
- data.application_font = g_byte_array_new ();
-
- channel = g_io_channel_unix_new (pipe_to_factory_fd[0]);
- g_io_channel_set_flags (channel, g_io_channel_get_flags (channel) |
- G_IO_FLAG_NONBLOCK, NULL);
- g_io_channel_set_encoding (channel, NULL, NULL);
- g_io_add_watch (channel, G_IO_IN | G_IO_HUP, message_from_capplet, &data);
- g_io_channel_unref (channel);
-
- gtk_main ();
- _exit (0);
- }
-
- g_assert (child_pid > 0);
-
- /* Parent */
- close (pipe_to_factory_fd[0]);
- close (pipe_from_factory_fd[1]);
- async_data.set = FALSE;
- async_data.meta_theme_name = NULL;
- async_data.data = g_byte_array_new ();
-
- theme_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
-}