Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
29 changes: 29 additions & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,8 @@ singularity_core_sources = files(
'src/core/wallpaper_rotation_state.vala',
'src/core/wallpaper_rotator.vala',
'src/core/artist_pack_manager.vala',
'src/core/wallpaper_history.vala',
'src/core/wallpaper_favorites.vala',
'src/core/wallpaper_sidecar.vala',
'src/core/wallpaper_browse_cache.vala',
'src/core/wallpaper_thumbnail_cache.vala',
Expand Down Expand Up @@ -528,6 +530,33 @@ wallpaper_rotation_state_test = executable('wallpaper-rotation-state-test',
)
test('wallpaper-rotation-state', wallpaper_rotation_state_test)

glib_compile_schemas = find_program('glib-compile-schemas')
wallpaper_test_schema = custom_target('wallpaper-test-schema',
input: 'tests/dev.sinty.desktop.gschema.xml',
output: 'gschemas.compiled',
command: [glib_compile_schemas, '--strict', '--targetdir', meson.current_build_dir(),
join_paths(meson.current_source_dir(), 'tests')],
build_by_default: true,
)
wallpaper_test_env = environment()
wallpaper_test_env.set('GSETTINGS_SCHEMA_DIR', meson.current_build_dir())

wallpaper_history_test = executable('wallpaper-history-test',
sources: ['src/core/wallpaper_history.vala', 'tests/wallpaper_history_test.vala'],
dependencies: [dependency('gobject-2.0'), dependency('gio-2.0'), dependency('gio-unix-2.0'), gee_dep],
)
test('wallpaper-history', wallpaper_history_test,
depends: wallpaper_test_schema,
env: wallpaper_test_env)

wallpaper_favorites_test = executable('wallpaper-favorites-test',
sources: ['src/core/wallpaper_favorites.vala', 'tests/wallpaper_favorites_test.vala'],
dependencies: [dependency('gobject-2.0'), dependency('gio-2.0'), dependency('gio-unix-2.0'), gee_dep],
)
test('wallpaper-favorites', wallpaper_favorites_test,
depends: wallpaper_test_schema,
env: wallpaper_test_env)

wallpaper_gallery_test = executable('wallpaper-gallery-test',
sources: ['src/core/wallpaper_gallery.vala', 'tests/wallpaper_gallery_test.vala'],
dependencies: [dependency('gobject-2.0'), dependency('gio-2.0'), gee_dep],
Expand Down
113 changes: 109 additions & 4 deletions src/components/panel/panel.vala
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,109 @@ using Singularity.Widgets;

namespace Singularity {

private class WallpaperIndicator : Gtk.Box {
private GLib.Settings settings;
private WallpaperHistory history;
private WallpaperFavorites favorites;
private WallpaperRotationState rotation_state;
private Button previous_button;
private Button next_button;
private Button pause_button;
private Button favorite_button;
private string? navigation_target = null;

public WallpaperIndicator(GLib.Settings settings) {
Object(orientation: Orientation.HORIZONTAL, spacing: 0);
valign = Align.CENTER;
this.settings = settings;
history = new WallpaperHistory(settings);
favorites = new WallpaperFavorites(settings);
rotation_state = new WallpaperRotationState(
WallpaperRotationState.default_config_dir());

var button = new MenuButton();
button.add_css_class("flat");
button.tooltip_text = _("Wallpaper controls");
var icon = new Image.from_icon_name("preferences-desktop-wallpaper-symbolic");
icon.pixel_size = 16;
button.child = icon;
append(button);

var controls = new Box(Orientation.HORIZONTAL, 6);
controls.margin_top = 10;
controls.margin_bottom = 10;
controls.margin_start = 12;
controls.margin_end = 12;

previous_button = new Button.from_icon_name("go-previous-symbolic");
previous_button.tooltip_text = _("Previous wallpaper");
previous_button.clicked.connect(() => navigate(history.go_back()));
controls.append(previous_button);

next_button = new Button.from_icon_name("go-next-symbolic");
next_button.tooltip_text = _("Next wallpaper");
next_button.clicked.connect(() => navigate(history.go_forward()));
controls.append(next_button);

pause_button = new Button();
pause_button.clicked.connect(() => {
rotation_state.set_rotate_enabled(!rotation_state.get_rotate_enabled());
update_controls();
});
controls.append(pause_button);

favorite_button = new Button();
favorite_button.clicked.connect(() => {
string? path = WallpaperManager.get_default().wallpaper_path;
if (path != null) favorites.toggle_favorite(path);
});
controls.append(favorite_button);

var popover = new Popover();
popover.child = controls;
button.popover = popover;
popover.notify["visible"].connect(() => {
if (popover.visible) update_controls();
});

var manager = WallpaperManager.get_default();
manager.wallpaper_path_changed.connect((path) => {
if (navigation_target == path) navigation_target = null;
else history.record(path);
update_controls();
});
favorites.favorites_changed.connect(update_controls);
if (manager.wallpaper_path != null && history.current_path != manager.wallpaper_path)
history.record(manager.wallpaper_path);
update_controls();
}

private void navigate(string? path) {
if (path == null) return;
navigation_target = path;
settings.delay();
SettingsSafety.set_string(settings, "background-picture-uri",
File.new_for_path(path).get_uri());
SettingsSafety.set_string(settings, "background-attribution-title", "");
SettingsSafety.set_string(settings, "background-attribution-author", "");
settings.apply();
update_controls();
}

private void update_controls() {
previous_button.sensitive = history.can_go_back();
next_button.sensitive = history.can_go_forward();
bool rotating = rotation_state.get_rotate_enabled();
pause_button.icon_name = rotating ? "media-playback-pause-symbolic" : "media-playback-start-symbolic";
pause_button.tooltip_text = rotating ? _("Pause wallpaper rotation") : _("Resume wallpaper rotation");
string? path = WallpaperManager.get_default().wallpaper_path;
bool is_favorite = path != null && favorites.is_favorite(path);
favorite_button.icon_name = is_favorite ? "starred-symbolic" : "non-starred-symbolic";
favorite_button.tooltip_text = is_favorite ? _("Remove from favorites") : _("Add to favorites");
favorite_button.sensitive = path != null;
}
}

private class TilingPositionIndicator : Gtk.Fixed {
private const int TRACK_WIDTH = 58;
private const int TRACK_HEIGHT = 18;
Expand Down Expand Up @@ -638,6 +741,8 @@ namespace Singularity {
clock_box.append(clock_btn);
clock_box.append(clock_suffix_box);
layout_items["clock"] = clock_box;
if (is_primary && !is_greeter_mode)
layout_items["wallpaper"] = new WallpaperIndicator(_settings);
reload_bar_layout();
_settings.changed["panel-layout-left"].connect(() => {
if (!saving_bar_layout) reload_bar_layout();
Expand All @@ -656,8 +761,8 @@ namespace Singularity {
center_box,
right_box,
layout_items,
{ "overview", "workspaces", "tiling-position", "app-title", "global-menu", "system", "notifications", "clock" },
{ _("Overview"), _("Workspaces"), _("Scrolling Position"), _("App Title"), _("Global Menu"), _("System Status"), _("Notifications"), _("Clock") }
{ "overview", "workspaces", "tiling-position", "app-title", "global-menu", "system", "notifications", "clock", "wallpaper" },
{ _("Overview"), _("Workspaces"), _("Scrolling Position"), _("App Title"), _("Global Menu"), _("System Status"), _("Notifications"), _("Clock"), _("Wallpaper") }
);
layout_editor.move_requested.connect((item_id, section, index) => {
if (bar_layout != null && bar_layout.move(item_id, section, index)) save_bar_layout();
Expand Down Expand Up @@ -1000,13 +1105,13 @@ namespace Singularity {
private void reload_bar_layout() {
string[] item_ids = {
"overview", "workspaces", "tiling-position", "app-title", "global-menu",
"system", "notifications", "clock"
"system", "notifications", "clock", "wallpaper"
};
bar_layout = new BarLayout(
item_ids,
{ "overview", "workspaces", "app-title", "global-menu" },
{ "tiling-position" },
{ "system", "notifications", "clock" },
{ "system", "notifications", "clock", "wallpaper" },
_settings.get_strv("panel-layout-left"),
_settings.get_strv("panel-layout-center"),
_settings.get_strv("panel-layout-right")
Expand Down
45 changes: 45 additions & 0 deletions src/core/wallpaper_favorites.vala
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using GLib;
using Gee;

namespace Singularity {

public class WallpaperFavorites : Object {
private const string FAVORITES_KEY = "wallpaper-favorites";
private GLib.Settings settings;
private ArrayList<string> favorites = new ArrayList<string>();

public signal void favorites_changed();

public WallpaperFavorites(GLib.Settings? settings = null) {
this.settings = settings ?? new GLib.Settings("dev.sinty.desktop");
SettingsSchema? schema = this.settings.settings_schema;
if (schema == null || !schema.has_key(FAVORITES_KEY)) return;
foreach (string path in this.settings.get_strv(FAVORITES_KEY)) {
if (path != "" && !favorites.contains(path)) favorites.add(path);
}
}

private void save() {
SettingsSchema? schema = settings.settings_schema;
if (schema == null || !schema.has_key(FAVORITES_KEY)) return;
settings.set_strv(FAVORITES_KEY, list_favorites());
}

public bool is_favorite(string path) {
return path != "" && favorites.contains(path);
}

public void toggle_favorite(string path) {
if (path == "") return;
if (!favorites.remove(path)) favorites.add(path);
save();
favorites_changed();
}

public string[] list_favorites() {
string[] result = {};
foreach (string path in favorites) result += path;
return result;
}
}
}
102 changes: 102 additions & 0 deletions src/core/wallpaper_history.vala
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
using GLib;
using Gee;

namespace Singularity {

public class WallpaperHistory : Object {
public const int MAX_ENTRIES = 200;
private const string BACK_KEY = "wallpaper-history-back";
private const string FORWARD_KEY = "wallpaper-history-forward";
private const string CURRENT_KEY = "wallpaper-history-current";

private GLib.Settings settings;
private ArrayList<string> back = new ArrayList<string>();
private ArrayList<string> forward = new ArrayList<string>();
private int max_entries;
public string? current_path { get; private set; default = null; }
public int size { get { return back.size + forward.size + (current_path != null ? 1 : 0); } }

public WallpaperHistory(GLib.Settings? settings = null, int max_entries = MAX_ENTRIES) {
this.settings = settings ?? new GLib.Settings("dev.sinty.desktop");
this.max_entries = int.max(1, max_entries);
load();
}

private bool has_key(string key) {
SettingsSchema? schema = settings.settings_schema;
return schema != null && schema.has_key(key);
}

private void load_stack(ArrayList<string> destination, string key) {
if (!has_key(key)) return;
foreach (string path in settings.get_strv(key)) {
if (path != "") destination.add(path);
}
}

private void load() {
load_stack(back, BACK_KEY);
load_stack(forward, FORWARD_KEY);
if (has_key(CURRENT_KEY)) {
string saved = settings.get_string(CURRENT_KEY);
if (saved != "") current_path = saved;
}
trim_to_limit();
}

private string[] stack_to_array(ArrayList<string> stack) {
string[] result = {};
foreach (string path in stack) result += path;
return result;
}

private void save() {
settings.delay();
if (has_key(BACK_KEY)) settings.set_strv(BACK_KEY, stack_to_array(back));
if (has_key(FORWARD_KEY)) settings.set_strv(FORWARD_KEY, stack_to_array(forward));
if (has_key(CURRENT_KEY)) settings.set_string(CURRENT_KEY, current_path ?? "");
settings.apply();
}

private void trim_to_limit() {
while (size > max_entries) {
if (back.size > 0) back.remove_at(0);
else if (forward.size > 0) forward.remove_at(0);
else break;
}
}

public void record(string path) {
if (path == "" || path == current_path) return;
if (current_path != null) back.add(current_path);
current_path = path;
forward.clear();
trim_to_limit();
save();
}

public bool can_go_back() {
return current_path != null && back.size > 0;
}

public bool can_go_forward() {
return current_path != null && forward.size > 0;
}

public string? go_back() {
if (!can_go_back()) return null;
forward.add(current_path);
current_path = back.remove_at(back.size - 1);
save();
return current_path;
}

public string? go_forward() {
if (!can_go_forward()) return null;
back.add(current_path);
current_path = forward.remove_at(forward.size - 1);
save();
return current_path;
}
}
}
3 changes: 3 additions & 0 deletions src/core/wallpaper_manager.vala
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ namespace Singularity {
public string attribution_author { get; private set; default = ""; }

public signal void wallpaper_changed();
// Emitted only after a different image becomes the displayed wallpaper.
public signal void wallpaper_path_changed(string new_path);

public static WallpaperManager get_default() {
if (_instance == null) {
Expand Down Expand Up @@ -243,6 +245,7 @@ namespace Singularity {
if (pb_small != null) preview_texture = Texture.for_pixbuf(pb_small);
message("Wallpaper loaded: %s", load_path);
wallpaper_changed();
wallpaper_path_changed(load_path);
return false;
});
});
Expand Down
9 changes: 9 additions & 0 deletions tests/dev.sinty.desktop.gschema.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<schemalist>
<schema id="dev.sinty.desktop" path="/dev/sinty/desktop/">
<key name="wallpaper-history-back" type="as"><default>[]</default></key>
<key name="wallpaper-history-forward" type="as"><default>[]</default></key>
<key name="wallpaper-history-current" type="s"><default>''</default></key>
<key name="wallpaper-favorites" type="as"><default>[]</default></key>
</schema>
</schemalist>
Loading
Loading