diff options
Diffstat (limited to 'panels/background/cc-background-chooser.c')
-rw-r--r-- | panels/background/cc-background-chooser.c | 386 |
1 files changed, 386 insertions, 0 deletions
diff --git a/panels/background/cc-background-chooser.c b/panels/background/cc-background-chooser.c new file mode 100644 index 0000000..b28a5ee --- /dev/null +++ b/panels/background/cc-background-chooser.c @@ -0,0 +1,386 @@ +/* cc-background-chooser.c + * + * Copyright 2019 Georges Basile Stavracas Neto <georges.stavracas@gmail.com> + * + * 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 <http://www.gnu.org/licenses/>. + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#undef G_LOG_DOMAIN +#define G_LOG_DOMAIN "cc-background-chooser" + +#include <glib/gi18n.h> +#include <libgnome-desktop/gnome-desktop-thumbnail.h> + +#include "bg-colors-source.h" +#include "bg-pictures-source.h" +#include "bg-recent-source.h" +#include "bg-wallpapers-source.h" +#include "cc-background-chooser.h" + +struct _CcBackgroundChooser +{ + GtkBox parent; + + GtkFlowBox *flowbox; + GtkWidget *recent_box; + GtkFlowBox *recent_flowbox; + + gboolean recent_selected; + + BgWallpapersSource *wallpapers_source; + BgRecentSource *recent_source; +}; + +G_DEFINE_TYPE (CcBackgroundChooser, cc_background_chooser, GTK_TYPE_BOX) + +enum +{ + BACKGROUND_CHOSEN, + N_SIGNALS, +}; + +static guint signals [N_SIGNALS]; + +static void +emit_background_chosen (CcBackgroundChooser *self) +{ + g_autoptr(GList) list = NULL; + CcBackgroundItem *item; + GtkFlowBox *flowbox; + + flowbox = self->recent_selected ? self->recent_flowbox : self->flowbox; + list = gtk_flow_box_get_selected_children (flowbox); + g_assert (g_list_length (list) == 1); + + item = g_object_get_data (list->data, "item"); + + g_signal_emit (self, signals[BACKGROUND_CHOSEN], 0, item); +} + +static void +on_delete_background_clicked_cb (GtkButton *button, + BgRecentSource *source) +{ + GtkWidget *parent; + CcBackgroundItem *item; + + parent = gtk_widget_get_parent (gtk_widget_get_parent (GTK_WIDGET (button))); + g_assert (GTK_IS_FLOW_BOX_CHILD (parent)); + + item = g_object_get_data (G_OBJECT (parent), "item"); + + bg_recent_source_remove_item (source, item); +} + +static GtkWidget* +create_widget_func (gpointer model_item, + gpointer user_data) +{ + g_autoptr(GdkPixbuf) pixbuf = NULL; + CcBackgroundItem *item; + GtkWidget *overlay; + GtkWidget *child; + GtkWidget *image; + GtkWidget *icon; + GtkWidget *button_image; + GtkWidget *button = NULL; + BgSource *source; + + source = BG_SOURCE (user_data); + item = CC_BACKGROUND_ITEM (model_item); + pixbuf = cc_background_item_get_thumbnail (item, + bg_source_get_thumbnail_factory (source), + bg_source_get_thumbnail_width (source), + bg_source_get_thumbnail_height (source), + bg_source_get_scale_factor (source)); + image = gtk_image_new_from_pixbuf (pixbuf); + gtk_widget_show (image); + + icon = g_object_new (GTK_TYPE_IMAGE, + "icon-name", "slideshow-emblem", + "pixel-size", 16, + "margin", 8, + "halign", GTK_ALIGN_END, + "valign", GTK_ALIGN_END, + "visible", cc_background_item_changes_with_time (item), + NULL); + gtk_style_context_add_class (gtk_widget_get_style_context (icon), "slideshow-emblem"); + + + if (BG_IS_RECENT_SOURCE (source)) + { + button_image = gtk_image_new_from_icon_name ("window-close-symbolic", GTK_ICON_SIZE_BUTTON); + button = g_object_new (GTK_TYPE_BUTTON, + "image", button_image, + "halign", GTK_ALIGN_END, + "valign", GTK_ALIGN_START, + "margin", 6, + "visible", TRUE, + NULL); + + gtk_style_context_add_class (gtk_widget_get_style_context (button), "osd"); + gtk_style_context_add_class (gtk_widget_get_style_context (button), "remove-button"); + + g_signal_connect (button, + "clicked", + G_CALLBACK (on_delete_background_clicked_cb), + source); + } + + overlay = gtk_overlay_new (); + gtk_container_add (GTK_CONTAINER (overlay), image); + gtk_overlay_add_overlay (GTK_OVERLAY (overlay), icon); + if (button) + gtk_overlay_add_overlay (GTK_OVERLAY (overlay), button); + gtk_widget_show (overlay); + + child = g_object_new (GTK_TYPE_FLOW_BOX_CHILD, + "halign", GTK_ALIGN_CENTER, + "valign", GTK_ALIGN_CENTER, + NULL); + gtk_container_add (GTK_CONTAINER (child), overlay); + gtk_widget_show (child); + + g_object_set_data_full (G_OBJECT (child), "item", g_object_ref (item), g_object_unref); + + return child; +} + +static void +update_recent_visibility (CcBackgroundChooser *self) +{ + GListStore *store; + gboolean has_items; + + store = bg_source_get_liststore (BG_SOURCE (self->recent_source)); + has_items = g_list_model_get_n_items (G_LIST_MODEL (store)) != 0; + + gtk_widget_set_visible (self->recent_box, has_items); +} + +static void +setup_flowbox (CcBackgroundChooser *self) +{ + GListStore *store; + + store = bg_source_get_liststore (BG_SOURCE (self->wallpapers_source)); + + gtk_flow_box_bind_model (self->flowbox, + G_LIST_MODEL (store), + create_widget_func, + self->wallpapers_source, + NULL); + + store = bg_source_get_liststore (BG_SOURCE (self->recent_source)); + + gtk_flow_box_bind_model (self->recent_flowbox, + G_LIST_MODEL (store), + create_widget_func, + self->recent_source, + NULL); + + update_recent_visibility (self); + g_signal_connect_object (store, + "items-changed", + G_CALLBACK (update_recent_visibility), + self, + G_CONNECT_SWAPPED); +} + +static void +on_item_activated_cb (GtkFlowBox *flowbox, + GtkFlowBoxChild *child, + CcBackgroundChooser *self) +{ + self->recent_selected = flowbox == self->recent_flowbox; + if (self->recent_selected) + gtk_flow_box_unselect_all (self->flowbox); + else + gtk_flow_box_unselect_all (self->recent_flowbox); + emit_background_chosen (self); +} + +static void +on_file_chooser_response_cb (GtkDialog *filechooser, + gint response, + CcBackgroundChooser *self) +{ + if (response == GTK_RESPONSE_ACCEPT) + { + g_autoptr(GSList) filenames = NULL; + GSList *l; + + filenames = gtk_file_chooser_get_filenames (GTK_FILE_CHOOSER (filechooser)); + for (l = filenames; l != NULL; l = l->next) + { + g_autofree gchar *filename = l->data; + + bg_recent_source_add_file (self->recent_source, filename); + } + } + + gtk_widget_destroy (GTK_WIDGET (filechooser)); +} + +static void +on_file_chooser_selection_changed_cb (GtkFileChooser *chooser, + GnomeDesktopThumbnailFactory *thumbnail_factory) +{ + g_autofree gchar *uri = NULL; + + uri = gtk_file_chooser_get_uri (chooser); + + if (uri) + { + g_autoptr(GFileInfo) file_info = NULL; + g_autoptr(GdkPixbuf) pixbuf = NULL; + g_autofree gchar *mime_type = NULL; + g_autoptr(GFile) file = NULL; + GtkWidget *preview; + + preview = gtk_file_chooser_get_preview_widget (chooser); + + file = g_file_new_for_uri (uri); + file_info = g_file_query_info (file, + "standard::*", + G_FILE_QUERY_INFO_NONE, + NULL, + NULL); + + if (file_info && g_file_info_get_file_type (file_info) != G_FILE_TYPE_DIRECTORY) + mime_type = g_strdup (g_file_info_get_content_type (file_info)); + + if (mime_type) + { + pixbuf = gnome_desktop_thumbnail_factory_generate_thumbnail (thumbnail_factory, + uri, + mime_type); + } + + gtk_dialog_set_response_sensitive (GTK_DIALOG (chooser), + GTK_RESPONSE_ACCEPT, + pixbuf != NULL); + + if (pixbuf) + gtk_image_set_from_pixbuf (GTK_IMAGE (preview), pixbuf); + else + gtk_image_set_from_icon_name (GTK_IMAGE (preview), "dialog-question", GTK_ICON_SIZE_DIALOG); + } + + gtk_file_chooser_set_preview_widget_active (chooser, TRUE); +} + +/* GObject overrides */ + +static void +cc_background_chooser_finalize (GObject *object) +{ + CcBackgroundChooser *self = (CcBackgroundChooser *)object; + + g_clear_object (&self->recent_source); + g_clear_object (&self->wallpapers_source); + + G_OBJECT_CLASS (cc_background_chooser_parent_class)->finalize (object); +} + +static void +cc_background_chooser_class_init (CcBackgroundChooserClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + object_class->finalize = cc_background_chooser_finalize; + + signals[BACKGROUND_CHOSEN] = g_signal_new ("background-chosen", + CC_TYPE_BACKGROUND_CHOOSER, + G_SIGNAL_RUN_FIRST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, + 1, + CC_TYPE_BACKGROUND_ITEM); + + gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/background/cc-background-chooser.ui"); + + gtk_widget_class_bind_template_child (widget_class, CcBackgroundChooser, flowbox); + gtk_widget_class_bind_template_child (widget_class, CcBackgroundChooser, recent_box); + gtk_widget_class_bind_template_child (widget_class, CcBackgroundChooser, recent_flowbox); + + gtk_widget_class_bind_template_callback (widget_class, on_item_activated_cb); +} + +static void +cc_background_chooser_init (CcBackgroundChooser *self) +{ + gtk_widget_init_template (GTK_WIDGET (self)); + + self->recent_source = bg_recent_source_new (GTK_WIDGET (self)); + self->wallpapers_source = bg_wallpapers_source_new (GTK_WIDGET (self)); + setup_flowbox (self); +} + +void +cc_background_chooser_select_file (CcBackgroundChooser *self) +{ + g_autoptr(GnomeDesktopThumbnailFactory) factory = NULL; + GtkFileFilter *filter; + GtkWidget *filechooser; + GtkWindow *toplevel; + GtkWidget *preview; + + g_return_if_fail (CC_IS_BACKGROUND_CHOOSER (self)); + + toplevel = (GtkWindow*) gtk_widget_get_toplevel (GTK_WIDGET (self)); + filechooser = gtk_file_chooser_dialog_new (_("Select a picture"), + toplevel, + GTK_FILE_CHOOSER_ACTION_OPEN, + _("_Cancel"), GTK_RESPONSE_CANCEL, + _("_Open"), GTK_RESPONSE_ACCEPT, + NULL); + gtk_window_set_modal (GTK_WINDOW (filechooser), TRUE); + + preview = gtk_image_new (); + gtk_widget_set_size_request (preview, 154, -1); + gtk_file_chooser_set_preview_widget (GTK_FILE_CHOOSER (filechooser), preview); + gtk_file_chooser_set_use_preview_label (GTK_FILE_CHOOSER (filechooser), FALSE); + gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (filechooser), TRUE); + gtk_widget_show (preview); + + factory = gnome_desktop_thumbnail_factory_new (GNOME_DESKTOP_THUMBNAIL_SIZE_LARGE); + g_signal_connect_after (filechooser, + "selection-changed", + G_CALLBACK (on_file_chooser_selection_changed_cb), + factory); + + g_object_set_data_full (G_OBJECT (filechooser), + "factory", + g_object_ref (factory), + g_object_unref); + + filter = gtk_file_filter_new (); + gtk_file_filter_add_pixbuf_formats (filter); + gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (filechooser), filter); + + gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (filechooser), + g_get_user_special_dir (G_USER_DIRECTORY_PICTURES)); + + g_signal_connect_object (filechooser, + "response", + G_CALLBACK (on_file_chooser_response_cb), + self, + 0); + + gtk_window_present (GTK_WINDOW (filechooser)); +} |