From 3d06d8b6dd1a26c26f34816a347524aeff3430b2 Mon Sep 17 00:00:00 2001 From: lukefromdc Date: Fri, 15 Dec 2023 02:06:53 -0500 Subject: Manage desktop backgrounds when running in wayland *Draw the background on the desktop window, using the same code as on navigation windows to bypass the no-root-window issue. *Works from caja's "Change Desktop Background" menu item, from caja-extensions "set as wallpaper" and with changing the background in dconf-editor. *All background options available in x11 supported in wayland, UI is new for wayland *Apply changes immediately, keep the dialog open until closed by user *Let users see changes in realtime while keeping the dialog open *Preview both colors and pictures *Add ability to apply changes from either combobox including using any image saved from when dialog was opened *Add tooltips to the buttons, filepicker, and comboboxes --- eel/eel-background.c | 12 +- libcaja-private/caja-icon-container.c | 13 + src/caja-desktop-window.c | 5 + src/file-manager/Makefile.am | 2 + src/file-manager/fm-desktop-icon-view.c | 28 +- src/file-manager/fm-desktop-wayland-bg-dialog.c | 418 ++++++++++++++++++++++++ src/file-manager/fm-desktop-wayland-bg-dialog.h | 28 ++ 7 files changed, 494 insertions(+), 12 deletions(-) create mode 100644 src/file-manager/fm-desktop-wayland-bg-dialog.c create mode 100644 src/file-manager/fm-desktop-wayland-bg-dialog.h diff --git a/eel/eel-background.c b/eel/eel-background.c index 2b50d450..f79797c8 100644 --- a/eel/eel-background.c +++ b/eel/eel-background.c @@ -424,16 +424,17 @@ set_root_surface (EelBackground *self, GdkScreen *screen) { eel_background_ensure_realized (self); + GdkDisplay *display = gdk_screen_get_display (screen); if (self->details->use_common_surface) { self->details->unset_root_surface = FALSE; } else { int width, height; drawable_get_adjusted_size (self, &width, &height); - self->details->bg_surface = mate_bg_create_surface (self->details->bg, window, - width, height, TRUE); + if ((GDK_IS_X11_DISPLAY (display)) || (self->details->bg_surface == NULL)) + self->details->bg_surface = mate_bg_create_surface (self->details->bg, window, + width, height, TRUE); } - GdkDisplay *display = gdk_screen_get_display (screen); if ((GDK_IS_X11_DISPLAY (display)) && (self->details->bg_surface != NULL)) mate_bg_set_surface_as_root (screen, self->details->bg_surface); } @@ -671,11 +672,10 @@ widget_realized_setup (GtkWidget *widget, self->details->use_common_surface = (gdk_window_get_visual (window) == gtk_widget_get_visual (widget)) ? TRUE : FALSE; } - else /*Wayland is always composited*/ + else /*Wayland is always composited but never has a root window*/ { - self->details->use_common_surface = TRUE; + self->details->use_common_surface = FALSE; } - init_fade (self); } diff --git a/libcaja-private/caja-icon-container.c b/libcaja-private/caja-icon-container.c index 18ca2054..4c4c084c 100644 --- a/libcaja-private/caja-icon-container.c +++ b/libcaja-private/caja-icon-container.c @@ -4606,6 +4606,19 @@ draw (GtkWidget *widget, cairo_t *cr) { eel_background_draw (widget, cr); } + /*If this is the desktop on wayland, we must draw it from here + *Calling eel_background_draw() from caja_desktop_window_class_init() + *as we do in x11 gives a black background on wayland + *Wayland is always composited but never has a root window + *We don't have a root window to draw on + *the code used for x11 without compositing somehow fails too + *But we can get caja's toplevel window from here and draw on it + */ + if ((!(GDK_IS_X11_DISPLAY (gdk_display_get_default()))) && (CAJA_ICON_CONTAINER (widget)->details->is_desktop)) + { + GtkWidget *toplevel = gtk_widget_get_toplevel(widget); + eel_background_draw (toplevel, cr); + } return GTK_WIDGET_CLASS (caja_icon_container_parent_class)->draw (widget, cr); diff --git a/src/caja-desktop-window.c b/src/caja-desktop-window.c index 6188fa63..662c2472 100644 --- a/src/caja-desktop-window.c +++ b/src/caja-desktop-window.c @@ -390,10 +390,12 @@ realize (GtkWidget *widget) G_CALLBACK (caja_desktop_window_screen_size_changed), window); } +/* Should only reached in x11*/ static gboolean draw (GtkWidget *widget, cairo_t *cr) { + g_assert (GDK_IS_X11_DISPLAY (gdk_display_get_default())); eel_background_draw (widget, cr); return GTK_WIDGET_CLASS (caja_desktop_window_parent_class)->draw (widget, cr); } @@ -415,6 +417,9 @@ caja_desktop_window_class_init (CajaDesktopWindowClass *klass) wclass->realize = realize; wclass->unrealize = unrealize; wclass->map = map; + /*Drawing the desktop background from here gives a black background in wayland + *So manage desktop background from the icon container as in navigation windows + */ if (GDK_IS_X11_DISPLAY (gdk_display_get_default())) wclass->draw = draw; diff --git a/src/file-manager/Makefile.am b/src/file-manager/Makefile.am index 98173976..3707409c 100644 --- a/src/file-manager/Makefile.am +++ b/src/file-manager/Makefile.am @@ -23,6 +23,8 @@ libcaja_file_manager_la_SOURCES = \ fm-actions.h \ fm-desktop-icon-view.c \ fm-desktop-icon-view.h \ + fm-desktop-wayland-bg-dialog.c \ + fm-desktop-wayland-bg-dialog.h \ fm-directory-view.c \ fm-directory-view.h \ fm-widget-view.c \ diff --git a/src/file-manager/fm-desktop-icon-view.c b/src/file-manager/fm-desktop-icon-view.c index 3a88b091..0d0c034a 100644 --- a/src/file-manager/fm-desktop-icon-view.c +++ b/src/file-manager/fm-desktop-icon-view.c @@ -62,6 +62,12 @@ #include "fm-desktop-icon-view.h" #include "fm-actions.h" +#ifdef HAVE_WAYLAND +#include +#include "fm-desktop-wayland-bg-dialog.h" + +#endif + /* Timeout to check the desktop directory for updates */ #define RESCAN_TIMEOUT 4 @@ -707,12 +713,22 @@ action_change_background_callback (GtkAction *action, gpointer data) { g_assert (FM_DIRECTORY_VIEW (data)); - - caja_launch_application_from_command (gtk_widget_get_screen (GTK_WIDGET (data)), - _("Background"), - "mate-appearance-properties", - FALSE, - "--show-page=background", NULL); +#ifdef HAVE_WAYLAND + /*Get the new background and switch to it in wayland*/ + if (GDK_IS_WAYLAND_DISPLAY (gdk_display_get_default())) + { + wayland_bg_dialog_new (); + } + else +#endif + /*Get the new background and switch to it in x11*/ + { + caja_launch_application_from_command (gtk_widget_get_screen (GTK_WIDGET (data)), + _("Background"), + "mate-appearance-properties", + FALSE, + "--show-page=background", NULL); + } } static void diff --git a/src/file-manager/fm-desktop-wayland-bg-dialog.c b/src/file-manager/fm-desktop-wayland-bg-dialog.c new file mode 100644 index 00000000..53c6cdb4 --- /dev/null +++ b/src/file-manager/fm-desktop-wayland-bg-dialog.c @@ -0,0 +1,418 @@ + +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* fm-icon-container.h - the container widget for file manager icons + + Copyright (C) 2024 Luke + + The Mate Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Mate Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Mate Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + Boston, MA 02110-1301, USA. + + Author: +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "fm-desktop-icon-view.h" +#include "fm-desktop-wayland-bg-dialog.h" + + +#ifdef HAVE_WAYLAND + +GSettings *background_settings; +GtkWidget *filebutton; +GtkWidget *preview; +GtkWidget *preview_image; +const gchar *filename; +GdkRGBA color1, color2; +const gchar *primary_color_str, *secondary_color_str, *shading_type; + +static void +update_preview() +{ + static GtkCssProvider *provider; + gchar *css; + GString *string; + + if (!provider) + provider = gtk_css_provider_new (); + + /*Build a color preview using a cssprovider due to requirement to handle RBGA values*/ + string = g_string_new(NULL); + g_string_append (string, "#caja-wayland-bg-preview {"); + + if (strcmp (shading_type, "vertical-gradient") == 0) + g_string_append (string, "background-image: linear-gradient(to bottom,"); + + else if (strcmp (shading_type, "horizontal-gradient") == 0) + g_string_append (string, "background-image: linear-gradient(to right,"); + + else + { + g_string_append (string, "background-color:"); + g_string_append (string, primary_color_str); + } + + if ((strcmp (shading_type, "vertical-gradient") == 0) || + (strcmp (shading_type, "horizontal-gradient") == 0)) + { + g_string_append (string, primary_color_str); + g_string_append (string, ","); + g_string_append (string, secondary_color_str); + g_string_append (string, ");"); + } + g_string_append (string, "}"); + + css = g_string_free (string, FALSE); + gtk_style_context_add_provider (gtk_widget_get_style_context (preview), + GTK_STYLE_PROVIDER (provider), + GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + + gtk_css_provider_load_from_data (provider, css, -1, NULL); + + if ((!filename) || (strcmp (filename, "") == 0) || (strcmp (filename, " ") == 0)) + gtk_image_clear(GTK_IMAGE(preview_image)); + + else + { + GdkRectangle geometry = {0}; + GdkPixbuf *pixbuf; + GdkMonitor *monitor; + GdkDisplay *display; + + display = gdk_screen_get_display (gdk_screen_get_default()); + monitor = gdk_display_get_monitor (display, 0); + gdk_monitor_get_geometry (monitor, &geometry); + + gtk_style_context_remove_provider (gtk_widget_get_style_context (preview), + GTK_STYLE_PROVIDER (provider)); + + gtk_widget_set_size_request (preview, geometry.width / 5, geometry.height / 5); + + pixbuf = gdk_pixbuf_new_from_file_at_scale (filename, geometry.width / 5, + geometry.height / 5, FALSE, NULL); + + gtk_image_set_from_pixbuf (GTK_IMAGE (preview_image), pixbuf); + g_object_unref(pixbuf); + } +} + +static void +update_primary_color(GtkWidget *colorbutton1) +{ + GdkRGBA color1; + + filename = ""; + gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (colorbutton1), &color1); + primary_color_str = gdk_rgba_to_string (&color1); + g_settings_set_string (background_settings, + "primary-color", primary_color_str); + + g_settings_set_string (background_settings, + "picture-filename", ""); + update_preview(); +} + +static void +update_secondary_color(GtkWidget *colorbutton2) +{ + GdkRGBA color2; + + filename = ""; + gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (colorbutton2), &color2); + secondary_color_str = gdk_rgba_to_string (&color2); + g_settings_set_string (background_settings, + "secondary-color", secondary_color_str); + + g_settings_set_string (background_settings, + "picture-filename", ""); + update_preview(); + +} + +static void +update_color_background_options (GtkWidget *colorbox) +{ + filename = ""; + + shading_type = gtk_combo_box_get_active_id (GTK_COMBO_BOX (colorbox)); + /*write to gsettings*/ + g_settings_set_string (background_settings, + "color-shading-type", shading_type); + g_settings_set_string (background_settings, + "picture-filename", ""); + update_preview(); +} + +static void +update_image_background_options(GtkWidget *stylebox) +{ + const gchar *options; + options = gtk_combo_box_get_active_id (GTK_COMBO_BOX(stylebox)); + filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (filebutton)); + if ((!filename) || (strcmp (filename, " ") == 0)) + filename = ""; + + /*write to gsettings*/ + g_settings_set_string (background_settings, + "picture-options", options); + + g_settings_set_string (background_settings, + "picture-filename", filename); + update_preview(); +} + +static void +update_background_image (GtkWidget *filebutton) +{ + filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (filebutton)); + if (strcmp (filename, " ") == 0) + filename = ""; + + /*write to gsettings*/ + g_settings_set_string (background_settings, + "picture-filename", filename); + update_preview (); +} + +void +wayland_bg_dialog_new (void) +{ + GtkWidget *dialog, *box, *vbox1, *vbox2, *hbox1, *hbox2; + GtkWidget *close_button, *colorlabel, *stylelabel; + GtkWidget *filelabel, *stylebox; + GtkWidget *colorbox, *colorbutton1, *colorbutton2; + const gchar *options; + GdkRectangle geometry = {0}; + GdkDisplay *display; + GdkMonitor *monitor; + + background_settings = g_settings_new ("org.mate.background"); + + filename = g_settings_get_string (background_settings, + "picture-filename"); + + options = g_settings_get_string (background_settings, + "picture-options"); + + primary_color_str = g_settings_get_string (background_settings, + "primary-color"); + + secondary_color_str = g_settings_get_string (background_settings, + "secondary-color"); + + shading_type = g_settings_get_string (background_settings, + "color-shading-type"); + + dialog = gtk_dialog_new (); + gtk_window_set_title (GTK_WINDOW (dialog), + _("Desktop Background Preferences")); + + gtk_window_set_transient_for (GTK_WINDOW (dialog), NULL); + + /*Image Style Combobox*/ + stylebox = gtk_combo_box_text_new (); + + gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (stylebox), + "wallpaper", "Tile" ); + + gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (stylebox), + "zoom", "Zoom" ); + + gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (stylebox), + "centered", "Center"); + + gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (stylebox), + "scaled", "Scale"); + + gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (stylebox), + "stretched", "Stretch"); + + gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (stylebox), + "spanned", "Span"); + + gtk_combo_box_set_active_id (GTK_COMBO_BOX (stylebox), options); + + g_signal_connect (stylebox, "changed", + G_CALLBACK (update_image_background_options), stylebox); + + gtk_widget_set_tooltip_text (stylebox, "Image Aspect Ratio and Size. \n" + "Changes applied immediately"); + + /*Color Combobox*/ + colorlabel = gtk_label_new ("Colors:"); + colorbox = gtk_combo_box_text_new (); + + gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (colorbox), + "solid", "Solid color" ); + + gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (colorbox), + "horizontal-gradient", "Horizontal gradient" ); + + gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (colorbox), + "vertical-gradient", "Vertical gradient"); + + gtk_combo_box_set_active_id (GTK_COMBO_BOX (colorbox), shading_type); + + g_signal_connect (colorbox, "changed", + G_CALLBACK (update_color_background_options), colorbox); + + gtk_widget_set_tooltip_text (colorbox, "Use gradient or solid color. \n" + "Changes applied immediately"); + + colorbutton1 = gtk_color_button_new (); + colorbutton2 = gtk_color_button_new (); + gtk_widget_set_tooltip_text (colorbutton1, "Color for gradient top/left or solid color \n" + "Applies on selecting any color"); + + gtk_widget_set_tooltip_text (colorbutton2, "Color for gradient bottom/right\n" + "Applies on selecting any color"); + + + if (!(gdk_rgba_parse (&color1, primary_color_str))) + gdk_rgba_parse (&color1, "rgb(88,145,188)"); + + if (!(gdk_rgba_parse (&color2, secondary_color_str))) + gdk_rgba_parse (&color2, "rgb(60,143,37)"); + + gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (colorbutton1), &color1); + gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (colorbutton2), &color2); + + g_signal_connect (colorbutton1, "color-set", + G_CALLBACK (update_primary_color), colorbutton1); + + g_signal_connect (colorbutton2, "color-set", + G_CALLBACK (update_secondary_color), colorbutton1); + + /*file chooser and it's label for the color bg case*/ + filelabel = gtk_label_new ("Image:"); + stylelabel = gtk_label_new ("Style:"); + filebutton = gtk_file_chooser_button_new (_("Select a file"), + GTK_FILE_CHOOSER_ACTION_OPEN); + + gtk_widget_set_tooltip_text (filebutton, "Image for desktop background. \n" + "Applies on opening image"); + + gtk_file_chooser_button_set_width_chars (GTK_FILE_CHOOSER_BUTTON (filebutton), 16); + + gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (filebutton), + filename); + + gtk_file_chooser_button_set_title (GTK_FILE_CHOOSER_BUTTON (filebutton), + "Select a File"); + + /* If the last background was an image show the user the default background directory*/ + if ((!filename) || (strcmp (filename, "") == 0) || (strcmp (filename, " ") == 0)) + { + gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (filebutton), "/usr/share/backgrounds/"); + } + + preview = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); + + /*Get the size and shape of the desktop*/ + display = gdk_screen_get_display (gdk_screen_get_default()); + monitor = gdk_display_get_monitor (display, 0); + gdk_monitor_get_geometry (monitor, &geometry); + + gtk_widget_set_size_request (preview, geometry.width / 5, geometry.height / 5); + gtk_widget_set_name (GTK_WIDGET (preview), "caja-wayland-bg-preview"); + preview_image = gtk_image_new (); + update_preview (); + + g_signal_connect (filebutton, "file-set", + G_CALLBACK (update_background_image), NULL); + + /*Apply and Cancel buttons */ + close_button = gtk_button_new_with_mnemonic (_("_Close")); + + gtk_button_set_image (GTK_BUTTON (close_button), + gtk_image_new_from_icon_name ("gtk-cancel", GTK_ICON_SIZE_BUTTON)); + + gtk_button_set_use_underline (GTK_BUTTON (close_button), TRUE); + gtk_widget_set_can_default (close_button, TRUE); + + /*Prepare the boxes to pack all this into*/ + box = gtk_dialog_get_content_area (GTK_DIALOG (dialog)); + vbox1 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2); + vbox2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2); + hbox1 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); + hbox2 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); + + /*Pack the filechooser and image options*/ + gtk_box_pack_start (GTK_BOX (hbox1), stylelabel, FALSE, FALSE, 7); + gtk_box_pack_start (GTK_BOX (hbox1), stylebox, FALSE, FALSE, 3); + gtk_box_pack_end (GTK_BOX (hbox1), filebutton, FALSE, FALSE, 5); + gtk_box_pack_end (GTK_BOX (hbox1), filelabel, FALSE, FALSE, 2); + + /*Pack the colorpickers and color options*/ + + gtk_box_pack_start (GTK_BOX (hbox2), colorbox, FALSE, FALSE, 7); + gtk_box_pack_end (GTK_BOX (hbox2), colorbutton2, FALSE, FALSE, 5); + gtk_box_pack_end (GTK_BOX (hbox2), colorbutton1, FALSE, FALSE, 2); + gtk_box_pack_end (GTK_BOX (hbox2), colorlabel, FALSE, FALSE, 2); + + gtk_box_pack_start (GTK_BOX (preview), preview_image, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (vbox2), preview, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (vbox2), hbox1, FALSE, FALSE, 0); + + /*Pack the other boxes into the final vertical box*/ + gtk_box_pack_start (GTK_BOX (vbox1), vbox2, FALSE, FALSE, 20); + gtk_box_pack_start (GTK_BOX (vbox1), hbox2, FALSE, FALSE, 5); + + /*Pack the final vertical box into the content area*/ + gtk_box_pack_start (GTK_BOX (box), vbox1, FALSE, FALSE, 0); + + /*Pack the close action area*/ + + gtk_dialog_add_action_widget (GTK_DIALOG (dialog), + close_button, + GTK_RESPONSE_APPLY); + + gtk_widget_show_all (dialog); + + /*Run the dialog*/ + gtk_dialog_run (GTK_DIALOG (dialog)); + /*cleanup*/ + g_signal_handlers_disconnect_by_func (stylebox, update_image_background_options, stylebox); + g_signal_handlers_disconnect_by_func (colorbox, update_color_background_options, colorbox); + g_signal_handlers_disconnect_by_func (colorbutton1, update_primary_color, colorbutton1); + g_signal_handlers_disconnect_by_func (colorbutton2, update_primary_color, colorbutton2); + g_signal_handlers_disconnect_by_func (filebutton, update_background_image, NULL); + + g_object_unref (background_settings); + gtk_widget_destroy (dialog); +} +#endif + diff --git a/src/file-manager/fm-desktop-wayland-bg-dialog.h b/src/file-manager/fm-desktop-wayland-bg-dialog.h new file mode 100644 index 00000000..65858c05 --- /dev/null +++ b/src/file-manager/fm-desktop-wayland-bg-dialog.h @@ -0,0 +1,28 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* fm-icon-container.h - the container widget for file manager icons + + Copyright (C) 2024 Luke + + The Mate Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Mate Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Mate Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + Boston, MA 02110-1301, USA. + + Author: Luke +*/ +#ifdef HAVE_WAYLAND +#include "fm-desktop-icon-view.h" + +void wayland_bg_dialog_new (void); +#endif -- cgit v1.2.1