Skip to content

Commit

Permalink
Add nightlight support using gammastep - closes #649
Browse files Browse the repository at this point in the history
  • Loading branch information
fossfreedom committed Feb 6, 2025
1 parent 0b8a8dd commit 7822989
Show file tree
Hide file tree
Showing 5 changed files with 250 additions and 0 deletions.
1 change: 1 addition & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ cdata = configuration_data()
if get_option('with-runtime-dependencies')
find_program('wlopm', required: true)
find_program('swayidle', required: true)
find_program('gammastep', required: true)
found_gtklock = find_program('gtklock', required: false)
if found_gtklock.found() == false
find_program('swaylock', required: true)
Expand Down
68 changes: 68 additions & 0 deletions src/daemon/gammastep.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Global settings
[general]
# Set the day and night screen temperatures
temp-day=5700
temp-night=3500

# Disable the smooth fade between temperatures when Redshift starts and stops.
# 0 will cause an immediate change between screen temperatures.
# 1 will gradually apply the new screen temperature over a couple of seconds.
fade=1

# Solar elevation thresholds.
# By default, Redshift will use the current elevation of the sun to determine
# whether it is daytime, night or in transition (dawn/dusk). When the sun is
# above the degrees specified with elevation-high it is considered daytime and
# below elevation-low it is considered night.
#elevation-high=3
#elevation-low=-6

# Custom dawn/dusk intervals.
# Instead of using the solar elevation, the time intervals of dawn and dusk
# can be specified manually. The times must be specified as HH:MM in 24-hour
# format.
#dawn-time=6:00-7:45
#dusk-time=18:35-20:15

# Set the screen brightness. Default is 1.0.
#brightness=0.9
# It is also possible to use different settings for day and night
# since version 1.8.
#brightness-day=0.7
#brightness-night=0.4
# Set the screen gamma (for all colors, or each color channel
# individually)
gamma=0.8
#gamma=0.8:0.7:0.8
# This can also be set individually for day and night since
# version 1.10.
#gamma-day=0.8:0.7:0.8
#gamma-night=0.6

# Set the location-provider: 'geoclue2', 'manual'.
# The location provider settings are in a different section.
location-provider=manual

# Set the adjustment-method: 'randr', 'vidmode', 'drm', 'wayland'.
# 'randr' is the preferred X11 method, 'vidmode' is an older API
# that works in some cases when 'randr' does not.
# The adjustment method settings are in a different section.
adjustment-method=wayland

# Configuration of the location-provider:
# type 'gammastep -l PROVIDER:help' to see the settings.
# ex: 'gammastep -l manual:help'
# Keep in mind that longitudes west of Greenwich (e.g. the Americas)
# are negative numbers.
#[manual]
#lat=48.1
#lon=11.6

# Configuration of the adjustment-method
# type 'gammastep -m METHOD:help' to see the settings.
# ex: 'gammastep -m randr:help'
# In this example, randr is configured to adjust only screen 0.
# Note that the numbering starts from 0, so this is actually the first screen.
# If this option is not specified, Redshift will try to adjust _all_ screens.
#[randr]
#screen=0
6 changes: 6 additions & 0 deletions src/daemon/manager.vala
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ namespace Budgie {

/* Screenlock */
Budgie.Screenlock? screenlock;

/* NightLight */
Budgie.NightLightManager? nightlight;

/**
* Construct a new ServiceManager and initialiase appropriately
*/
Expand Down Expand Up @@ -64,6 +68,8 @@ namespace Budgie {

screenlock = Screenlock.init();
screenlock.setup_dbus();

nightlight = new NightLightManager();
}

/**
Expand Down
5 changes: 5 additions & 0 deletions src/daemon/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ daemon_sources = [
'main.vala',
'manager.vala',
'menus.vala',
'nightlight.vala',
'osd.vala',
'settings.vala',
'screenlock.vala',
Expand Down Expand Up @@ -126,6 +127,10 @@ install_data('icons/org.buddiesofbudgie.BudgieScreenshot.svg',
install_dir: join_paths(datadir, 'icons', 'hicolor', 'scalable', 'apps')
)

install_data('gammastep.config',
install_dir: join_paths(datadir, 'budgie-desktop')
)

# Now merge the translations of the .desktop.in to a .desktop
custom_target('org.buddiesofbudgie.BudgieScreenshot',
input : 'org.buddiesofbudgie.BudgieScreenshot.desktop.in',
Expand Down
170 changes: 170 additions & 0 deletions src/daemon/nightlight.vala
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
/*
* This file is part of budgie-desktop
*
* Copyright Budgie Desktop Developers
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/

namespace Budgie {
public class NightLightManager : GLib.Object {
private Settings settings;
private const string config_file = "gammastep.config";
private string local_config_path;

public NightLightManager() {
// Initialise the GSettings schema
settings = new Settings("org.gnome.settings-daemon.plugins.color");

// Ensure the local configuration file exists
local_config_path = Path.build_filename(GLib.Environment.get_user_config_dir(), "budgie-desktop", config_file);
ensure_local_config_exists();

// Connect to the "changed" signal for the relevant keys
settings.changed.connect(on_settings_changed);

on_settings_changed(settings, "");
}

private void on_settings_changed(Settings settings, string key) {
bool night_light_enabled = settings.get_boolean("night-light-enabled");
if (night_light_enabled) {
update_gammastep_config();
run_gammastep();
} else {
stop_gammastep();
}
}

private string? search_for_config() {
// Check if a local gammastep config_file exists - if doesn't
// use the budgie-desktop shared file - or the distro variant if it exists
// to populate the local config folder

string[] search_path = {local_config_path};
foreach (string system_dir in GLib.Environment.get_system_data_dirs()) {
search_path += Path.build_filename(system_dir, "budgie-desktop", "distro-"+config_file);
search_path += Path.build_filename(system_dir, "budgie-desktop", config_file);
}

string path = "";
foreach (unowned string p in search_path) {
File search_config_file = File.new_for_path(p);
if (search_config_file.query_exists(null)) {
path = p;
break;
}
}

if (path == "") {
critical("Could not find an existing "+config_file+" or a shipped budgie equivalent");
return null;
}

return path;
}


private void ensure_local_config_exists() {
string? default_config_path = search_for_config();

if (default_config_path != null && default_config_path != local_config_path) {
try {
// Copy the default configuration file to the local configuration file location
File dir = File.new_for_path(Path.get_dirname(local_config_path));
dir.make_directory_with_parents(null);
File default_config_file = File.new_for_path(default_config_path);
File local_config_file = File.new_for_path(local_config_path);
default_config_file.copy(local_config_file, FileCopyFlags.NONE, null, null);
} catch (Error e) {
warning("Failed to copy configuration file: %s\n", e.message);
}
}
}

private void update_gammastep_config() {
try {
// Load the configuration file
KeyFile key_file = new KeyFile();
key_file.load_from_file(local_config_path, KeyFileFlags.NONE);

// Get the value of the night-light-temperature key from GSettings
uint night_light_temperature = settings.get_uint("night-light-temperature");

// Update the temp-night key in the configuration file
key_file.set_uint64("general", "temp-night", night_light_temperature);

// Check if night-light-schedule-automatic is enabled and update location-provider
bool schedule_automatic = settings.get_boolean("night-light-schedule-automatic");
if (schedule_automatic) {
key_file.set_string("general", "location-provider", "geoclue2");
} else {
key_file.set_string("general", "location-provider", "manual");
}

// Get the value of the night-light-schedule-from key from GSettings
double night_light_schedule_from = settings.get_double("night-light-schedule-from");

// Convert the double value to an integer hour in 24-hour format
int dusk_hour = (int) night_light_schedule_from;

// Update the dusk-time key in the configuration file
key_file.set_string("general", "dusk-time", dusk_hour.to_string()+":00");

// Get the value of the night-light-schedule-to key from GSettings
double night_light_schedule_to = settings.get_double("night-light-schedule-to");

// Convert the double value to an integer hour in 24-hour format
int dawn_hour = (int) night_light_schedule_to;

// Update the dawn-time key in the configuration file
key_file.set_string("general", "dawn-time", dawn_hour.to_string()+":00");

// Save the updated configuration file
key_file.save_to_file(local_config_path);
} catch (Error e) {
warning("Failed to update Gammastep configuration file: %s\n", e.message);
}
}

private void run_gammastep() {
try {
// Run gammastep with the configuration file
string[] spawn_args = {"gammastep", "-o", "-c", local_config_path};
string[] spawn_env = Environ.get();

Process.spawn_async("/",
spawn_args,
spawn_env,
SpawnFlags.SEARCH_PATH | SpawnFlags.DO_NOT_REAP_CHILD,
null,
null);
} catch (Error e) {
warning("Failed to start gammastep: %s\n", e.message);
}
}

private void stop_gammastep() {
try {
string[] spawn_args = {"killall", "-s", "SIGHUP", "gammastep"};
string[] spawn_env = Environ.get();

Process.spawn_sync ("/",
spawn_args,
spawn_env,
SpawnFlags.SEARCH_PATH |
SpawnFlags.STDERR_TO_DEV_NULL |
SpawnFlags.STDOUT_TO_DEV_NULL,
null,
null,
null,
null);
} catch (Error e) {
warning("Failed to stop gammastep process: %s\n", e.message);
}
}
}
}

0 comments on commit 7822989

Please sign in to comment.