From 5b214404a170582f380001e52d714d04f18614df Mon Sep 17 00:00:00 2001 From: Georges Basile Stavracas Neto Date: Wed, 22 May 2019 18:55:17 -0300 Subject: [PATCH] background: Move preview to CcBackgroundPreview This is a dedicate class to generate the preview. Not only it renders the pixbuf of the wallpaper, but it also adds lock screen or desktop frames on top of it. It also monitors the time to keep the lock screen preview label always updated. --- panels/background/background.gresource.xml | 2 + panels/background/cc-background-panel.c | 87 +----- panels/background/cc-background-panel.ui | 80 +---- panels/background/cc-background-preview.c | 322 +++++++++++++++++++++ panels/background/cc-background-preview.h | 36 +++ panels/background/cc-background-preview.ui | 141 +++++++++ panels/background/meson.build | 3 + panels/background/preview.css | 27 ++ 8 files changed, 542 insertions(+), 156 deletions(-) create mode 100644 panels/background/cc-background-preview.c create mode 100644 panels/background/cc-background-preview.h create mode 100644 panels/background/cc-background-preview.ui create mode 100644 panels/background/preview.css diff --git a/panels/background/background.gresource.xml b/panels/background/background.gresource.xml index 7fa4dbac6..c715aad9a 100644 --- a/panels/background/background.gresource.xml +++ b/panels/background/background.gresource.xml @@ -3,5 +3,7 @@ cc-background-chooser.ui cc-background-panel.ui + cc-background-preview.ui + preview.css diff --git a/panels/background/cc-background-panel.c b/panels/background/cc-background-panel.c index c00e69c25..c4d32a1ec 100644 --- a/panels/background/cc-background-panel.c +++ b/panels/background/cc-background-panel.c @@ -31,6 +31,7 @@ #include "cc-background-chooser.h" #include "cc-background-item.h" +#include "cc-background-preview.h" #include "cc-background-resources.h" #include "cc-background-xml.h" @@ -61,10 +62,8 @@ struct _CcBackgroundPanel GCancellable *copy_cancellable; GtkWidget *bottom_hbox; - GtkWidget *desktop_drawing_area; - GtkWidget *desktop_slide_image; - GtkWidget *lock_drawing_area; - GtkWidget *lock_slide_image; + CcBackgroundPreview *desktop_preview; + CcBackgroundPreview *lock_screen_preview; GtkWidget *spinner; GtkWidget *chooser; @@ -72,41 +71,6 @@ struct _CcBackgroundPanel CC_PANEL_REGISTER (CcBackgroundPanel, cc_background_panel) -static GdkPixbuf* -get_or_create_cached_pixbuf (CcBackgroundPanel *panel, - GtkWidget *widget, - CcBackgroundItem *background) -{ - const gint preview_width = 309; - const gint preview_height = 168; - gint scale_factor; - GdkPixbuf *pixbuf; - - scale_factor = gtk_widget_get_scale_factor (widget); - pixbuf = cc_background_item_get_frame_thumbnail (background, - panel->thumb_factory, - preview_width, - preview_height, - scale_factor, - -2, TRUE); - - return pixbuf; -} - -static void -update_display_preview (CcBackgroundPanel *panel, - GtkWidget *widget, - cairo_t *cr, - CcBackgroundItem *background) -{ - g_autoptr(GdkPixbuf) pixbuf = NULL; - - pixbuf = get_or_create_cached_pixbuf (panel, widget, background); - - gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0); - cairo_paint (cr); -} - static CcBackgroundItem * get_current_background (CcBackgroundPanel *panel, GSettings *settings) @@ -122,7 +86,6 @@ update_preview (CcBackgroundPanel *panel, GSettings *settings, CcBackgroundItem *item) { - gboolean changes_with_time; CcBackgroundItem *current_background; current_background = get_current_background (panel, settings); @@ -138,23 +101,10 @@ update_preview (CcBackgroundPanel *panel, cc_background_item_load (current_background, NULL); } - changes_with_time = FALSE; - - if (current_background) - { - changes_with_time = cc_background_item_changes_with_time (current_background); - } - if (settings == panel->settings) - { - gtk_widget_set_visible (panel->desktop_slide_image, changes_with_time); - gtk_widget_queue_draw (panel->desktop_drawing_area); - } + cc_background_preview_set_item (panel->desktop_preview, current_background); else - { - gtk_widget_set_visible (panel->lock_slide_image, changes_with_time); - gtk_widget_queue_draw (panel->lock_drawing_area); - } + cc_background_preview_set_item (panel->lock_screen_preview, current_background); } static gchar * @@ -439,24 +389,6 @@ on_chooser_background_chosen_cb (CcBackgroundChooser *chooser, set_background (self, self->lock_settings, item); } -static gboolean -on_preview_draw_cb (GtkWidget *widget, - cairo_t *cr, - CcBackgroundPanel *panel) -{ - update_display_preview (panel, widget, cr, panel->current_background); - return TRUE; -} - -static gboolean -on_lock_preview_draw_cb (GtkWidget *widget, - cairo_t *cr, - CcBackgroundPanel *panel) -{ - update_display_preview (panel, widget, cr, panel->current_lock_background); - return TRUE; -} - static const char * cc_background_panel_get_help_uri (CcPanel *panel) { @@ -500,6 +432,7 @@ cc_background_panel_class_init (CcBackgroundPanelClass *klass) GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); g_type_ensure (CC_TYPE_BACKGROUND_CHOOSER); + g_type_ensure (CC_TYPE_BACKGROUND_PREVIEW); panel_class->get_help_uri = cc_background_panel_get_help_uri; @@ -509,14 +442,10 @@ cc_background_panel_class_init (CcBackgroundPanelClass *klass) gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/background/cc-background-panel.ui"); gtk_widget_class_bind_template_child (widget_class, CcBackgroundPanel, bottom_hbox); - gtk_widget_class_bind_template_child (widget_class, CcBackgroundPanel, desktop_drawing_area); - gtk_widget_class_bind_template_child (widget_class, CcBackgroundPanel, desktop_slide_image); - gtk_widget_class_bind_template_child (widget_class, CcBackgroundPanel, lock_drawing_area); - gtk_widget_class_bind_template_child (widget_class, CcBackgroundPanel, lock_slide_image); + gtk_widget_class_bind_template_child (widget_class, CcBackgroundPanel, desktop_preview); + gtk_widget_class_bind_template_child (widget_class, CcBackgroundPanel, lock_screen_preview); gtk_widget_class_bind_template_callback (widget_class, on_chooser_background_chosen_cb); - gtk_widget_class_bind_template_callback (widget_class, on_lock_preview_draw_cb); - gtk_widget_class_bind_template_callback (widget_class, on_preview_draw_cb); } static void diff --git a/panels/background/cc-background-panel.ui b/panels/background/cc-background-panel.ui index 11a4fc925..d3c2aa884 100644 --- a/panels/background/cc-background-panel.ui +++ b/panels/background/cc-background-panel.ui @@ -25,13 +25,10 @@ center vertical - - 310 - 170 + True False center - @@ -39,37 +36,6 @@ True False 12 - - - True - False - center - 12 - 2 - - - True - False - slideshow-symbolic - - - - - True - False - - - - - - - False - 0 - Changes throughout the day - - - - @@ -82,51 +48,11 @@ start center - - 310 - 170 + True False + True center - - - - - - True - False - 12 - - - True - False - center - 12 - 2 - - - True - False - slideshow-symbolic - - - - - True - False - - - - - - - False - 0 - Changes throughout the day - - - - diff --git a/panels/background/cc-background-preview.c b/panels/background/cc-background-preview.c new file mode 100644 index 000000000..f2f986676 --- /dev/null +++ b/panels/background/cc-background-preview.c @@ -0,0 +1,322 @@ +/* cc-background-preview.c + * + * Copyright 2019 Georges Basile Stavracas Neto + * + * 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 3 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 . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include "cc-background-preview.h" + +struct _CcBackgroundPreview +{ + GtkBox parent; + + GtkLabel *desktop_clock_label; + GtkWidget *drawing_area; + GtkLabel *lock_screen_label; + GtkStack *stack; + + GnomeDesktopThumbnailFactory *thumbnail_factory; + + CcBackgroundItem *item; + GSettings *desktop_settings; + + guint lock_screen_time_timeout_id; + gboolean is_lock_screen; + GDateTime *previous_time; + gboolean is_24h_format; +}; + +G_DEFINE_TYPE (CcBackgroundPreview, cc_background_preview, GTK_TYPE_BOX) + +enum +{ + PROP_0, + PROP_IS_LOCK_SCREEN, + PROP_ITEM, + N_PROPS +}; + +static GParamSpec *properties [N_PROPS]; + +/* Auxiliary methods */ + +static void +update_lock_screen_label (CcBackgroundPreview *self, + gboolean force) +{ + g_autoptr(GDateTime) now = NULL; + g_autofree gchar *label = NULL; + + now = g_date_time_new_now_local (); + + /* Don't update the label if the hour:minute pair did not change */ + if (!force && self->previous_time && + g_date_time_get_hour (now) == g_date_time_get_hour (self->previous_time) && + g_date_time_get_minute (now) == g_date_time_get_minute (self->previous_time)) + { + return; + } + + if (self->is_24h_format) + label = g_date_time_format (now, "%R"); + else + label = g_date_time_format (now, "%I:%M %p"); + + gtk_label_set_label (self->lock_screen_label, label); + gtk_label_set_label (self->desktop_clock_label, label); + + g_clear_pointer (&self->previous_time, g_date_time_unref); + self->previous_time = g_steal_pointer (&now); +} + +static void +update_clock_format (CcBackgroundPreview *self) +{ + g_autofree gchar *clock_format = NULL; + gboolean is_24h_format; + + clock_format = g_settings_get_string (self->desktop_settings, "clock-format"); + is_24h_format = g_strcmp0 (clock_format, "24h") == 0; + + if (is_24h_format != self->is_24h_format) + { + self->is_24h_format = is_24h_format; + update_lock_screen_label (self, TRUE); + } +} + +static void +load_custom_css (CcBackgroundPreview *self) +{ + g_autoptr(GtkCssProvider) provider = NULL; + + /* use custom CSS */ + provider = gtk_css_provider_new (); + gtk_css_provider_load_from_resource (provider, "/org/gnome/control-center/background/preview.css"); + gtk_style_context_add_provider_for_screen (gdk_screen_get_default (), + GTK_STYLE_PROVIDER (provider), + GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + +} + +static gboolean +update_clock_cb (gpointer data) +{ + CcBackgroundPreview *self = data; + + update_lock_screen_label (self, FALSE); + + return G_SOURCE_CONTINUE; +} + +static void +start_monitor_time (CcBackgroundPreview *self) +{ + if (self->lock_screen_time_timeout_id > 0) + return; + + self->lock_screen_time_timeout_id = g_timeout_add_seconds (1, + update_clock_cb, + self); +} + +static void +stop_monitor_time (CcBackgroundPreview *self) +{ + if (self->lock_screen_time_timeout_id > 0) + { + g_source_remove (self->lock_screen_time_timeout_id); + self->lock_screen_time_timeout_id = 0; + } +} + + +/* Callbacks */ + +static gboolean +on_preview_draw_cb (GtkWidget *widget, + cairo_t *cr, + CcBackgroundPreview *self) +{ + g_autoptr(GdkPixbuf) pixbuf = NULL; + GtkAllocation allocation; + gint scale_factor; + + if (!self->item) + return FALSE; + + scale_factor = gtk_widget_get_scale_factor (widget); + gtk_widget_get_allocation (widget, &allocation); + pixbuf = cc_background_item_get_frame_thumbnail (self->item, + self->thumbnail_factory, + allocation.width, + allocation.height, + scale_factor, + 0, + TRUE); + + + gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0); + cairo_paint (cr); + + return TRUE; +} + +/* GObject overrides */ + +static void +cc_background_preview_finalize (GObject *object) +{ + CcBackgroundPreview *self = (CcBackgroundPreview *)object; + + g_clear_object (&self->desktop_settings); + g_clear_object (&self->item); + g_clear_object (&self->thumbnail_factory); + + g_clear_pointer (&self->previous_time, g_date_time_unref); + + stop_monitor_time (self); + + G_OBJECT_CLASS (cc_background_preview_parent_class)->finalize (object); +} + +static void +cc_background_preview_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + CcBackgroundPreview *self = CC_BACKGROUND_PREVIEW (object); + + switch (prop_id) + { + case PROP_IS_LOCK_SCREEN: + g_value_set_boolean (value, self->is_lock_screen); + break; + + case PROP_ITEM: + g_value_set_object (value, self->item); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +cc_background_preview_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + CcBackgroundPreview *self = CC_BACKGROUND_PREVIEW (object); + + switch (prop_id) + { + case PROP_IS_LOCK_SCREEN: + self->is_lock_screen = g_value_get_boolean (value); + gtk_stack_set_visible_child_name (self->stack, + self->is_lock_screen ? "lock" : "desktop"); + if (self->is_lock_screen) + start_monitor_time (self); + else + stop_monitor_time (self); + break; + + case PROP_ITEM: + cc_background_preview_set_item (self, g_value_get_object (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +cc_background_preview_class_init (CcBackgroundPreviewClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + object_class->finalize = cc_background_preview_finalize; + object_class->get_property = cc_background_preview_get_property; + object_class->set_property = cc_background_preview_set_property; + + properties[PROP_IS_LOCK_SCREEN] = g_param_spec_boolean ("is-lock-screen", + "Lock screen", + "Whether the preview is of the lock screen", + FALSE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + properties[PROP_ITEM] = g_param_spec_object ("item", + "Item", + "Background item", + CC_TYPE_BACKGROUND_ITEM, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, N_PROPS, properties); + + gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/background/cc-background-preview.ui"); + + gtk_widget_class_bind_template_child (widget_class, CcBackgroundPreview, desktop_clock_label); + gtk_widget_class_bind_template_child (widget_class, CcBackgroundPreview, drawing_area); + gtk_widget_class_bind_template_child (widget_class, CcBackgroundPreview, lock_screen_label); + gtk_widget_class_bind_template_child (widget_class, CcBackgroundPreview, stack); + + gtk_widget_class_bind_template_callback (widget_class, on_preview_draw_cb); +} + +static void +cc_background_preview_init (CcBackgroundPreview *self) +{ + gtk_widget_init_template (GTK_WIDGET (self)); + + self->thumbnail_factory = gnome_desktop_thumbnail_factory_new (GNOME_DESKTOP_THUMBNAIL_SIZE_LARGE); + self->desktop_settings = g_settings_new ("org.gnome.desktop.interface"); + + g_signal_connect_object (self->desktop_settings, + "changed::clock-format", + G_CALLBACK (update_clock_format), + self, + G_CONNECT_SWAPPED); + + update_clock_format (self); + load_custom_css (self); +} + +CcBackgroundItem* +cc_background_preview_get_item (CcBackgroundPreview *self) +{ + g_return_val_if_fail (CC_IS_BACKGROUND_PREVIEW (self), NULL); + + return self->item; +} + +void +cc_background_preview_set_item (CcBackgroundPreview *self, + CcBackgroundItem *item) +{ + g_return_if_fail (CC_IS_BACKGROUND_PREVIEW (self)); + g_return_if_fail (CC_IS_BACKGROUND_ITEM (item)); + + if (!g_set_object (&self->item, item)) + return; + + gtk_widget_queue_draw (self->drawing_area); + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ITEM]); +} diff --git a/panels/background/cc-background-preview.h b/panels/background/cc-background-preview.h new file mode 100644 index 000000000..e8e20d49d --- /dev/null +++ b/panels/background/cc-background-preview.h @@ -0,0 +1,36 @@ +/* cc-background-preview.h + * + * Copyright 2019 Georges Basile Stavracas Neto + * + * 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 3 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 . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#include + +#include "cc-background-item.h" + +G_BEGIN_DECLS + +#define CC_TYPE_BACKGROUND_PREVIEW (cc_background_preview_get_type()) +G_DECLARE_FINAL_TYPE (CcBackgroundPreview, cc_background_preview, CC, BACKGROUND_PREVIEW, GtkBox) + +CcBackgroundItem* cc_background_preview_get_item (CcBackgroundPreview *self); +void cc_background_preview_set_item (CcBackgroundPreview *self, + CcBackgroundItem *item); + +G_END_DECLS diff --git a/panels/background/cc-background-preview.ui b/panels/background/cc-background-preview.ui new file mode 100644 index 000000000..c20b2c3e4 --- /dev/null +++ b/panels/background/cc-background-preview.ui @@ -0,0 +1,141 @@ + + + + + diff --git a/panels/background/meson.build b/panels/background/meson.build index 2585808eb..7482431f3 100644 --- a/panels/background/meson.build +++ b/panels/background/meson.build @@ -62,6 +62,8 @@ common_sources += gnome.mkenums( resource_data = files( 'cc-background-chooser.ui', 'cc-background-panel.ui', + 'cc-background-preview.ui', + 'preview.css', ) common_sources += gnome.compile_resources( @@ -81,6 +83,7 @@ sources = common_sources + files( 'cc-background-grilo-miner.c', 'cc-background-item.c', 'cc-background-panel.c', + 'cc-background-preview.c', 'cc-background-xml.c', ) diff --git a/panels/background/preview.css b/panels/background/preview.css new file mode 100644 index 000000000..f4966eb24 --- /dev/null +++ b/panels/background/preview.css @@ -0,0 +1,27 @@ +frame.desktop-preview { + min-height: 10px; + padding: 0 4px; + background-color: black; +} + +frame.desktop-preview image { + color: white; +} + +frame.desktop-preview label { + color: white; + font-weight: bold; + font-size: 6px; +} + +frame.lock-screen-preview { + border: solid rgba(0, 0, 0, 0.33); + border-width: 10px 0 0 0; +} + +frame.lock-screen-preview label { + color: white; + font-weight: bold; + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6); + font-size: 1.2em; +}