gnome-control-center/panels/background/cc-background-paintable.c
velsinki 18413cb172 background: Make CcBackgroundPaintable independent
To make the CcBackgroundPaintable fully reusable, it has to know the
desired thumbnail size and the thumbnail factory. We add a width and
height property, and modify the thumbnail retrieval of CcBackgroundItem
to use the scale factor now.

This also allows us to greatly simplify the background sources, so that
they now only do one thing: provide CcBackgroundItems from different
sources.

We keep the fixed thumbnail height and width for the chooser, which
makes more sense now that it is in the chooser code instead of the
background source code.
2023-12-19 14:14:28 +00:00

390 lines
13 KiB
C

/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2021 Alexander Mikhaylenko <alexm@gnome.org>
*
* 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, see <http://www.gnu.org/licenses/>.
*
*/
#include <config.h>
#include "cc-background-enum-types.h"
#include "cc-background-paintable.h"
struct _CcBackgroundPaintable
{
GObject parent_instance;
GnomeDesktopThumbnailFactory *thumbnail_factory;
CcBackgroundItem *item;
int width;
int height;
int scale_factor;
GtkTextDirection text_direction;
GdkPaintable *texture;
GdkPaintable *dark_texture;
CcBackgroundPaintFlags paint_flags;
};
enum
{
PROP_0,
PROP_THUMBNAIL_FACTORY,
PROP_ITEM,
PROP_WIDTH,
PROP_HEIGHT,
PROP_SCALE_FACTOR,
PROP_TEXT_DIRECTION,
PROP_PAINT_FLAGS,
N_PROPS
};
static GParamSpec *properties [N_PROPS];
static void cc_background_paintable_paintable_init (GdkPaintableInterface *iface);
G_DEFINE_TYPE_WITH_CODE (CcBackgroundPaintable, cc_background_paintable, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE,
cc_background_paintable_paintable_init))
static void
update_cache (CcBackgroundPaintable *self)
{
g_autoptr(GdkPixbuf) pixbuf = NULL;
g_autoptr(GdkPixbuf) dark_pixbuf = NULL;
gboolean has_dark;
g_clear_object (&self->texture);
g_clear_object (&self->dark_texture);
has_dark = cc_background_item_has_dark_version (self->item);
if ((self->paint_flags & CC_BACKGROUND_PAINT_LIGHT) || !has_dark)
{
pixbuf = cc_background_item_get_thumbnail (self->item,
self->thumbnail_factory,
self->width,
self->height,
self->scale_factor,
FALSE);
self->texture = GDK_PAINTABLE (gdk_texture_new_for_pixbuf (pixbuf));
}
if ((self->paint_flags & CC_BACKGROUND_PAINT_DARK) && has_dark)
{
dark_pixbuf = cc_background_item_get_thumbnail (self->item,
self->thumbnail_factory,
self->width,
self->height,
self->scale_factor,
TRUE);
self->dark_texture = GDK_PAINTABLE (gdk_texture_new_for_pixbuf (dark_pixbuf));
}
gdk_paintable_invalidate_size (GDK_PAINTABLE (self));
}
static void
cc_background_paintable_dispose (GObject *object)
{
CcBackgroundPaintable *self = CC_BACKGROUND_PAINTABLE (object);
g_clear_object (&self->item);
g_clear_object (&self->thumbnail_factory);
g_clear_object (&self->texture);
g_clear_object (&self->dark_texture);
G_OBJECT_CLASS (cc_background_paintable_parent_class)->dispose (object);
}
static void
cc_background_paintable_constructed (GObject *object)
{
CcBackgroundPaintable *self = CC_BACKGROUND_PAINTABLE (object);
G_OBJECT_CLASS (cc_background_paintable_parent_class)->constructed (object);
update_cache (self);
}
static void
cc_background_paintable_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
CcBackgroundPaintable *self = CC_BACKGROUND_PAINTABLE (object);
switch (prop_id)
{
case PROP_THUMBNAIL_FACTORY:
g_value_set_object (value, self->thumbnail_factory);
break;
case PROP_ITEM:
g_value_set_object (value, self->item);
break;
case PROP_WIDTH:
g_value_set_int (value, self->width);
break;
case PROP_HEIGHT:
g_value_set_int (value, self->height);
break;
case PROP_SCALE_FACTOR:
g_value_set_int (value, self->scale_factor);
break;
case PROP_TEXT_DIRECTION:
g_value_set_enum (value, self->text_direction);
break;
case PROP_PAINT_FLAGS:
g_value_set_flags (value, self->paint_flags);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
cc_background_paintable_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
CcBackgroundPaintable *self = CC_BACKGROUND_PAINTABLE (object);
switch (prop_id)
{
case PROP_THUMBNAIL_FACTORY:
g_set_object (&self->thumbnail_factory, g_value_get_object (value));
break;
case PROP_ITEM:
g_set_object (&self->item, g_value_get_object (value));
break;
case PROP_WIDTH:
self->width = g_value_get_int (value);
break;
case PROP_HEIGHT:
self->height = g_value_get_int (value);
break;
case PROP_SCALE_FACTOR:
self->scale_factor = g_value_get_int (value);
update_cache (self);
break;
case PROP_TEXT_DIRECTION:
self->text_direction = g_value_get_enum (value);
gdk_paintable_invalidate_contents (GDK_PAINTABLE (self));
break;
case PROP_PAINT_FLAGS:
self->paint_flags = g_value_get_flags (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
cc_background_paintable_class_init (CcBackgroundPaintableClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = cc_background_paintable_dispose;
object_class->constructed = cc_background_paintable_constructed;
object_class->get_property = cc_background_paintable_get_property;
object_class->set_property = cc_background_paintable_set_property;
properties[PROP_THUMBNAIL_FACTORY] =
g_param_spec_object ("thumbnail-factory",
"Thumbnail factory",
"Thumbnail factory",
GNOME_DESKTOP_TYPE_THUMBNAIL_FACTORY,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
properties[PROP_ITEM] =
g_param_spec_object ("item",
"Item",
"Item",
CC_TYPE_BACKGROUND_ITEM,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
properties[PROP_WIDTH] =
g_param_spec_int ("width",
"Width",
"Width",
1, G_MAXINT, 144,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
properties[PROP_HEIGHT] =
g_param_spec_int ("height",
"Height",
"Height",
1, G_MAXINT, 144 * 3 / 4,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
properties[PROP_SCALE_FACTOR] =
g_param_spec_int ("scale-factor",
"Scale Factor",
"Scale Factor",
1, G_MAXINT, 1,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
properties[PROP_TEXT_DIRECTION] =
g_param_spec_enum ("text-direction",
"Text Direction",
"Text Direction",
GTK_TYPE_TEXT_DIRECTION,
GTK_TEXT_DIR_LTR,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
properties[PROP_PAINT_FLAGS] =
g_param_spec_flags ("paint-flags",
"Paint Flags",
"Paint Flags",
CC_TYPE_BACKGROUND_PAINT_FLAGS,
CC_BACKGROUND_PAINT_LIGHT,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, N_PROPS, properties);
}
static void
cc_background_paintable_init (CcBackgroundPaintable *self)
{
self->scale_factor = 1;
self->text_direction = GTK_TEXT_DIR_LTR;
}
static void
cc_background_paintable_snapshot (GdkPaintable *paintable,
GdkSnapshot *snapshot,
double width,
double height)
{
CcBackgroundPaintable *self = CC_BACKGROUND_PAINTABLE (paintable);
gboolean is_rtl;
if (!self->dark_texture)
{
gdk_paintable_snapshot (self->texture, snapshot, width, height);
return;
}
if (!self->texture)
{
gdk_paintable_snapshot (self->dark_texture, snapshot, width, height);
return;
}
is_rtl = self->text_direction == GTK_TEXT_DIR_RTL;
gtk_snapshot_push_clip (GTK_SNAPSHOT (snapshot),
&GRAPHENE_RECT_INIT (is_rtl ? width / 2.0f : 0.0f,
0.0f,
width / 2.0f,
height));
gdk_paintable_snapshot (self->texture, snapshot, width, height);
gtk_snapshot_pop (GTK_SNAPSHOT (snapshot));
gtk_snapshot_push_clip (GTK_SNAPSHOT (snapshot),
&GRAPHENE_RECT_INIT (is_rtl ? 0.0f : width / 2.0f,
0.0f,
width / 2.0f,
height));
gdk_paintable_snapshot (self->dark_texture, snapshot, width, height);
gtk_snapshot_pop (GTK_SNAPSHOT (snapshot));
}
static int
cc_background_paintable_get_intrinsic_width (GdkPaintable *paintable)
{
CcBackgroundPaintable *self = CC_BACKGROUND_PAINTABLE (paintable);
GdkPaintable *valid_texture = self->texture ? self->texture : self->dark_texture;
return gdk_paintable_get_intrinsic_width (valid_texture) / self->scale_factor;
}
static int
cc_background_paintable_get_intrinsic_height (GdkPaintable *paintable)
{
CcBackgroundPaintable *self = CC_BACKGROUND_PAINTABLE (paintable);
GdkPaintable *valid_texture = self->texture ? self->texture : self->dark_texture;
return gdk_paintable_get_intrinsic_height (valid_texture) / self->scale_factor;
}
static double
cc_background_paintable_get_intrinsic_aspect_ratio (GdkPaintable *paintable)
{
CcBackgroundPaintable *self = CC_BACKGROUND_PAINTABLE (paintable);
GdkPaintable *valid_texture = self->texture ? self->texture : self->dark_texture;
return gdk_paintable_get_intrinsic_aspect_ratio (valid_texture);
}
static void
cc_background_paintable_paintable_init (GdkPaintableInterface *iface)
{
iface->snapshot = cc_background_paintable_snapshot;
iface->get_intrinsic_width = cc_background_paintable_get_intrinsic_width;
iface->get_intrinsic_height = cc_background_paintable_get_intrinsic_height;
iface->get_intrinsic_aspect_ratio = cc_background_paintable_get_intrinsic_aspect_ratio;
}
/* Workaround for a typo in libgnome-desktop, see gnome-desktop!160 */
#define G_TYPE_INSTANCE_CHECK_TYPE G_TYPE_CHECK_INSTANCE_TYPE
CcBackgroundPaintable *
cc_background_paintable_new (GnomeDesktopThumbnailFactory *thumbnail_factory,
CcBackgroundItem *item,
CcBackgroundPaintFlags paint_flags,
int width,
int height)
{
g_return_val_if_fail (GNOME_DESKTOP_IS_THUMBNAIL_FACTORY (thumbnail_factory), NULL);
g_return_val_if_fail (CC_IS_BACKGROUND_ITEM (item), NULL);
return g_object_new (CC_TYPE_BACKGROUND_PAINTABLE,
"thumbnail-factory", thumbnail_factory,
"item", item,
"paint-flags", paint_flags,
"width", width,
"height", height,
NULL);
}