Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GTK Background #2070

Draft
wants to merge 30 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
6debeb0
Prototype
leolost2605 Sep 22, 2024
6c11391
Works pretty good now
leolost2605 Sep 22, 2024
47c708d
Fix startup delay due to granite
leolost2605 Sep 23, 2024
b894a61
Proper background clone and backgrounds per monitor + update them
leolost2605 Sep 23, 2024
5a6db97
Allow switching wallpapers
leolost2605 Sep 23, 2024
93a5e15
Add solid color
leolost2605 Sep 23, 2024
fd1a0b1
Support dim
leolost2605 Sep 23, 2024
e376ce8
disable granite settings for now
leolost2605 Sep 23, 2024
14a533b
Introduce backgroundmanager
leolost2605 Sep 23, 2024
b05c989
Add background menu
leolost2605 Sep 23, 2024
9a6a925
Remove background
leolost2605 Sep 23, 2024
6b5f092
Add licenses and cleanup
leolost2605 Sep 23, 2024
5cb7d29
Make background black again
leolost2605 Sep 24, 2024
8f8d250
Add color info first version
leolost2605 Sep 24, 2024
5544bc2
ColorInformation: Support dimmed background
leolost2605 Sep 24, 2024
947cd78
Move ColorInformation to Background
leolost2605 Sep 24, 2024
c555053
Implement color info for SolidColor backgrounds
leolost2605 Sep 24, 2024
0ea8dea
Don't create ALL BackgroundWindows new if monitors change
leolost2605 Sep 24, 2024
e21498d
Fix lint
leolost2605 Sep 24, 2024
da4dbaf
Keep aspect ratio
leolost2605 Sep 24, 2024
7081e6b
Merge branch 'main' into leolost/gtk-background
leolost2605 Oct 3, 2024
6834e2d
Use account service for dark scheme and fix build
leolost2605 Oct 3, 2024
62768c8
Fix menu coloring
leolost2605 Oct 4, 2024
9606794
Some cleanup and support ZOOM BackgroundStyle
leolost2605 Oct 4, 2024
ef0251e
Fix translation
leolost2605 Oct 4, 2024
0cbe479
Cleanup and support CENTERED
leolost2605 Oct 4, 2024
3edfa28
Add some comments
leolost2605 Oct 4, 2024
3f33900
Keep correct size on different scales
leolost2605 Oct 7, 2024
301bfc4
Support X11
leolost2605 Oct 9, 2024
17b88e1
Fix multitasking view on x and improve comment
leolost2605 Oct 9, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions background/Application.vala
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright 2024 elementary, Inc. (https://elementary.io)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Authored by: Leonhard Kargl <[email protected]>
*/

public class Gala.Background.Application : Gtk.Application {
private BackgroundManager background_manager;

public Application () {
Object (application_id: "io.elementary.desktop.background");
}

public override void startup () {
base.startup ();

hold ();

/*
* We can't use Granite for the color scheme since it connects to the portal which only becomes available
* some time after we are already showing.
*/
Utils.init_color_scheme_watcher ((scheme) => {
Gtk.Settings.get_default ().gtk_application_prefer_dark_theme = scheme == DARK;
});

background_manager = new BackgroundManager ();

try {
get_dbus_connection ().register_object (get_dbus_object_path (), background_manager);
} catch (Error e) {
warning ("Failed to export background manager: %s", e.message);
}
}

public override void activate () { }
}

public static int main (string[] args) {
GLib.Intl.setlocale (LocaleCategory.ALL, "");
GLib.Intl.bindtextdomain (Config.GETTEXT_PACKAGE, Config.LOCALEDIR);
GLib.Intl.bind_textdomain_codeset (Config.GETTEXT_PACKAGE, "UTF-8");
GLib.Intl.textdomain (Config.GETTEXT_PACKAGE);

var app = new Gala.Background.Application ();
return app.run ();
}
163 changes: 163 additions & 0 deletions background/Background.vala
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
/*
* Copyright 2024 elementary, Inc. (https://elementary.io)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Authored by: Leonhard Kargl <[email protected]>
*/

public interface Gala.Background.Background : Object, Gdk.Paintable {
public struct ColorInformation {
double average_red;
double average_green;
double average_blue;
double mean_luminance;
double luminance_variance;
double mean_acutance;
}

public static Background get_for_color (Gdk.RGBA color) {
return new SolidColor (color);
}

public static Background? get_for_file (File file, GDesktop.BackgroundStyle style) {
Gdk.Texture texture;
try {
texture = Gdk.Texture.from_file (file);
} catch (Error e) {
warning ("Failed to load texture: %s", e.message);
return null;
}

return new ImageBackground (texture, style);
}

public static Background get_dimmed (Background other) {
return new DimBackground (other);
}

public abstract ColorInformation? get_color_information (int height);

private class SolidColor : Object, Gdk.Paintable, Background {
public Gdk.RGBA color { get; construct; }

public SolidColor (Gdk.RGBA color) {
Object (color: color);
}

public ColorInformation? get_color_information (int height) {
var r = color.red * 255;
var g = color.green * 255;
var b = color.blue * 255;

return {r, g, b, (0.3 * r + 0.59 * g + 0.11 * b), 0, 0};
}

public void snapshot (Gdk.Snapshot gdk_snapshot, double width, double height) {
if (!(gdk_snapshot is Gtk.Snapshot)) {
critical ("No Gtk Snapshot provided can't render solid color");
return;
}

var snapshot = (Gtk.Snapshot) gdk_snapshot;

var rect = Graphene.Rect ().init (0, 0, (float) width, (float) height);

snapshot.append_color (color, rect);
}
}

private class DimBackground : Object, Gdk.Paintable, Background {
public Background texture { get; construct; }

public DimBackground (Background texture) {
Object (texture: texture);
}

public ColorInformation? get_color_information (int height) {
var info = texture.get_color_information (height);
if (info == null) {
return null;
}

info.average_red *= 0.55;
info.average_green *= 0.55;
info.average_blue *= 0.55;
info.mean_luminance *= 0.55;
info.luminance_variance *= 0.55;

return info;
}

public override double get_intrinsic_aspect_ratio () {
return texture.get_intrinsic_aspect_ratio ();
}

public void snapshot (Gdk.Snapshot gdk_snapshot, double width, double height) {
if (!(gdk_snapshot is Gtk.Snapshot)) {
critical ("No Gtk Snapshot provided can't render brightness changed");
texture.snapshot (gdk_snapshot, width, height);
return;
}

var snapshot = (Gtk.Snapshot) gdk_snapshot;

float[] matrix_values = {
0.55f, 0, 0, 0,
0, 0.55f, 0, 0,
0, 0, 0.55f, 0,
0, 0, 0, 1,
};

var brightness_matrix = Graphene.Matrix ().init_from_float (matrix_values);

snapshot.push_color_matrix (brightness_matrix, Graphene.Vec4.zero ());

texture.snapshot (gdk_snapshot, width, height);

snapshot.pop ();
}
}

private class ImageBackground : Object, Gdk.Paintable, Background {
public Gdk.Texture texture { get; construct; }
public GDesktop.BackgroundStyle style { get; construct; }

public ImageBackground (Gdk.Texture texture, GDesktop.BackgroundStyle style) {
Object (texture: texture, style: style);
}

public ColorInformation? get_color_information (int height) {
return Utils.get_background_color_information (texture, height);
}

public void snapshot (Gdk.Snapshot gdk_snapshot, double width, double height) {
var snapshot = (Gtk.Snapshot) gdk_snapshot;

switch (style) {
case ZOOM:
/* We scale according to the bigger scale factor. Therefore the texture will be pushed off screen
* in the other direction so center it in that direction. */
var x_scale = (float) width / texture.width;
var y_scale = (float) height / texture.height;
if (x_scale > y_scale) {
snapshot.translate ({0, (float) (height - texture.height * x_scale) / 2}); // Center it vertically
snapshot.scale (x_scale, x_scale);
} else {
snapshot.translate ({(float) (width - (texture.width * y_scale)) / 2, 0}); // Center it horizontally
snapshot.scale (y_scale, y_scale);
}
texture.snapshot (snapshot, texture.width, texture.height);
break;

case CENTERED:
snapshot.translate ({(float) (width - texture.width) / 2, (float) (height - texture.height) / 2}); // Center it
texture.snapshot (snapshot, texture.width, texture.height); // Draw at original texture size
break;

default:
texture.snapshot (gdk_snapshot, width, height);
break;
}
}
}
}
93 changes: 93 additions & 0 deletions background/BackgroundManager.vala
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*
* Copyright 2024 elementary, Inc. (https://elementary.io)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Authored by: Leonhard Kargl <[email protected]>
*/

[DBus (name = "io.elementary.desktop.BackgroundManager")]
public class Gala.Background.BackgroundManager : Object {
private static Settings gnome_settings = new Settings ("org.gnome.desktop.background");
private static Settings elementary_settings = new Settings ("io.elementary.desktop.background");

public signal void changed ();

private BackgroundWindow[] windows = {};
private Background? current_background;

private uint idle_id = 0;

construct {
setup_background ();
Gdk.Display.get_default ().get_monitors ().items_changed.connect (setup_background);

set_background ();
gnome_settings.changed.connect (queue_set_background);
elementary_settings.changed.connect (queue_set_background);

Gtk.Settings.get_default ().notify["gtk-application-prefer-dark-theme"].connect (queue_set_background);
}

private void setup_background () {
foreach (var window in windows) {
window.destroy ();
}

windows = {};

var monitors = Gdk.Display.get_default ().get_monitors ();
for (int i = 0; i < monitors.get_n_items (); i++) {
windows += new BackgroundWindow (i);
}
}

private void queue_set_background () {
// We want to update only once for a series of changes (e.g. style to 0 and different primary color).
if (idle_id != 0) {
Source.remove (idle_id);
}

idle_id = Timeout.add (100, () => {
set_background ();
idle_id = 0;
return Source.REMOVE;
});
}

private void set_background () {
var style = gnome_settings.get_enum ("picture-options");
if (style != GDesktop.BackgroundStyle.NONE) {
var uri = gnome_settings.get_string ("picture-uri");
var file = File.new_for_uri (uri);
current_background = Background.get_for_file (file, style);
} else {
Gdk.RGBA color = {};
color.parse (gnome_settings.get_string ("primary-color"));
current_background = Background.get_for_color (color);
}

if (current_background == null) {
current_background = Background.get_for_color ({0, 0, 0, 255});
}

if (elementary_settings.get_boolean ("dim-wallpaper-in-dark-style")
&& Gtk.Settings.get_default ().gtk_application_prefer_dark_theme
) {
current_background = Background.get_dimmed (current_background);
}

foreach (var window in windows) {
window.set_background (current_background);
}

changed ();
}

public Background.ColorInformation? get_background_color_information (int height) throws DBusError, IOError {
if (current_background == null) {
return null;
}

return current_background.get_color_information (height);
}
}
Loading
Loading