-
-
Notifications
You must be signed in to change notification settings - Fork 41
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
19 changed files
with
1,322 additions
and
176 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
/* | ||
* SPDX-License-Identifier: GPL-3.0-or-later | ||
* SPDX-FileCopyrightText: 2024 elementary, Inc. (https://elementary.io) | ||
* 2014 Tom Beckmann | ||
*/ | ||
|
||
namespace GreeterCompositor { | ||
public class Animation : Object { | ||
public string filename { get; construct; } | ||
public string[] key_frame_files { get; private set; default = {}; } | ||
public double transition_progress { get; private set; default = 0.0; } | ||
public double transition_duration { get; private set; default = 0.0; } | ||
public bool loaded { get; private set; default = false; } | ||
|
||
private Gnome.BGSlideShow? show = null; | ||
|
||
public Animation (string filename) { | ||
Object (filename: filename); | ||
} | ||
|
||
public async void load () { | ||
show = new Gnome.BGSlideShow (filename); | ||
|
||
show.load_async (null, (obj, res) => { | ||
loaded = true; | ||
|
||
load.callback (); | ||
}); | ||
|
||
yield; | ||
} | ||
|
||
#if HAS_MUTTER45 | ||
public void update (Mtk.Rectangle monitor) { | ||
#else | ||
public void update (Meta.Rectangle monitor) { | ||
#endif | ||
string[] key_frame_files = {}; | ||
|
||
if (show == null) | ||
return; | ||
|
||
if (show.get_num_slides () < 1) | ||
return; | ||
|
||
double progress, duration; | ||
bool is_fixed; | ||
string file1, file2; | ||
show.get_current_slide (monitor.width, monitor.height, out progress, out duration, out is_fixed, out file1, out file2); | ||
|
||
transition_duration = duration; | ||
transition_progress = progress; | ||
|
||
if (file1 != null) | ||
key_frame_files += file1; | ||
|
||
if (file2 != null) | ||
key_frame_files += file2; | ||
|
||
this.key_frame_files = key_frame_files; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,240 @@ | ||
/* | ||
* SPDX-License-Identifier: GPL-3.0-or-later | ||
* SPDX-FileCopyrightText: 2024 elementary, Inc. (https://elementary.io) | ||
* 2014 Tom Beckmann | ||
*/ | ||
|
||
namespace GreeterCompositor { | ||
public class Background : Object { | ||
private const double ANIMATION_OPACITY_STEP_INCREMENT = 4.0; | ||
private const double ANIMATION_MIN_WAKEUP_INTERVAL = 1.0; | ||
|
||
public signal void changed (); | ||
public signal void loaded (); | ||
|
||
public Meta.Display display { get; construct; } | ||
public int monitor_index { get; construct; } | ||
public BackgroundSource background_source { get; construct; } | ||
public bool is_loaded { get; private set; default = false; } | ||
public GDesktop.BackgroundStyle style { get; construct; } | ||
public string? filename { get; construct; } | ||
public Meta.Background background { get; private set; } | ||
|
||
private Animation? animation = null; | ||
private Gee.HashMap<string,ulong> file_watches; | ||
private Cancellable cancellable; | ||
private uint update_animation_timeout_id = 0; | ||
|
||
public Background (Meta.Display display, int monitor_index, string? filename, | ||
BackgroundSource background_source, GDesktop.BackgroundStyle style) { | ||
Object (display: display, | ||
monitor_index: monitor_index, | ||
background_source: background_source, | ||
style: style, | ||
filename: filename); | ||
} | ||
|
||
construct { | ||
background = new Meta.Background (display); | ||
background.set_data<unowned Background> ("delegate", this); | ||
|
||
file_watches = new Gee.HashMap<string,ulong> (); | ||
cancellable = new Cancellable (); | ||
|
||
background_source.changed.connect (settings_changed); | ||
|
||
load (); | ||
} | ||
|
||
public void destroy () { | ||
cancellable.cancel (); | ||
remove_animation_timeout (); | ||
|
||
var cache = BackgroundCache.get_default (); | ||
|
||
foreach (var watch in file_watches.values) { | ||
cache.disconnect (watch); | ||
} | ||
|
||
background_source.changed.disconnect (settings_changed); | ||
} | ||
|
||
public void update_resolution () { | ||
if (animation != null) { | ||
remove_animation_timeout (); | ||
update_animation (); | ||
} | ||
} | ||
|
||
private void set_loaded () { | ||
if (is_loaded) | ||
return; | ||
|
||
is_loaded = true; | ||
|
||
Idle.add (() => { | ||
loaded (); | ||
return Source.REMOVE; | ||
}); | ||
} | ||
|
||
private void load_pattern () { | ||
string color_string; | ||
var settings = background_source.gnome_background_settings; | ||
|
||
color_string = settings.get_string ("primary-color"); | ||
var color = Clutter.Color.from_string (color_string); | ||
|
||
var shading_type = settings.get_enum ("color-shading-type"); | ||
|
||
if (shading_type == GDesktop.BackgroundShading.SOLID) { | ||
background.set_color (color); | ||
} else { | ||
color_string = settings.get_string ("secondary-color"); | ||
var second_color = Clutter.Color.from_string (color_string); | ||
background.set_gradient ((GDesktop.BackgroundShading) shading_type, color, second_color); | ||
} | ||
} | ||
|
||
private void watch_file (string filename) { | ||
if (file_watches.has_key (filename)) | ||
return; | ||
|
||
var cache = BackgroundCache.get_default (); | ||
|
||
cache.monitor_file (filename); | ||
|
||
file_watches[filename] = cache.file_changed.connect ((changed_file) => { | ||
if (changed_file == filename) { | ||
var image_cache = Meta.BackgroundImageCache.get_default (); | ||
image_cache.purge (File.new_for_path (changed_file)); | ||
changed (); | ||
} | ||
}); | ||
} | ||
|
||
private void remove_animation_timeout () { | ||
if (update_animation_timeout_id != 0) { | ||
Source.remove (update_animation_timeout_id); | ||
update_animation_timeout_id = 0; | ||
} | ||
} | ||
|
||
private void finish_animation (string[] files) { | ||
set_loaded (); | ||
|
||
if (files.length > 1) | ||
background.set_blend (File.new_for_path (files[0]), File.new_for_path (files[1]), animation.transition_progress, style); | ||
else if (files.length > 0) | ||
background.set_file (File.new_for_path (files[0]), style); | ||
else | ||
background.set_file (null, style); | ||
|
||
queue_update_animation (); | ||
} | ||
|
||
private void update_animation () { | ||
update_animation_timeout_id = 0; | ||
|
||
animation.update (display.get_monitor_geometry (monitor_index)); | ||
var files = animation.key_frame_files; | ||
|
||
var cache = Meta.BackgroundImageCache.get_default (); | ||
var num_pending_images = files.length; | ||
for (var i = 0; i < files.length; i++) { | ||
watch_file (files[i]); | ||
|
||
var image = cache.load (File.new_for_path (files[i])); | ||
|
||
if (image.is_loaded ()) { | ||
num_pending_images--; | ||
if (num_pending_images == 0) { | ||
finish_animation (files); | ||
} | ||
} else { | ||
ulong handler = 0; | ||
handler = image.loaded.connect (() => { | ||
image.disconnect (handler); | ||
if (--num_pending_images == 0) { | ||
finish_animation (files); | ||
} | ||
}); | ||
} | ||
} | ||
} | ||
|
||
private void queue_update_animation () { | ||
if (update_animation_timeout_id != 0) | ||
return; | ||
|
||
if (cancellable == null || cancellable.is_cancelled ()) | ||
return; | ||
|
||
if (animation.transition_duration == 0) | ||
return; | ||
|
||
var n_steps = 255.0 / ANIMATION_OPACITY_STEP_INCREMENT; | ||
var time_per_step = (animation.transition_duration * 1000) / n_steps; | ||
|
||
var interval = (uint32) Math.fmax (ANIMATION_MIN_WAKEUP_INTERVAL * 1000, time_per_step); | ||
|
||
if (interval > uint32.MAX) | ||
return; | ||
|
||
update_animation_timeout_id = Timeout.add (interval, () => { | ||
update_animation_timeout_id = 0; | ||
update_animation (); | ||
return Source.REMOVE; | ||
}); | ||
} | ||
|
||
private async void load_animation (string filename) { | ||
animation = yield BackgroundCache.get_default ().get_animation (filename); | ||
|
||
if (animation == null || cancellable.is_cancelled ()) { | ||
set_loaded (); | ||
return; | ||
} | ||
|
||
update_animation (); | ||
watch_file (filename); | ||
} | ||
|
||
private void load_image (string filename) { | ||
background.set_file (File.new_for_path (filename), style); | ||
watch_file (filename); | ||
|
||
var cache = Meta.BackgroundImageCache.get_default (); | ||
var image = cache.load (File.new_for_path (filename)); | ||
if (image.is_loaded ()) | ||
set_loaded (); | ||
else { | ||
ulong handler = 0; | ||
handler = image.loaded.connect (() => { | ||
set_loaded (); | ||
image.disconnect (handler); | ||
}); | ||
} | ||
} | ||
|
||
private void load_file (string filename) { | ||
if (filename.has_suffix (".xml")) | ||
load_animation.begin (filename); | ||
else | ||
load_image (filename); | ||
} | ||
|
||
private void load () { | ||
load_pattern (); | ||
|
||
if (filename == null) | ||
set_loaded (); | ||
else | ||
load_file (filename); | ||
} | ||
|
||
private void settings_changed () { | ||
changed (); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
/* | ||
* SPDX-License-Identifier: GPL-3.0-or-later | ||
* SPDX-FileCopyrightText: 2024 elementary, Inc. (https://elementary.io) | ||
* 2014 Tom Beckmann | ||
*/ | ||
|
||
namespace GreeterCompositor { | ||
public class BackgroundCache : Object { | ||
private static BackgroundCache? instance = null; | ||
|
||
public static unowned BackgroundCache get_default () { | ||
if (instance == null) | ||
instance = new BackgroundCache (); | ||
|
||
return instance; | ||
} | ||
|
||
public signal void file_changed (string filename); | ||
|
||
private Gee.HashMap<string,FileMonitor> file_monitors; | ||
private BackgroundSource background_source; | ||
|
||
private Animation animation; | ||
|
||
public BackgroundCache () { | ||
Object (); | ||
} | ||
|
||
construct { | ||
file_monitors = new Gee.HashMap<string,FileMonitor> (); | ||
} | ||
|
||
public void monitor_file (string filename) { | ||
if (file_monitors.has_key (filename)) | ||
return; | ||
|
||
var file = File.new_for_path (filename); | ||
try { | ||
var monitor = file.monitor (FileMonitorFlags.NONE, null); | ||
monitor.changed.connect (() => { | ||
file_changed (filename); | ||
}); | ||
|
||
file_monitors[filename] = monitor; | ||
} catch (Error e) { | ||
warning ("Failed to monitor %s: %s", filename, e.message); | ||
} | ||
} | ||
|
||
public async Animation get_animation (string filename) { | ||
if (animation != null && animation.filename == filename) { | ||
Idle.add (() => { | ||
get_animation.callback (); | ||
return Source.REMOVE; | ||
}); | ||
yield; | ||
|
||
return animation; | ||
} | ||
|
||
var animation = new Animation (filename); | ||
|
||
yield animation.load (); | ||
|
||
Idle.add (() => { | ||
get_animation.callback (); | ||
return Source.REMOVE; | ||
}); | ||
yield; | ||
|
||
return animation; | ||
} | ||
|
||
public BackgroundSource get_background_source (Meta.Display display) { | ||
if (background_source == null) { | ||
background_source = new BackgroundSource (display); | ||
background_source.use_count = 1; | ||
} else | ||
background_source.use_count++; | ||
|
||
return background_source; | ||
} | ||
|
||
public void release_background_source () { | ||
if (--background_source.use_count == 0) { | ||
background_source.destroy (); | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.