summaryrefslogtreecommitdiffstats
path: root/panels/background/cc-background-chooser.c
diff options
context:
space:
mode:
Diffstat (limited to 'panels/background/cc-background-chooser.c')
-rw-r--r--panels/background/cc-background-chooser.c337
1 files changed, 337 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..8d24e45
--- /dev/null
+++ b/panels/background/cc-background-chooser.c
@@ -0,0 +1,337 @@
+/* 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-recent-source.h"
+#include "bg-wallpapers-source.h"
+#include "cc-background-chooser.h"
+#include "cc-background-paintable.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 void
+direction_changed_cb (GtkWidget *widget,
+ GtkTextDirection *previous_direction,
+ GdkPaintable *paintable)
+{
+ g_object_set (paintable,
+ "text-direction", gtk_widget_get_direction (widget),
+ NULL);
+}
+
+static GtkWidget*
+create_widget_func (gpointer model_item,
+ gpointer user_data)
+{
+ g_autoptr(CcBackgroundPaintable) paintable = NULL;
+ CcBackgroundItem *item;
+ GtkWidget *overlay;
+ GtkWidget *child;
+ GtkWidget *picture;
+ GtkWidget *icon;
+ GtkWidget *check;
+ GtkWidget *button = NULL;
+ BgSource *source;
+
+ source = BG_SOURCE (user_data);
+ item = CC_BACKGROUND_ITEM (model_item);
+
+ paintable = cc_background_paintable_new (source, item);
+
+ picture = gtk_picture_new_for_paintable (GDK_PAINTABLE (paintable));
+ gtk_picture_set_can_shrink (GTK_PICTURE (picture), FALSE);
+
+ g_object_bind_property (picture, "scale-factor",
+ paintable, "scale-factor", G_BINDING_SYNC_CREATE);
+ g_signal_connect_object (picture, "direction-changed",
+ G_CALLBACK (direction_changed_cb), paintable, 0);
+
+ icon = gtk_image_new_from_icon_name ("slideshow-symbolic");
+ gtk_widget_set_halign (icon, GTK_ALIGN_START);
+ gtk_widget_set_valign (icon, GTK_ALIGN_END);
+ gtk_widget_set_visible (icon, cc_background_item_changes_with_time (item));
+ gtk_widget_add_css_class (icon, "slideshow-icon");
+
+ check = gtk_image_new_from_icon_name ("background-selected-symbolic");
+ gtk_widget_set_halign (check, GTK_ALIGN_END);
+ gtk_widget_set_valign (check, GTK_ALIGN_END);
+ gtk_widget_add_css_class (check, "selected-check");
+
+ if (BG_IS_RECENT_SOURCE (source))
+ {
+ button = gtk_button_new_from_icon_name ("window-close-symbolic");
+ gtk_widget_set_halign (button, GTK_ALIGN_END);
+ gtk_widget_set_valign (button, GTK_ALIGN_START);
+
+ gtk_widget_add_css_class (button, "osd");
+ gtk_widget_add_css_class (button, "circular");
+ gtk_widget_add_css_class (button, "remove-button");
+
+ g_signal_connect (button,
+ "clicked",
+ G_CALLBACK (on_delete_background_clicked_cb),
+ source);
+ }
+
+ overlay = gtk_overlay_new ();
+ gtk_widget_set_overflow (overlay, GTK_OVERFLOW_HIDDEN);
+ gtk_widget_add_css_class (overlay, "background-thumbnail");
+ gtk_overlay_set_child (GTK_OVERLAY (overlay), picture);
+ gtk_overlay_add_overlay (GTK_OVERLAY (overlay), icon);
+ gtk_overlay_add_overlay (GTK_OVERLAY (overlay), check);
+ if (button)
+ gtk_overlay_add_overlay (GTK_OVERLAY (overlay), button);
+ gtk_accessible_update_property (GTK_ACCESSIBLE (overlay),
+ GTK_ACCESSIBLE_PROPERTY_LABEL,
+ cc_background_item_get_name (item),
+ -1);
+
+
+ child = gtk_flow_box_child_new ();
+ gtk_widget_set_halign (child, GTK_ALIGN_CENTER);
+ gtk_widget_set_valign (child, GTK_ALIGN_CENTER);
+ gtk_flow_box_child_set_child (GTK_FLOW_BOX_CHILD (child), overlay);
+
+ 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(GListModel) files = NULL;
+ guint i;
+
+ files = gtk_file_chooser_get_files (GTK_FILE_CHOOSER (filechooser));
+ for (i = 0; i < g_list_model_get_n_items (files); i++)
+ {
+ g_autoptr(GFile) file = g_list_model_get_item (files, i);
+ g_autofree gchar *filename = g_file_get_path (file);
+
+ bg_recent_source_add_file (self->recent_source, filename);
+ }
+ }
+
+ gtk_window_destroy (GTK_WINDOW (filechooser));
+}
+
+/* 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(GFile) pictures_folder = NULL;
+ GtkFileFilter *filter;
+ GtkWidget *filechooser;
+ GtkWindow *toplevel;
+
+ g_return_if_fail (CC_IS_BACKGROUND_CHOOSER (self));
+
+ toplevel = (GtkWindow*) gtk_widget_get_native (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);
+
+ 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_select_multiple (GTK_FILE_CHOOSER (filechooser), TRUE);
+
+ pictures_folder = g_file_new_for_path (g_get_user_special_dir (G_USER_DIRECTORY_PICTURES));
+ gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (filechooser),
+ pictures_folder,
+ NULL);
+
+ g_signal_connect_object (filechooser,
+ "response",
+ G_CALLBACK (on_file_chooser_response_cb),
+ self,
+ 0);
+
+ gtk_window_present (GTK_WINDOW (filechooser));
+}