diff options
author | Perberos <[email protected]> | 2011-11-04 22:16:15 -0300 |
---|---|---|
committer | Perberos <[email protected]> | 2011-11-04 22:16:15 -0300 |
commit | fff4ecc82f2bcfa7427596e7ad9c3769fcab040b (patch) | |
tree | ac4f1812a7991609c9c32c776daede2d8492f7b5 /savers/gste-slideshow.c | |
download | mate-screensaver-fff4ecc82f2bcfa7427596e7ad9c3769fcab040b.tar.bz2 mate-screensaver-fff4ecc82f2bcfa7427596e7ad9c3769fcab040b.tar.xz |
first commit
Diffstat (limited to 'savers/gste-slideshow.c')
-rw-r--r-- | savers/gste-slideshow.c | 1082 |
1 files changed, 1082 insertions, 0 deletions
diff --git a/savers/gste-slideshow.c b/savers/gste-slideshow.c new file mode 100644 index 0000000..9180be8 --- /dev/null +++ b/savers/gste-slideshow.c @@ -0,0 +1,1082 @@ +/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8; tab-width: 8 -*- + * + * Copyright (C) 2005-2006 William Jon McCann <[email protected]> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + */ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +#include <glib.h> +#include <gtk/gtk.h> + +#include "gs-theme-engine.h" +#include "gste-slideshow.h" + +static void gste_slideshow_class_init (GSTESlideshowClass *klass); +static void gste_slideshow_init (GSTESlideshow *engine); +static void gste_slideshow_finalize (GObject *object); + +struct GSTESlideshowPrivate +{ + /* Image at full opacity */ + cairo_pattern_t *pat1; + /* Image at partial opacity */ + cairo_pattern_t *pat2; + /* Alpha of pat2 */ + gdouble alpha2; + /* edges of pat2 */ + int pat2top; + int pat2bottom; + int pat2left; + int pat2right; + + /* backbuffer that we do all the alpha drawing into (no round + * trips to the X server when the server doesn't support drawing + * pixmaps with alpha?) */ + cairo_surface_t *surf; + + gint64 fade_ticks; + + GThread *load_thread; + GAsyncQueue *op_q; + GAsyncQueue *results_q; + + guint results_pull_id; + guint update_image_id; + + GSList *filename_list; + char *images_location; + gboolean sort_images; + int window_width; + int window_height; + PangoColor *background_color; + gboolean no_stretch_hint; + + guint timeout_id; + + GTimer *timer; + gboolean fade_disabled; +}; + +enum +{ + PROP_0, + PROP_IMAGES_LOCATION, + PROP_SORT_IMAGES, + PROP_SOLID_BACKGROUND, + PROP_NO_STRETCH_HINT +}; + +#define GSTE_SLIDESHOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSTE_TYPE_SLIDESHOW, GSTESlideshowPrivate)) + +static GObjectClass *parent_class = NULL; + +G_DEFINE_TYPE (GSTESlideshow, gste_slideshow, GS_TYPE_THEME_ENGINE) + +#define N_FADE_TICKS 10 +#define MINIMUM_FPS 3.0 +#define DEFAULT_IMAGES_LOCATION DATADIR "/pixmaps/backgrounds" +#define IMAGE_LOAD_TIMEOUT 10000 + +typedef struct _Op +{ + char *location; + GSTESlideshow *slideshow; +} Op; + +typedef struct _OpResult +{ + GdkPixbuf *pixbuf; +} OpResult; + +static gboolean +push_load_image_func (GSTESlideshow *show) +{ + Op *op; + + gs_theme_engine_profile_msg ("Starting a new image load"); + + op = g_new (Op, 1); + + op->location = g_strdup (show->priv->images_location); + op->slideshow = g_object_ref (show); + + g_async_queue_push (show->priv->op_q, op); + + show->priv->update_image_id = 0; + + return FALSE; +} + +static void +start_new_load (GSTESlideshow *show, + guint timeout) +{ + gs_theme_engine_profile_msg ("Scheduling a new image load"); + + /* queue a new load */ + if (show->priv->update_image_id <= 0) + { + show->priv->update_image_id = g_timeout_add_full (G_PRIORITY_LOW, timeout, + (GSourceFunc)push_load_image_func, + show, NULL); + } +} + +static void +start_fade (GSTESlideshow *show, + GdkPixbuf *pixbuf) +{ + int pw; + int ph; + int x; + int y; + cairo_t *cr; + int window_width; + int window_height; + + gs_theme_engine_profile_start ("start"); + + window_width = show->priv->window_width; + window_height = show->priv->window_height; + + if (show->priv->pat2 != NULL) + { + cairo_pattern_destroy (show->priv->pat2); + } + + pw = gdk_pixbuf_get_width (pixbuf); + ph = gdk_pixbuf_get_height (pixbuf); + x = (window_width - pw) / 2; + y = (window_height - ph) / 2; + + if (gdk_pixbuf_get_has_alpha (pixbuf) && show->priv->background_color) + { + GdkPixbuf *colored; + guint32 color; + GdkPixmap *pixmap; + + color = (show->priv->background_color->red << 16) + + (show->priv->background_color->green / 256 << 8) + + show->priv->background_color->blue / 256; + colored = gdk_pixbuf_composite_color_simple (pixbuf, + pw, ph, + GDK_INTERP_BILINEAR, + 255, + 256, + color, + color); + pixmap = gdk_pixmap_new (NULL, ph, pw, gdk_visual_get_system ()->depth); + + gdk_draw_pixbuf (pixmap, NULL, colored, 0, 0, 0, 0, -1, -1, GDK_RGB_DITHER_MAX, 0, 0); + gdk_pixbuf_get_from_drawable (pixbuf, pixmap, NULL, 0, 0, 0, 0, -1, -1); + + g_object_unref (pixmap); + + g_object_unref(colored); + } + + cr = cairo_create (show->priv->surf); + + /* XXX Handle out of memory? */ + gdk_cairo_set_source_pixbuf (cr, pixbuf, x, y); + show->priv->pat2 = cairo_pattern_reference (cairo_get_source (cr)); + show->priv->pat2top = y; + show->priv->pat2bottom = y + ph; + show->priv->pat2left = x; + show->priv->pat2right = x + pw; + + cairo_destroy (cr); + + show->priv->fade_ticks = 0; + g_timer_start (show->priv->timer); + + gs_theme_engine_profile_end ("end"); +} + +static void +finish_fade (GSTESlideshow *show) +{ + gs_theme_engine_profile_start ("start"); + + if (show->priv->pat1 != NULL) + { + cairo_pattern_destroy (show->priv->pat1); + } + + show->priv->pat1 = show->priv->pat2; + show->priv->pat2 = NULL; + + start_new_load (show, IMAGE_LOAD_TIMEOUT); + + gs_theme_engine_profile_end ("end"); +} + +static void +update_display (GSTESlideshow *show) +{ + int window_width; + int window_height; + cairo_t *cr; + + gs_theme_engine_profile_start ("start"); + + cr = cairo_create (show->priv->surf); + + gs_theme_engine_get_window_size (GS_THEME_ENGINE (show), + &window_width, + &window_height); + + if (show->priv->pat2 != NULL) + { + /* fade out areas not covered by the new image */ + /* top */ + cairo_rectangle (cr, 0, 0, window_width, show->priv->pat2top); + if (show->priv->background_color) + { + cairo_set_source_rgba (cr, show->priv->background_color->red / 65535.0, + show->priv->background_color->green / 65535.0, + show->priv->background_color->blue / 65535.0, show->priv->alpha2); + } + else + { + cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, show->priv->alpha2); + } + cairo_fill (cr); + /* left (excluding what's covered by top and bottom) */ + cairo_rectangle (cr, 0, show->priv->pat2top, + show->priv->pat2left, + show->priv->pat2bottom - show->priv->pat2top); + if (show->priv->background_color) + { + cairo_set_source_rgba (cr, show->priv->background_color->red / 65535.0, + show->priv->background_color->green / 65535.0, + show->priv->background_color->blue / 65535.0, show->priv->alpha2); + } + else + { + cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, show->priv->alpha2); + } + cairo_fill (cr); + /* bottom */ + cairo_rectangle (cr, 0, show->priv->pat2bottom, window_width, + window_height - show->priv->pat2bottom); + if (show->priv->background_color) + { + cairo_set_source_rgba (cr, show->priv->background_color->red / 65535.0, + show->priv->background_color->green / 65535.0, + show->priv->background_color->blue / 65535.0, show->priv->alpha2); + } + else + { + cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, show->priv->alpha2); + } + cairo_fill (cr); + /* right (excluding what's covered by top and bottom) */ + cairo_rectangle (cr, show->priv->pat2right, + show->priv->pat2top, + window_width - show->priv->pat2right, + show->priv->pat2bottom - show->priv->pat2top); + if (show->priv->background_color) + { + cairo_set_source_rgba (cr, show->priv->background_color->red / 65535.0, + show->priv->background_color->green / 65535.0, + show->priv->background_color->blue / 65535.0, show->priv->alpha2); + } + else + { + cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, show->priv->alpha2); + } + cairo_fill (cr); + + gs_theme_engine_profile_start ("paint pattern to surface"); + cairo_set_source (cr, show->priv->pat2); + + cairo_paint_with_alpha (cr, show->priv->alpha2); + gs_theme_engine_profile_end ("paint pattern to surface"); + } + else + { + if (show->priv->pat1 != NULL) + { + cairo_set_source (cr, show->priv->pat1); + cairo_paint (cr); + } + } + + cairo_destroy (cr); + + /* paint the image buffer into the window */ + cr = gdk_cairo_create (GTK_WIDGET (show)->window); + + cairo_set_source_surface (cr, show->priv->surf, 0, 0); + + gs_theme_engine_profile_start ("paint surface to window"); + cairo_paint (cr); + gs_theme_engine_profile_end ("paint surface to window"); + + cairo_destroy (cr); + + gs_theme_engine_profile_end ("end"); +} + +static gboolean +draw_iter (GSTESlideshow *show) +{ + double old_opacity; + double new_opacity; + + if (show->priv->pat2 != NULL) + { + gdouble fps; + gdouble elapsed; + + if (show->priv->fade_disabled) + { + show->priv->alpha2 = 1.0; + update_display (show); + finish_fade (show); + return TRUE; + } + + /* we are in a fade */ + show->priv->fade_ticks++; + + /* + * We have currently drawn pat2 with old_opacity, and we + * want to set alpha2 so that drawing pat2 at alpha2 + * yields it drawn with new_opacity + * + * Solving + * new_opacity = 1 - (1 - alpha2) * (1 - old_opacity) + * yields + * alpha2 = 1 - (1 - new_opacity) / (1 - old_opacity) + * + * XXX This assumes that cairo doesn't correct alpha for + * the color profile. However, any error is guaranteed + * to be cleaned up by the last iteration, where alpha2 + * becomes 1 because new_opacity is 1. + */ + old_opacity = (double) (show->priv->fade_ticks - 1) / + (double) N_FADE_TICKS; + new_opacity = (double) show->priv->fade_ticks / + (double) N_FADE_TICKS; + show->priv->alpha2 = 1.0 - (1.0 - new_opacity) / + (1.0 - old_opacity); + + update_display (show); + + elapsed = g_timer_elapsed (show->priv->timer, NULL); + fps = (gdouble)show->priv->fade_ticks / elapsed; + if (fps < MINIMUM_FPS) + { + g_warning ("Getting less than %.2f frames per second, disabling fade", MINIMUM_FPS); + show->priv->fade_ticks = N_FADE_TICKS - 1; + show->priv->fade_disabled = TRUE; + } + + if (show->priv->fade_ticks >= N_FADE_TICKS) + { + finish_fade (show); + } + } + + return TRUE; +} + +static void +process_new_pixbuf (GSTESlideshow *show, + GdkPixbuf *pixbuf) +{ + gs_theme_engine_profile_msg ("Processing a new image"); + + if (pixbuf != NULL) + { + start_fade (show, pixbuf); + } + else + { + start_new_load (show, 10); + } +} + +static void +op_result_free (OpResult *result) +{ + if (result == NULL) + { + return; + } + + if (result->pixbuf != NULL) + { + g_object_unref (result->pixbuf); + } + + g_free (result); +} + +static gboolean +results_pull_func (GSTESlideshow *show) +{ + OpResult *result; + + GDK_THREADS_ENTER (); + + g_async_queue_lock (show->priv->results_q); + + result = g_async_queue_try_pop_unlocked (show->priv->results_q); + g_assert (result); + + while (result != NULL) + { + process_new_pixbuf (show, result->pixbuf); + op_result_free (result); + + result = g_async_queue_try_pop_unlocked (show->priv->results_q); + } + + show->priv->results_pull_id = 0; + + g_async_queue_unlock (show->priv->results_q); + + GDK_THREADS_LEAVE (); + + return FALSE; +} + +static GdkPixbuf * +scale_pixbuf (GdkPixbuf *pixbuf, + int max_width, + int max_height, + gboolean no_stretch_hint) +{ + int pw; + int ph; + float scale_factor_x = 1.0; + float scale_factor_y = 1.0; + float scale_factor = 1.0; + + pw = gdk_pixbuf_get_width (pixbuf); + ph = gdk_pixbuf_get_height (pixbuf); + + /* If the image is less than 256 wide or high then it + is probably a thumbnail and we should ignore it */ + if (pw < 256 || ph < 256) + { + return NULL; + } + + /* Determine which dimension requires the smallest scale. */ + scale_factor_x = (float) max_width / (float) pw; + scale_factor_y = (float) max_height / (float) ph; + + if (scale_factor_x > scale_factor_y) + { + scale_factor = scale_factor_y; + } + else + { + scale_factor = scale_factor_x; + } + + /* always scale down, allow to disable scaling up */ + if (scale_factor < 1.0 || !no_stretch_hint) + { + int scale_x; + int scale_y; + + scale_x = (int) (pw * scale_factor); + scale_y = (int) (ph * scale_factor); + return gdk_pixbuf_scale_simple (pixbuf, + scale_x, + scale_y, + GDK_INTERP_BILINEAR); + } + else + { + return g_object_ref (pixbuf); + } +} + +static void +add_files_to_list (GSList **list, + const char *base) +{ + GDir *d; + const char *d_name; + + d = g_dir_open (base, 0, NULL); + if (d == NULL) + { + g_warning ("Could not open directory: %s", base); + return; + } + + while ((d_name = g_dir_read_name (d)) != NULL) + { + char *path; + + /* skip hidden files */ + if (d_name[0] == '.') + { + continue; + } + + path = g_build_filename (base, d_name, NULL); + if (g_file_test (path, G_FILE_TEST_IS_DIR)) + { + add_files_to_list (list, path); + g_free (path); + } + else + { + *list = g_slist_prepend (*list, path); + } + } + + g_dir_close (d); +} + +static GSList * +build_filename_list_local_dir (const char *base) +{ + GSList *list = NULL; + + add_files_to_list (&list, base); + + return list; +} + +static int +gste_strcmp_compare_func (gconstpointer string_a, gconstpointer string_b) +{ + return strcmp (string_a == NULL ? "" : string_a, + string_b == NULL ? "" : string_b); +} + + +static GdkPixbuf * +get_pixbuf_from_local_dir (GSTESlideshow *show, + const char *location) +{ + GdkPixbuf *pixbuf, *transformed_pixbuf; + char *filename; + int i; + GSList *l; + + /* rebuild the cache */ + if (show->priv->filename_list == NULL) + { + show->priv->filename_list = build_filename_list_local_dir (location); + } + + if (show->priv->filename_list == NULL) + { + return NULL; + } + else + { + if (show->priv->sort_images) + { + show->priv->filename_list = g_slist_sort (show->priv->filename_list, gste_strcmp_compare_func); + } + } + + /* get a random filename if needed */ + if (! show->priv->sort_images) + { + i = g_random_int_range (0, g_slist_length (show->priv->filename_list)); + l = g_slist_nth (show->priv->filename_list, i); + } + else + { + l = show->priv->filename_list; + } + filename = l->data; + + pixbuf = gdk_pixbuf_new_from_file (filename, NULL); + + if (pixbuf != NULL) + { + transformed_pixbuf = gdk_pixbuf_apply_embedded_orientation (pixbuf); + g_object_unref (pixbuf); + } + else + { + transformed_pixbuf = NULL; + } + + g_free (filename); + show->priv->filename_list = g_slist_delete_link (show->priv->filename_list, l); + + return transformed_pixbuf; +} + +static GdkPixbuf * +get_pixbuf_from_location (GSTESlideshow *show, + const char *location) +{ + GdkPixbuf *pixbuf = NULL; + gboolean is_dir; + + if (location == NULL) + { + return NULL; + } + + is_dir = g_file_test (location, G_FILE_TEST_IS_DIR); + + if (is_dir) + { + pixbuf = get_pixbuf_from_local_dir (show, location); + } + + return pixbuf; +} + +static GdkPixbuf * +get_pixbuf (GSTESlideshow *show, + const char *location, + int width, + int height) +{ + GdkPixbuf *pixbuf; + GdkPixbuf *scaled = NULL; + + if (location == NULL) + { + return NULL; + } + + pixbuf = get_pixbuf_from_location (show, location); + + if (pixbuf != NULL) + { + scaled = scale_pixbuf (pixbuf, width, height, show->priv->no_stretch_hint); + g_object_unref (pixbuf); + } + + return scaled; +} + +static void +op_load_image (GSTESlideshow *show, + const char *location) +{ + OpResult *op_result; + int window_width; + int window_height; + + window_width = show->priv->window_width; + window_height = show->priv->window_height; + + op_result = g_new0 (OpResult, 1); + + op_result->pixbuf = get_pixbuf (show, + location, + window_width, + window_height); + + GDK_THREADS_ENTER (); + g_async_queue_lock (show->priv->results_q); + g_async_queue_push_unlocked (show->priv->results_q, op_result); + + if (show->priv->results_pull_id == 0) + { + show->priv->results_pull_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE, + (GSourceFunc)results_pull_func, + show, NULL); + } + + g_async_queue_unlock (show->priv->results_q); + GDK_THREADS_LEAVE (); +} + +static gpointer +load_threadfunc (GAsyncQueue *op_q) +{ + Op *op; + + op = g_async_queue_pop (op_q); + while (op) + { + op_load_image (op->slideshow, + op->location); + + if (op->slideshow != NULL) + { + g_object_unref (op->slideshow); + } + g_free (op->location); + g_free (op); + + op = g_async_queue_pop (op_q); + } + + return NULL; +} + +void +gste_slideshow_set_images_location (GSTESlideshow *show, + const char *location) +{ + g_return_if_fail (GSTE_IS_SLIDESHOW (show)); + + g_free (show->priv->images_location); + show->priv->images_location = g_strdup (location); +} + + +void +gste_slideshow_set_sort_images (GSTESlideshow *show, + gboolean sort_images) +{ + g_return_if_fail (GSTE_IS_SLIDESHOW (show)); + + show->priv->sort_images = sort_images; +} + +void +gste_slideshow_set_no_stretch_hint (GSTESlideshow *show, + gboolean no_stretch_hint) +{ + g_return_if_fail (GSTE_IS_SLIDESHOW (show)); + + show->priv->no_stretch_hint = no_stretch_hint; +} + +void +gste_slideshow_set_background_color (GSTESlideshow *show, + const char *background_color) +{ + g_return_if_fail (GSTE_IS_SLIDESHOW (show)); + + if (show->priv->background_color != NULL) + { + g_slice_free (PangoColor, show->priv->background_color); + show->priv->background_color = NULL; + } + + if (background_color != NULL) + { + show->priv->background_color = g_slice_new (PangoColor); + + if (pango_color_parse (show->priv->background_color, background_color) == FALSE) + { + g_slice_free (PangoColor, show->priv->background_color); + show->priv->background_color = NULL; + } + } +} + +static void +gste_slideshow_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GSTESlideshow *self; + + self = GSTE_SLIDESHOW (object); + + switch (prop_id) + { + case PROP_IMAGES_LOCATION: + gste_slideshow_set_images_location (self, g_value_get_string (value)); + break; + case PROP_SORT_IMAGES: + gste_slideshow_set_sort_images (self, g_value_get_boolean (value)); + break; + case PROP_SOLID_BACKGROUND: + gste_slideshow_set_background_color (self, g_value_get_string (value)); + break; + case PROP_NO_STRETCH_HINT: + gste_slideshow_set_no_stretch_hint (self, g_value_get_boolean (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gste_slideshow_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GSTESlideshow *self; + + self = GSTE_SLIDESHOW (object); + + switch (prop_id) + { + case PROP_IMAGES_LOCATION: + g_value_set_string (value, self->priv->images_location); + break; + case PROP_SORT_IMAGES: + g_value_set_boolean (value, self->priv->sort_images); + break; + case PROP_SOLID_BACKGROUND: + { + char *color = NULL; + color = pango_color_to_string (self->priv->background_color); + g_value_set_string (value, color); + g_free (color); + break; + } + case PROP_NO_STRETCH_HINT: + g_value_set_boolean (value, self->priv->no_stretch_hint); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gste_slideshow_real_show (GtkWidget *widget) +{ + GSTESlideshow *show = GSTE_SLIDESHOW (widget); + int delay; + + if (GTK_WIDGET_CLASS (parent_class)->show) + { + GTK_WIDGET_CLASS (parent_class)->show (widget); + } + + start_new_load (show, 10); + + delay = 25; + show->priv->timeout_id = g_timeout_add (delay, (GSourceFunc)draw_iter, show); + + if (show->priv->timer != NULL) + { + g_timer_destroy (show->priv->timer); + } + show->priv->timer = g_timer_new (); +} + +static gboolean +gste_slideshow_real_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GSTESlideshow *show = GSTE_SLIDESHOW (widget); + gboolean handled = FALSE; + + update_display (show); + + if (GTK_WIDGET_CLASS (parent_class)->expose_event) + { + handled = GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event); + } + + return handled; +} + +static gboolean +gste_slideshow_real_configure (GtkWidget *widget, + GdkEventConfigure *event) +{ + GSTESlideshow *show = GSTE_SLIDESHOW (widget); + gboolean handled = FALSE; + cairo_t *cr; + + /* resize */ + gs_theme_engine_get_window_size (GS_THEME_ENGINE (show), + &show->priv->window_width, + &show->priv->window_height); + + gs_theme_engine_profile_msg ("Resize to x:%d y:%d", + show->priv->window_width, + show->priv->window_height); + + if (show->priv->surf != NULL) + { + cairo_surface_destroy (show->priv->surf); + } + + cr = gdk_cairo_create (widget->window); + show->priv->surf = cairo_surface_create_similar (cairo_get_target (cr), + CAIRO_CONTENT_COLOR, + show->priv->window_width, + show->priv->window_height); + cairo_destroy (cr); + + /* schedule a redraw */ + gtk_widget_queue_draw (widget); + + if (GTK_WIDGET_CLASS (parent_class)->configure_event) + { + handled = GTK_WIDGET_CLASS (parent_class)->configure_event (widget, event); + } + + return handled; +} + +static void +gste_slideshow_class_init (GSTESlideshowClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class->finalize = gste_slideshow_finalize; + object_class->get_property = gste_slideshow_get_property; + object_class->set_property = gste_slideshow_set_property; + + widget_class->show = gste_slideshow_real_show; + widget_class->expose_event = gste_slideshow_real_expose; + widget_class->configure_event = gste_slideshow_real_configure; + + g_type_class_add_private (klass, sizeof (GSTESlideshowPrivate)); + + g_object_class_install_property (object_class, + PROP_IMAGES_LOCATION, + g_param_spec_string ("images-location", + NULL, + NULL, + NULL, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_SORT_IMAGES, + g_param_spec_boolean ("sort-images", + NULL, + NULL, + FALSE, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_SOLID_BACKGROUND, + g_param_spec_string ("background-color", + NULL, + NULL, + NULL, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_NO_STRETCH_HINT, + g_param_spec_boolean ("no-stretch", + NULL, + NULL, + FALSE, + G_PARAM_READWRITE)); +} + +static void +set_colormap (GtkWidget *widget) +{ + GdkScreen *screen; + GdkColormap *colormap; + + screen = gtk_widget_get_screen (widget); + colormap = gdk_screen_get_rgba_colormap (screen); + if (colormap == NULL) + { + colormap = gdk_screen_get_rgb_colormap (screen); + } + + gtk_widget_set_colormap (widget, colormap); +} + +static void +gste_slideshow_init (GSTESlideshow *show) +{ + GError *error; + + show->priv = GSTE_SLIDESHOW_GET_PRIVATE (show); + + show->priv->images_location = g_strdup (DEFAULT_IMAGES_LOCATION); + + show->priv->op_q = g_async_queue_new (); + show->priv->results_q = g_async_queue_new (); + + error = NULL; + show->priv->load_thread = g_thread_create ((GThreadFunc)load_threadfunc, show->priv->op_q, FALSE, &error); + if (show->priv->load_thread == NULL) + { + g_error ("Could not create a thread to load images: %s", + error->message); + g_error_free (error); + exit (-1); + } + + set_colormap (GTK_WIDGET (show)); +} + +static void +gste_slideshow_finalize (GObject *object) +{ + GSTESlideshow *show; + gpointer result; + + g_return_if_fail (object != NULL); + g_return_if_fail (GSTE_IS_SLIDESHOW (object)); + + show = GSTE_SLIDESHOW (object); + + g_return_if_fail (show->priv != NULL); + + if (show->priv->surf) + { + cairo_surface_destroy (show->priv->surf); + } + + if (show->priv->timeout_id > 0) + { + g_source_remove (show->priv->timeout_id); + show->priv->timeout_id = 0; + } + + if (show->priv->results_pull_id > 0) + { + g_source_remove (show->priv->results_pull_id); + } + + if (show->priv->results_q != NULL) + { + result = g_async_queue_try_pop (show->priv->results_q); + + while (result) + { + result = g_async_queue_try_pop (show->priv->results_q); + } + g_async_queue_unref (show->priv->results_q); + } + + g_free (show->priv->images_location); + show->priv->images_location = NULL; + + if (show->priv->background_color) + { + g_slice_free (PangoColor, show->priv->background_color); + show->priv->background_color = NULL; + } + + if (show->priv->timer != NULL) + { + g_timer_destroy (show->priv->timer); + } + + G_OBJECT_CLASS (parent_class)->finalize (object); +} |