diff --git a/src/components/background/background.vala b/src/components/background/background.vala index 219c41d..8ea0c75 100644 --- a/src/components/background/background.vala +++ b/src/components/background/background.vala @@ -44,10 +44,12 @@ namespace Singularity { // but the manager owns that decision). Bottom-left, 40% width x // 30% height, with a small margin from the very edge so the // sample doesn't include the empty space around the label. - private const double CORNER_SAMPLE_X_FRAC = 0.0; - private const double CORNER_SAMPLE_Y_FRAC = 0.65; private const double CORNER_SAMPLE_W_FRAC = 0.40; private const double CORNER_SAMPLE_H_FRAC = 0.30; + private const double CORNER_SAMPLE_X_LEFT = 0.0; + private const double CORNER_SAMPLE_X_RIGHT = 1.0 - CORNER_SAMPLE_W_FRAC; + private const double CORNER_SAMPLE_Y_TOP = 1.0 - 0.65 - CORNER_SAMPLE_H_FRAC; + private const double CORNER_SAMPLE_Y_BOTTOM = 0.65; // Pixel margin from the screen edge to the attribution label. // Bottom-left is clear of the dock (which is bottom-anchored // and horizontally centered) at any reasonable screen width, @@ -66,6 +68,16 @@ namespace Singularity { public signal void first_painted(); private bool _first_painted_done = false; + private ulong panel_handler = 0; + + public override void dispose() { + if (panel_handler != 0) { + AppSystem.get_default().disconnect(panel_handler); + panel_handler = 0; + } + base.dispose(); + } + public Background(Gtk.Application app, Gdk.Monitor? monitor = null) { Object(application: app); init_for_window(this); @@ -94,9 +106,6 @@ namespace Singularity { picture_b.can_target = false; wp_stack.add_overlay(picture_b); - // Attribution overlay. The label is bottom-left-anchored - // (halign=START, valign=END, ATTRIBUTION_MARGIN gutter) - // and click-through so it never intercepts desktop mouse // events. can_target=false is GTK4's correct way to make a // widget hit-test-transparent; setting can_focus=false // prevents the label from grabbing Tab focus out of the @@ -109,10 +118,6 @@ namespace Singularity { // the contrast rule is consistent across panel + overlay. attribution_label = new Label(""); attribution_label.add_css_class("attribution-label"); - attribution_label.halign = Align.START; - attribution_label.valign = Align.END; - attribution_label.xalign = 0.0f; - attribution_label.yalign = 1.0f; attribution_label.margin_start = ATTRIBUTION_MARGIN; attribution_label.margin_end = ATTRIBUTION_MARGIN; attribution_label.margin_bottom = ATTRIBUTION_MARGIN; @@ -133,9 +138,15 @@ namespace Singularity { // the toggle in Settings immediately hides or re-shows the // overlay for the wallpaper that's currently displayed. settings = new GLib.Settings("dev.sinty.desktop"); - settings.changed["show-wallpaper-attribution"].connect(() => { - update_attribution(WallpaperManager.get_default()); + settings.changed.connect((key) => { + if (key == "show-wallpaper-attribution") { + update_attribution(WallpaperManager.get_default()); + } else if (key == "wallpaper-attribution-position") { + update_attribution_position(); + } }); + update_attribution_position(); + panel_handler = AppSystem.get_default().notify["shell-panel-height"].connect(() => update_attribution_position()); // First load: set both pictures to avoid flash, no animation needed if (manager.display_texture != null) { picture_a.set_paintable(manager.display_texture); @@ -196,7 +207,6 @@ namespace Singularity { // Wallpaper attribution overlay (Background.vala). // - // Sits in the bottom-left corner of the live desktop background // as a single Gtk.Label over the wallpaper cross-fade. The scrim // is a semi-transparent rounded rectangle so the text reads // against both bright and dark wallpapers without an aggressive @@ -309,13 +319,14 @@ namespace Singularity { attribution_label.set_markup(markup); attribution_label.visible = true; - // Sample the corner. The pixbuf aspect matches the screen - // aspect so a fractional bottom-left corner maps 1:1 to a - // fractional bottom-left corner of the screen at the same - // proportional position. + string sample_position = settings.get_string("wallpaper-attribution-position"); + double sample_x = (sample_position == "top-right" || sample_position == "bottom-right") + ? CORNER_SAMPLE_X_RIGHT : CORNER_SAMPLE_X_LEFT; + double sample_y = (sample_position == "top-left" || sample_position == "top-right") + ? CORNER_SAMPLE_Y_TOP : CORNER_SAMPLE_Y_BOTTOM; double lum = manager.corner_luminance_frac( - CORNER_SAMPLE_X_FRAC, - CORNER_SAMPLE_Y_FRAC, + sample_x, + sample_y, CORNER_SAMPLE_W_FRAC, CORNER_SAMPLE_H_FRAC); if (lum >= 0.0) { @@ -325,6 +336,40 @@ namespace Singularity { } } + private void update_attribution_position() { + string position = settings.get_string("wallpaper-attribution-position"); + bool at_top = position == "top-left" || position == "top-right"; + attribution_label.margin_top = ATTRIBUTION_MARGIN + + (at_top ? AppSystem.get_default().shell_panel_height : 0); + switch (position) { + case "top-left": + attribution_label.halign = Align.START; + attribution_label.valign = Align.START; + attribution_label.xalign = 0.0f; + attribution_label.yalign = 0.0f; + break; + case "top-right": + attribution_label.halign = Align.END; + attribution_label.valign = Align.START; + attribution_label.xalign = 1.0f; + attribution_label.yalign = 0.0f; + break; + case "bottom-right": + attribution_label.halign = Align.END; + attribution_label.valign = Align.END; + attribution_label.xalign = 1.0f; + attribution_label.yalign = 1.0f; + break; + default: + attribution_label.halign = Align.START; + attribution_label.valign = Align.END; + attribution_label.xalign = 0.0f; + attribution_label.yalign = 1.0f; + break; + } + attribution_label.queue_allocate(); + } + private void update_wallpaper(WallpaperManager manager) { var texture = manager.display_texture; if (texture == null) return; diff --git a/src/components/sidebar/pages/desktop_page.vala b/src/components/sidebar/pages/desktop_page.vala index 9f100dd..c843f60 100644 --- a/src/components/sidebar/pages/desktop_page.vala +++ b/src/components/sidebar/pages/desktop_page.vala @@ -310,6 +310,26 @@ namespace Singularity { settings.set_boolean("show-wallpaper-attribution", attribution_row.switch_btn.active); }); + var attribution_position_options = new Gee.ArrayList(); + attribution_position_options.add(new Singularity.Core.AppSettingOption() { id = "top-left", label = _("Top Left") }); + attribution_position_options.add(new Singularity.Core.AppSettingOption() { id = "top-right", label = _("Top Right") }); + attribution_position_options.add(new Singularity.Core.AppSettingOption() { id = "bottom-left", label = _("Bottom Left") }); + attribution_position_options.add(new Singularity.Core.AppSettingOption() { id = "bottom-right", label = _("Bottom Right") }); + string attribution_position = settings.get_string("wallpaper-attribution-position"); + bool valid_position = false; + foreach (var opt in attribution_position_options) { + if (opt.id == attribution_position) { valid_position = true; break; } + } + if (!valid_position) attribution_position = "bottom-left"; + var attribution_position_row = new SelectionRow.with_options( + _("Wallpaper Info Position"), attribution_position_options, attribution_position); + settings.bind("show-wallpaper-attribution", attribution_position_row, + "sensitive", SettingsBindFlags.GET); + attribution_position_row.selected.connect((id) => { + settings.set_string("wallpaper-attribution-position", id); + }); + grid_group.add_row(attribution_position_row); + var interval_options = new Gee.ArrayList(); interval_options.add(new Singularity.Core.AppSettingOption() { id = "600", label = _("Every 10 minutes") }); interval_options.add(new Singularity.Core.AppSettingOption() { id = "1800", label = _("Every 30 minutes") }); diff --git a/src/core/app_system.vala b/src/core/app_system.vala index 778ad13..03b98b0 100644 --- a/src/core/app_system.vala +++ b/src/core/app_system.vala @@ -65,7 +65,7 @@ namespace Singularity { public static bool activate_next_created_workspace = false; public static Window? window_to_move_to_new_workspace = null; // Updated by Panel/Dock on allocation so screenshot geometry is accurate - public int shell_panel_height = 32; + public int shell_panel_height { get; set; default = 32; } public int shell_dock_height = 56; public List get_running_apps() {