4
#include <metacity-private/util.h>
5
#include <metacity-private/theme.h>
6
#include <metacity-private/theme-parser.h>
7
#include <metacity-private/preview-widget.h>
12
/* We have to #undef this as metacity #defines these. */
18
#include "theme-thumbnail.h"
19
#include "gtkrc-utils.h"
20
#include "capplet-util.h"
26
gint thumbnail_height;
29
ThemeThumbnailFunc func;
31
GDestroyNotify destroy;
34
} ThemeThumbnailAsyncData;
37
static ThemeThumbnailAsyncData async_data;
41
/* Our protocol is pretty simple. The parent process will write several strings
42
* (separated by a '\000'). They are the widget theme, the wm theme, the icon
43
* theme, etc. Then, it will wait for the child to write back the data. The
44
* parent expects ICON_SIZE_WIDTH * ICON_SIZE_HEIGHT * 4 bytes of information.
45
* After that, the child is ready for the next theme to render.
52
READING_CONTROL_THEME_NAME,
53
READING_GTK_COLOR_SCHEME,
54
READING_WM_THEME_NAME,
55
READING_ICON_THEME_NAME,
56
READING_APPLICATION_FONT,
64
GByteArray *control_theme_name;
65
GByteArray *gtk_color_scheme;
66
GByteArray *wm_theme_name;
67
GByteArray *icon_theme_name;
68
GByteArray *application_font;
73
gchar *thumbnail_type;
75
ThemeThumbnailFunc func;
77
GDestroyNotify destroy;
80
static GList *theme_queue = NULL;
82
static int pipe_to_factory_fd[2];
83
static int pipe_from_factory_fd[2];
85
#define THUMBNAIL_TYPE_META "meta"
86
#define THUMBNAIL_TYPE_GTK "gtk"
87
#define THUMBNAIL_TYPE_METACITY "metacity"
88
#define THUMBNAIL_TYPE_ICON "icon"
90
#define META_THUMBNAIL_SIZE 128
91
#define GTK_THUMBNAIL_SIZE 96
92
#define METACITY_THUMBNAIL_WIDTH 120
93
#define METACITY_THUMBNAIL_HEIGHT 60
96
draw_window_on_pixbuf (GtkWidget *widget)
101
GdkScreen *screen = gdk_screen_get_default ();
105
gtk_widget_ensure_style (widget);
107
style = gtk_widget_get_style (widget);
110
g_assert (style->font_desc);
112
gtk_window_get_size (GTK_WINDOW (widget), &width, &height);
114
visual = gtk_widget_get_visual (widget);
115
pixmap = gdk_pixmap_new (NULL, width, height, visual->depth);
116
gdk_drawable_set_colormap (GDK_DRAWABLE (pixmap), gtk_widget_get_colormap (widget));
118
window = gtk_widget_get_window (widget);
120
gdk_window_redirect_to_drawable (window, pixmap, 0, 0, 0, 0, width, height);
121
gdk_window_set_override_redirect (window, TRUE);
122
gtk_window_move (GTK_WINDOW (widget), gdk_screen_get_width (screen), gdk_screen_get_height (screen));
123
gtk_widget_show(widget);
125
gdk_window_process_updates (window, TRUE);
126
gtk_widget_hide(widget);
132
pixbuf_apply_mask_region (GdkPixbuf *pixbuf, GdkRegion *region)
134
gint nchannels, rowstride, w, h;
137
g_return_if_fail (pixbuf);
138
g_return_if_fail (region);
140
nchannels = gdk_pixbuf_get_n_channels (pixbuf);
141
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
142
pixels = gdk_pixbuf_get_pixels (pixbuf);
145
/* we need an alpha channel ... */
146
if (!gdk_pixbuf_get_has_alpha (pixbuf) || nchannels != 4)
149
for (w = 0; w < gdk_pixbuf_get_width (pixbuf); ++w)
150
for (h = 0; h < gdk_pixbuf_get_height (pixbuf); ++h)
152
if (!gdk_region_point_in (region, w, h))
154
p = pixels + h * rowstride + w * nchannels;
155
if (G_BYTE_ORDER == G_BIG_ENDIAN)
165
create_folder_icon (char *icon_theme_name)
167
GtkIconTheme *icon_theme;
168
GdkPixbuf *folder_icon = NULL;
169
GtkIconInfo *folder_icon_info;
170
gchar *example_icon_name;
171
const gchar *icon_names[5];
174
icon_theme = gtk_icon_theme_new ();
175
gtk_icon_theme_set_custom_theme (icon_theme, icon_theme_name);
178
/* Get the Example icon name in the theme if specified */
179
example_icon_name = gtk_icon_theme_get_example_icon_name (icon_theme);
180
if (example_icon_name != NULL)
181
icon_names[i++] = example_icon_name;
182
icon_names[i++] = "x-directory-normal";
183
icon_names[i++] = "gnome-fs-directory";
184
icon_names[i++] = "folder";
185
icon_names[i++] = NULL;
187
folder_icon_info = gtk_icon_theme_choose_icon (icon_theme, icon_names, 48, GTK_ICON_LOOKUP_FORCE_SIZE);
188
if (folder_icon_info != NULL)
190
folder_icon = gtk_icon_info_load_icon (folder_icon_info, NULL);
191
gtk_icon_info_free (folder_icon_info);
194
g_object_unref (icon_theme);
195
g_free (example_icon_name);
197
/* render the icon to the thumbnail */
198
if (folder_icon == NULL)
201
dummy = gtk_label_new ("");
203
folder_icon = gtk_widget_render_icon (dummy,
204
GTK_STOCK_MISSING_IMAGE,
205
GTK_ICON_SIZE_DIALOG,
208
gtk_widget_destroy (dummy);
215
create_meta_theme_pixbuf (ThemeThumbnailData *theme_thumbnail_data)
222
GtkWidget *stock_button;
226
GtkRequisition requisition;
227
GtkAllocation allocation;
228
GtkAllocation vbox_allocation;
230
MetaFrameFlags flags;
232
GdkPixbuf *pixbuf, *icon;
233
int icon_width, icon_height;
236
g_object_set (gtk_settings_get_default (),
237
"gtk-theme-name", (char *) theme_thumbnail_data->control_theme_name->data,
238
"gtk-font-name", (char *) theme_thumbnail_data->application_font->data,
239
"gtk-icon-theme-name", (char *) theme_thumbnail_data->icon_theme_name->data,
240
"gtk-color-scheme", (char *) theme_thumbnail_data->gtk_color_scheme->data,
243
theme = meta_theme_load ((char *) theme_thumbnail_data->wm_theme_name->data, NULL);
247
/* Represent the icon theme */
248
icon = create_folder_icon ((char *) theme_thumbnail_data->icon_theme_name->data);
249
icon_width = gdk_pixbuf_get_width (icon);
250
icon_height = gdk_pixbuf_get_height (icon);
252
/* Create a fake window */
253
flags = META_FRAME_ALLOWS_DELETE |
254
META_FRAME_ALLOWS_MENU |
255
META_FRAME_ALLOWS_MINIMIZE |
256
META_FRAME_ALLOWS_MAXIMIZE |
257
META_FRAME_ALLOWS_VERTICAL_RESIZE |
258
META_FRAME_ALLOWS_HORIZONTAL_RESIZE |
259
META_FRAME_HAS_FOCUS |
260
META_FRAME_ALLOWS_SHADE |
261
META_FRAME_ALLOWS_MOVE;
263
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
264
preview = meta_preview_new ();
265
gtk_container_add (GTK_CONTAINER (window), preview);
266
gtk_widget_realize (window);
267
gtk_widget_realize (preview);
268
vbox = gtk_vbox_new (FALSE, 6);
269
gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
270
gtk_container_add (GTK_CONTAINER (preview), vbox);
271
align = gtk_alignment_new (0, 0, 0.0, 0.0);
272
gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 0);
273
stock_button = gtk_button_new_from_stock (GTK_STOCK_OPEN);
274
gtk_container_add (GTK_CONTAINER (align), stock_button);
275
box = gtk_hbox_new (FALSE, 0);
276
gtk_box_pack_start (GTK_BOX (vbox), box, FALSE, FALSE, 0);
277
checkbox = gtk_check_button_new ();
278
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbox), TRUE);
279
gtk_box_pack_start (GTK_BOX (box), checkbox, FALSE, FALSE, 0);
280
radio = gtk_radio_button_new (NULL);
281
gtk_box_pack_start (GTK_BOX (box), radio, FALSE, FALSE, 0);
283
gtk_widget_show_all (preview);
285
meta_preview_set_frame_flags (META_PREVIEW (preview), flags);
286
meta_preview_set_theme (META_PREVIEW (preview), theme);
287
meta_preview_set_title (META_PREVIEW (preview), "");
289
gtk_window_set_default_size (GTK_WINDOW (window), META_THUMBNAIL_SIZE, META_THUMBNAIL_SIZE);
291
gtk_widget_size_request (window, &requisition);
294
allocation.width = META_THUMBNAIL_SIZE;
295
allocation.height = META_THUMBNAIL_SIZE;
296
gtk_widget_size_allocate (window, &allocation);
297
gtk_widget_size_request (window, &requisition);
299
pixmap = draw_window_on_pixbuf (window);
301
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, META_THUMBNAIL_SIZE, META_THUMBNAIL_SIZE);
302
gdk_pixbuf_get_from_drawable (pixbuf, pixmap, NULL, 0, 0, 0, 0, META_THUMBNAIL_SIZE, META_THUMBNAIL_SIZE);
304
gtk_widget_get_allocation (vbox, &vbox_allocation);
306
/* Add the icon theme to the pixbuf */
307
gdk_pixbuf_composite (icon, pixbuf,
308
vbox_allocation.x + vbox_allocation.width - icon_width - 5,
309
vbox_allocation.y + vbox_allocation.height - icon_height - 5,
310
icon_width, icon_height,
311
vbox_allocation.x + vbox_allocation.width - icon_width - 5,
312
vbox_allocation.y + vbox_allocation.height - icon_height - 5,
313
1.0, 1.0, GDK_INTERP_BILINEAR, 255);
314
region = meta_preview_get_clip_region (META_PREVIEW (preview),
315
META_THUMBNAIL_SIZE, META_THUMBNAIL_SIZE);
316
pixbuf_apply_mask_region (pixbuf, region);
317
gdk_region_destroy (region);
319
g_object_unref (icon);
320
gtk_widget_destroy (window);
321
meta_theme_free (theme);
322
g_object_unref (pixmap);
328
create_gtk_theme_pixbuf (ThemeThumbnailData *theme_thumbnail_data)
330
GtkSettings *settings;
331
GtkWidget *window, *vbox, *box, *stock_button, *checkbox, *radio;
332
GtkRequisition requisition;
333
GtkAllocation allocation;
335
GdkPixbuf *pixbuf, *retval;
338
settings = gtk_settings_get_default ();
339
g_object_set (settings, "gtk-theme-name", (char *) theme_thumbnail_data->control_theme_name->data,
340
"gtk-color-scheme", (char *) theme_thumbnail_data->gtk_color_scheme->data,
343
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
345
vbox = gtk_vbox_new (FALSE, 0);
346
gtk_container_add (GTK_CONTAINER (window), vbox);
347
box = gtk_hbox_new (FALSE, 6);
348
gtk_container_set_border_width (GTK_CONTAINER (box), 6);
349
gtk_box_pack_start (GTK_BOX (vbox), box, FALSE, FALSE, 0);
350
stock_button = gtk_button_new_from_stock (GTK_STOCK_OPEN);
351
gtk_box_pack_start (GTK_BOX (box), stock_button, FALSE, FALSE, 0);
352
checkbox = gtk_check_button_new ();
353
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbox), TRUE);
354
gtk_box_pack_start (GTK_BOX (box), checkbox, FALSE, FALSE, 0);
355
radio = gtk_radio_button_new_from_widget (NULL);
356
gtk_box_pack_start (GTK_BOX (box), radio, FALSE, FALSE, 0);
358
gtk_widget_show_all (vbox);
359
gtk_widget_realize (stock_button);
360
gtk_widget_realize (gtk_bin_get_child (GTK_BIN (stock_button)));
361
gtk_widget_realize (checkbox);
362
gtk_widget_realize (radio);
363
gtk_widget_map (stock_button);
364
gtk_widget_map (gtk_bin_get_child (GTK_BIN (stock_button)));
365
gtk_widget_map (checkbox);
366
gtk_widget_map (radio);
368
gtk_widget_size_request (window, &requisition);
371
allocation.width = requisition.width;
372
allocation.height = requisition.height;
373
gtk_widget_size_allocate (window, &allocation);
374
gtk_widget_size_request (window, &requisition);
376
gtk_window_get_size (GTK_WINDOW (window), &width, &height);
378
pixmap = draw_window_on_pixbuf (window);
380
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, width, height);
381
gdk_pixbuf_get_from_drawable (pixbuf, pixmap, NULL, 0, 0, 0, 0, width, height);
383
retval = gdk_pixbuf_scale_simple (pixbuf,
385
(int) GTK_THUMBNAIL_SIZE * (((double) height) / ((double) width)),
386
GDK_INTERP_BILINEAR);
387
g_object_unref (pixbuf);
388
gtk_widget_destroy (window);
389
g_object_unref (pixmap);
395
create_metacity_theme_pixbuf (ThemeThumbnailData *theme_thumbnail_data)
397
GtkWidget *window, *preview, *dummy;
398
MetaFrameFlags flags;
400
GtkRequisition requisition;
401
GtkAllocation allocation;
403
GdkPixbuf *pixbuf, *retval;
406
theme = meta_theme_load ((char *) theme_thumbnail_data->wm_theme_name->data, NULL);
410
flags = META_FRAME_ALLOWS_DELETE |
411
META_FRAME_ALLOWS_MENU |
412
META_FRAME_ALLOWS_MINIMIZE |
413
META_FRAME_ALLOWS_MAXIMIZE |
414
META_FRAME_ALLOWS_VERTICAL_RESIZE |
415
META_FRAME_ALLOWS_HORIZONTAL_RESIZE |
416
META_FRAME_HAS_FOCUS |
417
META_FRAME_ALLOWS_SHADE |
418
META_FRAME_ALLOWS_MOVE;
420
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
421
gtk_window_set_default_size (GTK_WINDOW (window), (int) METACITY_THUMBNAIL_WIDTH * 1.2, (int) METACITY_THUMBNAIL_HEIGHT * 1.2);
423
preview = meta_preview_new ();
424
meta_preview_set_frame_flags (META_PREVIEW (preview), flags);
425
meta_preview_set_theme (META_PREVIEW (preview), theme);
426
meta_preview_set_title (META_PREVIEW (preview), "");
427
gtk_container_add (GTK_CONTAINER (window), preview);
429
dummy = gtk_label_new ("");
430
gtk_container_add (GTK_CONTAINER (preview), dummy);
432
gtk_widget_realize (window);
433
gtk_widget_realize (preview);
434
gtk_widget_realize (dummy);
435
gtk_widget_show_all (preview);
436
gtk_widget_map (dummy);
438
gtk_widget_size_request (window, &requisition);
441
allocation.width = (int) METACITY_THUMBNAIL_WIDTH * 1.2;
442
allocation.height = (int) METACITY_THUMBNAIL_HEIGHT * 1.2;
443
gtk_widget_size_allocate (window, &allocation);
444
gtk_widget_size_request (window, &requisition);
446
pixmap = draw_window_on_pixbuf (window);
448
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, (int) METACITY_THUMBNAIL_WIDTH * 1.2, (int) METACITY_THUMBNAIL_HEIGHT * 1.2);
449
gdk_pixbuf_get_from_drawable (pixbuf, pixmap, NULL, 0, 0, 0, 0, (int) METACITY_THUMBNAIL_WIDTH * 1.2, (int) METACITY_THUMBNAIL_HEIGHT * 1.2);
451
region = meta_preview_get_clip_region (META_PREVIEW (preview),
452
METACITY_THUMBNAIL_WIDTH * 1.2, METACITY_THUMBNAIL_HEIGHT * 1.2);
453
pixbuf_apply_mask_region (pixbuf, region);
454
gdk_region_destroy (region);
457
retval = gdk_pixbuf_scale_simple (pixbuf,
458
METACITY_THUMBNAIL_WIDTH,
459
METACITY_THUMBNAIL_HEIGHT,
460
GDK_INTERP_BILINEAR);
461
g_object_unref (pixbuf);
463
gtk_widget_destroy (window);
464
meta_theme_free (theme);
465
g_object_unref (pixmap);
471
create_icon_theme_pixbuf (ThemeThumbnailData *theme_thumbnail_data)
473
return create_folder_icon ((char *) theme_thumbnail_data->icon_theme_name->data);
478
handle_bytes (const gchar *buffer,
480
ThemeThumbnailData *theme_thumbnail_data)
485
while (bytes_read > 0)
489
switch (theme_thumbnail_data->status)
491
case READY_FOR_THEME:
492
theme_thumbnail_data->status = READING_TYPE;
495
nil = memchr (ptr, '\000', bytes_read);
498
g_byte_array_append (theme_thumbnail_data->type, ptr, bytes_read);
503
g_byte_array_append (theme_thumbnail_data->type, ptr, nil - ptr + 1);
504
bytes_read -= (nil - ptr + 1);
506
theme_thumbnail_data->status = READING_CONTROL_THEME_NAME;
510
case READING_CONTROL_THEME_NAME:
511
nil = memchr (ptr, '\000', bytes_read);
514
g_byte_array_append (theme_thumbnail_data->control_theme_name, ptr, bytes_read);
519
g_byte_array_append (theme_thumbnail_data->control_theme_name, ptr, nil - ptr + 1);
520
bytes_read -= (nil - ptr + 1);
522
theme_thumbnail_data->status = READING_GTK_COLOR_SCHEME;
526
case READING_GTK_COLOR_SCHEME:
527
nil = memchr (ptr, '\000', bytes_read);
530
g_byte_array_append (theme_thumbnail_data->gtk_color_scheme, ptr, bytes_read);
535
g_byte_array_append (theme_thumbnail_data->gtk_color_scheme, ptr, nil - ptr + 1);
536
bytes_read -= (nil - ptr + 1);
538
theme_thumbnail_data->status = READING_WM_THEME_NAME;
542
case READING_WM_THEME_NAME:
543
nil = memchr (ptr, '\000', bytes_read);
546
g_byte_array_append (theme_thumbnail_data->wm_theme_name, ptr, bytes_read);
551
g_byte_array_append (theme_thumbnail_data->wm_theme_name, ptr, nil - ptr + 1);
552
bytes_read -= (nil - ptr + 1);
554
theme_thumbnail_data->status = READING_ICON_THEME_NAME;
558
case READING_ICON_THEME_NAME:
559
nil = memchr (ptr, '\000', bytes_read);
562
g_byte_array_append (theme_thumbnail_data->icon_theme_name, ptr, bytes_read);
567
g_byte_array_append (theme_thumbnail_data->icon_theme_name, ptr, nil - ptr + 1);
568
bytes_read -= (nil - ptr + 1);
570
theme_thumbnail_data->status = READING_APPLICATION_FONT;
574
case READING_APPLICATION_FONT:
575
nil = memchr (ptr, '\000', bytes_read);
578
g_byte_array_append (theme_thumbnail_data->application_font, ptr, bytes_read);
583
g_byte_array_append (theme_thumbnail_data->application_font, ptr, nil - ptr + 1);
584
bytes_read -= (nil - ptr + 1);
586
theme_thumbnail_data->status = WRITING_PIXBUF_DATA;
591
g_assert_not_reached ();
597
message_from_capplet (GIOChannel *source,
598
GIOCondition condition,
604
ThemeThumbnailData *theme_thumbnail_data;
606
theme_thumbnail_data = (ThemeThumbnailData *) data;
607
status = g_io_channel_read_chars (source,
615
case G_IO_STATUS_NORMAL:
616
handle_bytes (buffer, bytes_read, theme_thumbnail_data);
618
if (theme_thumbnail_data->status == WRITING_PIXBUF_DATA)
620
GdkPixbuf *pixbuf = NULL;
624
const gchar *type = (const gchar *) theme_thumbnail_data->type->data;
626
if (!strcmp (type, THUMBNAIL_TYPE_META))
627
pixbuf = create_meta_theme_pixbuf (theme_thumbnail_data);
628
else if (!strcmp (type, THUMBNAIL_TYPE_GTK))
629
pixbuf = create_gtk_theme_pixbuf (theme_thumbnail_data);
630
else if (!strcmp (type, THUMBNAIL_TYPE_METACITY))
631
pixbuf = create_metacity_theme_pixbuf (theme_thumbnail_data);
632
else if (!strcmp (type, THUMBNAIL_TYPE_ICON))
633
pixbuf = create_icon_theme_pixbuf (theme_thumbnail_data);
635
g_assert_not_reached ();
637
if (pixbuf == NULL) {
638
width = height = rowstride = 0;
641
width = gdk_pixbuf_get_width (pixbuf);
642
height = gdk_pixbuf_get_height (pixbuf);
643
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
644
pixels = gdk_pixbuf_get_pixels (pixbuf);
647
/* Write the pixbuf's size */
648
write (pipe_from_factory_fd[1], &width, sizeof (width));
649
write (pipe_from_factory_fd[1], &height, sizeof (height));
651
for (i = 0; i < height; i++)
653
write (pipe_from_factory_fd[1], pixels + rowstride * i, width * gdk_pixbuf_get_n_channels (pixbuf));
657
g_object_unref (pixbuf);
658
g_byte_array_set_size (theme_thumbnail_data->type, 0);
659
g_byte_array_set_size (theme_thumbnail_data->control_theme_name, 0);
660
g_byte_array_set_size (theme_thumbnail_data->gtk_color_scheme, 0);
661
g_byte_array_set_size (theme_thumbnail_data->wm_theme_name, 0);
662
g_byte_array_set_size (theme_thumbnail_data->icon_theme_name, 0);
663
g_byte_array_set_size (theme_thumbnail_data->application_font, 0);
664
theme_thumbnail_data->status = READY_FOR_THEME;
668
case G_IO_STATUS_AGAIN:
671
case G_IO_STATUS_EOF:
672
case G_IO_STATUS_ERROR:
676
g_assert_not_reached ();
683
generate_next_in_queue (void)
685
ThemeQueueItem *item;
687
if (theme_queue == NULL)
690
item = theme_queue->data;
691
theme_queue = g_list_delete_link (theme_queue, g_list_first (theme_queue));
693
if (!strcmp (item->thumbnail_type, THUMBNAIL_TYPE_META))
694
generate_meta_theme_thumbnail_async ((GnomeThemeMetaInfo *) item->theme_info,
698
else if (!strcmp (item->thumbnail_type, THUMBNAIL_TYPE_GTK))
699
generate_gtk_theme_thumbnail_async ((GnomeThemeInfo *) item->theme_info,
703
else if (!strcmp (item->thumbnail_type, THUMBNAIL_TYPE_METACITY))
704
generate_metacity_theme_thumbnail_async ((GnomeThemeInfo *) item->theme_info,
708
else if (!strcmp (item->thumbnail_type, THUMBNAIL_TYPE_ICON))
709
generate_icon_theme_thumbnail_async ((GnomeThemeIconInfo *) item->theme_info,
718
message_from_child (GIOChannel *source,
719
GIOCondition condition,
726
if (async_data.set == FALSE)
729
if (condition == G_IO_HUP)
732
status = g_io_channel_read_chars (source,
739
case G_IO_STATUS_NORMAL:
740
g_byte_array_append (async_data.data, (guchar *) buffer, bytes_read);
742
if (async_data.thumbnail_width == -1 && async_data.data->len >= 2 * sizeof (gint))
744
async_data.thumbnail_width = *((gint *) async_data.data->data);
745
async_data.thumbnail_height = *(((gint *) async_data.data->data) + 1);
746
g_byte_array_remove_range (async_data.data, 0, 2 * sizeof (gint));
749
if (async_data.thumbnail_width >= 0 && async_data.data->len == async_data.thumbnail_width * async_data.thumbnail_height * 4)
751
GdkPixbuf *pixbuf = NULL;
753
if (async_data.thumbnail_width > 0) {
757
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, async_data.thumbnail_width, async_data.thumbnail_height);
758
pixels = (gchar *) gdk_pixbuf_get_pixels (pixbuf);
759
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
761
for (i = 0; i < async_data.thumbnail_height; ++i)
762
memcpy (pixels + rowstride * i, async_data.data->data + 4 * async_data.thumbnail_width * i, async_data.thumbnail_width * 4);
765
/* callback function needs to ref the pixbuf if it wants to keep it */
766
(* async_data.func) (pixbuf, async_data.theme_name, async_data.user_data);
768
if (async_data.destroy)
769
(* async_data.destroy) (async_data.user_data);
772
g_object_unref (pixbuf);
774
/* Clean up async_data */
775
g_free (async_data.theme_name);
776
g_source_remove (async_data.watch_id);
777
g_io_channel_unref (async_data.channel);
779
/* reset async_data */
780
async_data.thumbnail_width = -1;
781
async_data.thumbnail_height = -1;
782
async_data.theme_name = NULL;
783
async_data.channel = NULL;
784
async_data.func = NULL;
785
async_data.user_data = NULL;
786
async_data.destroy = NULL;
787
async_data.set = FALSE;
788
g_byte_array_set_size (async_data.data, 0);
790
generate_next_in_queue ();
794
case G_IO_STATUS_AGAIN:
797
case G_IO_STATUS_EOF:
798
case G_IO_STATUS_ERROR:
802
g_assert_not_reached ();
809
send_thumbnail_request (gchar *thumbnail_type,
810
gchar *gtk_theme_name,
811
gchar *gtk_color_scheme,
812
gchar *metacity_theme_name,
813
gchar *icon_theme_name,
814
gchar *application_font)
816
write (pipe_to_factory_fd[1], thumbnail_type, strlen (thumbnail_type) + 1);
819
write (pipe_to_factory_fd[1], gtk_theme_name, strlen (gtk_theme_name) + 1);
821
write (pipe_to_factory_fd[1], "", 1);
823
if (gtk_color_scheme)
824
write (pipe_to_factory_fd[1], gtk_color_scheme, strlen (gtk_color_scheme) + 1);
826
write (pipe_to_factory_fd[1], "", 1);
828
if (metacity_theme_name)
829
write (pipe_to_factory_fd[1], metacity_theme_name, strlen (metacity_theme_name) + 1);
831
write (pipe_to_factory_fd[1], "", 1);
834
write (pipe_to_factory_fd[1], icon_theme_name, strlen (icon_theme_name) + 1);
836
write (pipe_to_factory_fd[1], "", 1);
838
if (application_font)
839
write (pipe_to_factory_fd[1], application_font, strlen (application_font) + 1);
841
write (pipe_to_factory_fd[1], "Sans 10", strlen ("Sans 10") + 1);
848
gint bytes_read, i, j = 0;
856
bytes_read = read (pipe_from_factory_fd[0], ((guint8*) size) + j, 2 * sizeof (gint));
861
while (j < 2 * sizeof (gint));
863
if (size[0] <= 0 || size[1] <= 0)
866
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, size[0], size[1]);
867
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
868
pixels = gdk_pixbuf_get_pixels (pixbuf);
870
for (i = 0; i < size[1]; i++)
876
bytes_read = read (pipe_from_factory_fd[0], pixels + rowstride * i + j, size[0] * gdk_pixbuf_get_n_channels (pixbuf) - j);
880
else if (bytes_read == 0)
882
g_object_unref (pixbuf);
886
while (j < size[0] * gdk_pixbuf_get_n_channels (pixbuf));
892
g_warning ("Received EOF while reading thumbnail");
893
close (pipe_to_factory_fd[1]);
894
pipe_to_factory_fd[1] = 0;
895
close (pipe_from_factory_fd[0]);
896
pipe_from_factory_fd[0] = 0;
901
generate_theme_thumbnail (gchar *thumbnail_type,
902
gchar *gtk_theme_name,
903
gchar *gtk_color_scheme,
904
gchar *metacity_theme_name,
905
gchar *icon_theme_name,
906
gchar *application_font)
908
if (async_data.set || !pipe_to_factory_fd[1] || !pipe_from_factory_fd[0])
911
send_thumbnail_request (thumbnail_type,
918
return read_pixbuf ();
922
generate_meta_theme_thumbnail (GnomeThemeMetaInfo *theme_info)
924
return generate_theme_thumbnail (THUMBNAIL_TYPE_META,
925
theme_info->gtk_theme_name,
926
theme_info->gtk_color_scheme,
927
theme_info->metacity_theme_name,
928
theme_info->icon_theme_name,
929
theme_info->application_font);
933
generate_gtk_theme_thumbnail (GnomeThemeInfo *theme_info)
937
scheme = gtkrc_get_color_scheme_for_theme (theme_info->name);
939
return generate_theme_thumbnail (THUMBNAIL_TYPE_GTK,
949
generate_metacity_theme_thumbnail (GnomeThemeInfo *theme_info)
951
return generate_theme_thumbnail (THUMBNAIL_TYPE_METACITY,
960
generate_icon_theme_thumbnail (GnomeThemeIconInfo *theme_info)
962
return generate_theme_thumbnail (THUMBNAIL_TYPE_ICON,
971
generate_theme_thumbnail_async (gpointer theme_info,
973
gchar *thumbnail_type,
974
gchar *gtk_theme_name,
975
gchar *gtk_color_scheme,
976
gchar *metacity_theme_name,
977
gchar *icon_theme_name,
978
gchar *application_font,
979
ThemeThumbnailFunc func,
981
GDestroyNotify destroy)
985
ThemeQueueItem *item;
987
item = g_new0 (ThemeQueueItem, 1);
988
item->thumbnail_type = thumbnail_type;
989
item->theme_info = theme_info;
991
item->user_data = user_data;
992
item->destroy = destroy;
994
theme_queue = g_list_append (theme_queue, item);
998
if (!pipe_to_factory_fd[1] || !pipe_from_factory_fd[0])
1000
(* func) (NULL, theme_name, user_data);
1003
(* destroy) (user_data);
1008
if (async_data.channel == NULL)
1010
async_data.channel = g_io_channel_unix_new (pipe_from_factory_fd[0]);
1011
g_io_channel_set_flags (async_data.channel, g_io_channel_get_flags (async_data.channel) | G_IO_FLAG_NONBLOCK, NULL);
1012
g_io_channel_set_encoding (async_data.channel, NULL, NULL);
1013
async_data.watch_id = g_io_add_watch (async_data.channel, G_IO_IN | G_IO_HUP, message_from_child, NULL);
1016
async_data.set = TRUE;
1017
async_data.thumbnail_width = -1;
1018
async_data.thumbnail_height = -1;
1019
async_data.theme_name = g_strdup (theme_name);
1020
async_data.func = func;
1021
async_data.user_data = user_data;
1022
async_data.destroy = destroy;
1024
send_thumbnail_request (thumbnail_type,
1027
metacity_theme_name,
1033
generate_meta_theme_thumbnail_async (GnomeThemeMetaInfo *theme_info,
1034
ThemeThumbnailFunc func,
1036
GDestroyNotify destroy)
1038
generate_theme_thumbnail_async (theme_info,
1040
THUMBNAIL_TYPE_META,
1041
theme_info->gtk_theme_name,
1042
theme_info->gtk_color_scheme,
1043
theme_info->metacity_theme_name,
1044
theme_info->icon_theme_name,
1045
theme_info->application_font,
1046
func, user_data, destroy);
1050
generate_gtk_theme_thumbnail_async (GnomeThemeInfo *theme_info,
1051
ThemeThumbnailFunc func,
1053
GDestroyNotify destroy)
1057
scheme = gtkrc_get_color_scheme_for_theme (theme_info->name);
1059
generate_theme_thumbnail_async (theme_info,
1067
func, user_data, destroy);
1072
generate_metacity_theme_thumbnail_async (GnomeThemeInfo *theme_info,
1073
ThemeThumbnailFunc func,
1075
GDestroyNotify destroy)
1077
generate_theme_thumbnail_async (theme_info,
1079
THUMBNAIL_TYPE_METACITY,
1085
func, user_data, destroy);
1089
generate_icon_theme_thumbnail_async (GnomeThemeIconInfo *theme_info,
1090
ThemeThumbnailFunc func,
1092
GDestroyNotify destroy)
1094
generate_theme_thumbnail_async (theme_info,
1096
THUMBNAIL_TYPE_ICON,
1102
func, user_data, destroy);
1106
theme_thumbnail_factory_init (int argc, char *argv[])
1112
pipe (pipe_to_factory_fd);
1113
pipe (pipe_from_factory_fd);
1115
/* Apple's CoreFoundation classes must not be used from forked
1116
* processes. Since freetype (and thus GTK) uses them, we simply
1117
* disable the thumbnailer on MacOS for now. That means no thumbs
1118
* until the thumbnailing process is rewritten, but at least we won't
1119
* make apps crash. */
1121
child_pid = fork ();
1124
ThemeThumbnailData data;
1125
GIOChannel *channel;
1128
gtk_init (&argc, &argv);
1130
close (pipe_to_factory_fd[1]);
1131
pipe_to_factory_fd[1] = 0;
1132
close (pipe_from_factory_fd[0]);
1133
pipe_from_factory_fd[0] = 0;
1135
data.status = READY_FOR_THEME;
1136
data.type = g_byte_array_new ();
1137
data.control_theme_name = g_byte_array_new ();
1138
data.gtk_color_scheme = g_byte_array_new ();
1139
data.wm_theme_name = g_byte_array_new ();
1140
data.icon_theme_name = g_byte_array_new ();
1141
data.application_font = g_byte_array_new ();
1143
channel = g_io_channel_unix_new (pipe_to_factory_fd[0]);
1144
g_io_channel_set_flags (channel, g_io_channel_get_flags (channel) |
1145
G_IO_FLAG_NONBLOCK, NULL);
1146
g_io_channel_set_encoding (channel, NULL, NULL);
1147
g_io_add_watch (channel, G_IO_IN | G_IO_HUP, message_from_capplet, &data);
1148
g_io_channel_unref (channel);
1154
g_assert (child_pid > 0);
1157
close (pipe_to_factory_fd[0]);
1158
close (pipe_from_factory_fd[1]);
1159
#endif /* __APPLE__ */
1161
async_data.set = FALSE;
1162
async_data.theme_name = NULL;
1163
async_data.data = g_byte_array_new ();