Make the new login button stuff more automatic
By default it'll look at your environment to try to figure out which display manager is used in order to start a new session. We first try the org.freedesktop.DisplayManager dbus interface, and if that fails, inspect XDG_SESSION_DESKTOP to try to figure out which display manager is running. The user can also still specify the correct display manager, or a custom command.
This commit is contained in:
parent
99ffa88657
commit
dda1a53856
3
Cargo.lock
generated
3
Cargo.lock
generated
@ -318,6 +318,7 @@ dependencies = [
|
|||||||
"bscreensaver-util",
|
"bscreensaver-util",
|
||||||
"glib",
|
"glib",
|
||||||
"gtk",
|
"gtk",
|
||||||
|
"log",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -347,9 +348,11 @@ dependencies = [
|
|||||||
"humantime",
|
"humantime",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"libc",
|
"libc",
|
||||||
|
"shell-words",
|
||||||
"toml",
|
"toml",
|
||||||
"xcb",
|
"xcb",
|
||||||
"xdg",
|
"xdg",
|
||||||
|
"zbus",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -4,9 +4,9 @@ use gethostname::gethostname;
|
|||||||
use glib::GString;
|
use glib::GString;
|
||||||
use gtk::{prelude::*, Button, Entry, Label, Plug, Window};
|
use gtk::{prelude::*, Button, Entry, Label, Plug, Window};
|
||||||
use log::{debug, error, warn};
|
use log::{debug, error, warn};
|
||||||
use std::{io::{self, Write}, process::{exit, Command}, rc::Rc, thread, time::Duration};
|
use std::{io::{self, Write}, process::exit, rc::Rc, thread, time::Duration};
|
||||||
|
|
||||||
use bscreensaver_util::{init_logging, settings::Configuration};
|
use bscreensaver_util::{init_logging, settings::Configuration, desktop::NewLoginCommand};
|
||||||
|
|
||||||
const DIALOG_UPDATE_INTERVAL: Duration = Duration::from_millis(100);
|
const DIALOG_UPDATE_INTERVAL: Duration = Duration::from_millis(100);
|
||||||
const DIALOG_TIMEOUT: Duration = Duration::from_secs(60);
|
const DIALOG_TIMEOUT: Duration = Duration::from_secs(60);
|
||||||
@ -15,11 +15,13 @@ fn main() -> anyhow::Result<()> {
|
|||||||
init_logging("BSCREENSAVER_DIALOG_GTK3_LOG");
|
init_logging("BSCREENSAVER_DIALOG_GTK3_LOG");
|
||||||
glib::log_set_default_handler(glib::rust_log_handler);
|
glib::log_set_default_handler(glib::rust_log_handler);
|
||||||
|
|
||||||
let mut config = Configuration::load()?;
|
let config = Configuration::load()?;
|
||||||
let new_login_command = config.new_login_command
|
let new_login_command =
|
||||||
.take()
|
if config.new_login_command == NewLoginCommand::Disabled {
|
||||||
.map(|nlc| shell_words::split(&nlc))
|
None
|
||||||
.transpose()?;
|
} else {
|
||||||
|
Some(config.new_login_command.clone())
|
||||||
|
};
|
||||||
|
|
||||||
let standalone = std::env::var("BSCREENSAVER_DIALOG_STANDALONE").is_ok();
|
let standalone = std::env::var("BSCREENSAVER_DIALOG_STANDALONE").is_ok();
|
||||||
|
|
||||||
@ -245,14 +247,14 @@ fn main() -> anyhow::Result<()> {
|
|||||||
.label("New Login")
|
.label("New Login")
|
||||||
.build();
|
.build();
|
||||||
new_login_button.connect_clicked(move |_| {
|
new_login_button.connect_clicked(move |_| {
|
||||||
let cmd = &new_login_command[0];
|
let new_login_command = new_login_command.clone();
|
||||||
let empty = Vec::<String>::new();
|
thread::spawn(move || {
|
||||||
let args = if new_login_command.len() > 1 { &new_login_command[1..] } else { &empty };
|
if let Err(err) = new_login_command.run() {
|
||||||
if let Err(err) = Command::new(cmd).args(args).spawn() {
|
warn!("Failed to run new login command: {}", err);
|
||||||
warn!("Failed to run new login command: {}", err);
|
} else {
|
||||||
} else {
|
exit(1);
|
||||||
exit(1);
|
}
|
||||||
}
|
});
|
||||||
});
|
});
|
||||||
hbox.pack_start(&new_login_button, false, true, 8);
|
hbox.pack_start(&new_login_button, false, true, 8);
|
||||||
}
|
}
|
||||||
|
@ -8,3 +8,4 @@ anyhow = "1"
|
|||||||
bscreensaver-util = { path = "../util" }
|
bscreensaver-util = { path = "../util" }
|
||||||
glib = "0.15"
|
glib = "0.15"
|
||||||
gtk = { version = "0.15", features = ["v3_20"] }
|
gtk = { version = "0.15", features = ["v3_20"] }
|
||||||
|
log = "0.4"
|
||||||
|
@ -1,17 +1,20 @@
|
|||||||
use gtk::{glib, prelude::*};
|
use gtk::{glib, prelude::*};
|
||||||
use glib::clone;
|
use glib::clone;
|
||||||
|
use log::warn;
|
||||||
use std::{env, process::exit, time::Duration};
|
use std::{env, process::exit, time::Duration};
|
||||||
|
|
||||||
use bscreensaver_util::settings::Configuration;
|
use bscreensaver_util::{init_logging, settings::Configuration, desktop::NewLoginCommand};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct Widgets {
|
struct Widgets {
|
||||||
lock_timeout: gtk::SpinButton,
|
lock_timeout: gtk::SpinButton,
|
||||||
blank_before_locking: gtk::SpinButton,
|
blank_before_locking: gtk::SpinButton,
|
||||||
new_login_command: gtk::Entry,
|
new_login_command_combo: gtk::ComboBoxText,
|
||||||
|
custom_new_login_command_entry: gtk::Entry,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> anyhow::Result<()> {
|
fn main() -> anyhow::Result<()> {
|
||||||
|
init_logging("BSCREENSAVER_SETTINGS");
|
||||||
let config = Configuration::load()?;
|
let config = Configuration::load()?;
|
||||||
|
|
||||||
let app = gtk::Application::builder()
|
let app = gtk::Application::builder()
|
||||||
@ -122,27 +125,83 @@ fn show_ui(app: >k::Application, config: &Configuration) {
|
|||||||
label_sg.add_widget(&label);
|
label_sg.add_widget(&label);
|
||||||
hbox.pack_start(&label, false, false, 0);
|
hbox.pack_start(&label, false, false, 0);
|
||||||
|
|
||||||
let new_login_command_entry = gtk::Entry::builder()
|
let vbox = gtk::Box::builder()
|
||||||
.text(config.new_login_command.as_ref().unwrap_or(&"".to_string()))
|
.orientation(gtk::Orientation::Vertical)
|
||||||
.width_chars(30)
|
.spacing(8)
|
||||||
.activates_default(true)
|
|
||||||
.build();
|
.build();
|
||||||
hbox.pack_start(&new_login_command_entry, false, false, 0);
|
hbox.pack_start(&vbox, true, true, 0);
|
||||||
|
|
||||||
|
let new_login_command_combo = gtk::ComboBoxText::builder()
|
||||||
|
.build();
|
||||||
|
new_login_command_combo.append_text(NewLoginCommand::Auto.as_str());
|
||||||
|
new_login_command_combo.append_text(NewLoginCommand::DisplayManagerDBus.as_str());
|
||||||
|
new_login_command_combo.append_text(NewLoginCommand::Gdm.as_str());
|
||||||
|
new_login_command_combo.append_text(NewLoginCommand::Kdm.as_str());
|
||||||
|
new_login_command_combo.append_text(NewLoginCommand::LightDm.as_str());
|
||||||
|
new_login_command_combo.append_text(NewLoginCommand::Lxdm.as_str());
|
||||||
|
new_login_command_combo.append_text(NewLoginCommand::Custom("".to_string()).as_str());
|
||||||
|
new_login_command_combo.append_text(NewLoginCommand::Disabled.as_str());
|
||||||
|
vbox.pack_start(&new_login_command_combo, false, false, 0);
|
||||||
|
|
||||||
|
let (custom_new_login_command_hbox, custom_new_login_command_entry, custom_new_login_command_button) = {
|
||||||
|
let hbox = gtk::Box::builder()
|
||||||
|
.orientation(gtk::Orientation::Horizontal)
|
||||||
|
.spacing(8)
|
||||||
|
.sensitive(false)
|
||||||
|
.build();
|
||||||
|
topvbox.pack_start(&hbox, false, false, 0);
|
||||||
|
|
||||||
|
let spacer = gtk::Box::builder()
|
||||||
|
.orientation(gtk::Orientation::Horizontal)
|
||||||
|
.spacing(0)
|
||||||
|
.build();
|
||||||
|
label_sg.add_widget(&spacer);
|
||||||
|
hbox.pack_start(&spacer, false, false, 0);
|
||||||
|
|
||||||
|
let label = gtk::Label::builder()
|
||||||
|
.label("Custom Command:")
|
||||||
|
.tooltip_text("Custom command to run when the 'New Login' button is clicked in the unlock dialog")
|
||||||
|
.xalign(0.0)
|
||||||
|
.build();
|
||||||
|
hbox.pack_start(&label, false, false, 0);
|
||||||
|
|
||||||
|
let entry = gtk::Entry::builder()
|
||||||
|
.width_chars(30)
|
||||||
|
.activates_default(true)
|
||||||
|
.build();
|
||||||
|
hbox.pack_start(&entry, false, false, 0);
|
||||||
|
|
||||||
|
let button = gtk::Button::from_icon_name(Some("folder-open"), gtk::IconSize::Button);
|
||||||
|
hbox.pack_start(&button, false, false, 0);
|
||||||
|
|
||||||
|
(hbox, entry, button)
|
||||||
|
};
|
||||||
|
|
||||||
|
match &config.new_login_command {
|
||||||
|
NewLoginCommand::Custom(cmd) => {
|
||||||
|
custom_new_login_command_entry.set_text(cmd.as_str());
|
||||||
|
custom_new_login_command_hbox.set_sensitive(true);
|
||||||
|
},
|
||||||
|
_ => (),
|
||||||
|
};
|
||||||
|
new_login_command_combo.set_active(Some(config.new_login_command.ord()));
|
||||||
|
new_login_command_combo.connect_changed(clone!(@strong custom_new_login_command_hbox => move |combo| {
|
||||||
|
let sensitive = combo.active().unwrap_or(0) == NewLoginCommand::Custom("".to_string()).ord();
|
||||||
|
custom_new_login_command_hbox.set_sensitive(sensitive);
|
||||||
|
}));
|
||||||
|
|
||||||
let widgets = Widgets {
|
let widgets = Widgets {
|
||||||
lock_timeout: lock_timeout_spinbutton.clone(),
|
lock_timeout: lock_timeout_spinbutton.clone(),
|
||||||
blank_before_locking: blank_before_locking_spinbutton.clone(),
|
blank_before_locking: blank_before_locking_spinbutton.clone(),
|
||||||
new_login_command: new_login_command_entry.clone(),
|
new_login_command_combo: new_login_command_combo.clone(),
|
||||||
|
custom_new_login_command_entry: custom_new_login_command_entry.clone(),
|
||||||
};
|
};
|
||||||
mainwin.connect_delete_event(clone!(@strong config, @strong widgets, @strong app, @strong mainwin => move |_,_| {
|
mainwin.connect_delete_event(clone!(@strong config, @strong widgets, @strong app, @strong mainwin => move |_,_| {
|
||||||
Inhibit(!confirm_cancel(&config, &widgets, &mainwin))
|
Inhibit(!confirm_cancel(&config, &widgets, &mainwin))
|
||||||
}));
|
}));
|
||||||
|
custom_new_login_command_button.connect_clicked(clone!(@strong mainwin, @strong widgets => move |_| {
|
||||||
let button = gtk::Button::from_icon_name(Some("folder-open"), gtk::IconSize::Button);
|
|
||||||
button.connect_clicked(clone!(@strong mainwin, @strong widgets => move |_| {
|
|
||||||
run_file_chooser(&mainwin, &widgets);
|
run_file_chooser(&mainwin, &widgets);
|
||||||
}));
|
}));
|
||||||
hbox.pack_start(&button, false, false, 0);
|
|
||||||
|
|
||||||
let button_box = gtk::ButtonBox::builder()
|
let button_box = gtk::ButtonBox::builder()
|
||||||
.spacing(8)
|
.spacing(8)
|
||||||
@ -177,7 +236,7 @@ fn show_ui(app: >k::Application, config: &Configuration) {
|
|||||||
|
|
||||||
fn run_file_chooser(mainwin: >k::ApplicationWindow, widgets: &Widgets) {
|
fn run_file_chooser(mainwin: >k::ApplicationWindow, widgets: &Widgets) {
|
||||||
let file_chooser = gtk::FileChooserNative::new(
|
let file_chooser = gtk::FileChooserNative::new(
|
||||||
Some("New Login Command"),
|
Some("Custom New Login Command"),
|
||||||
Some(mainwin),
|
Some(mainwin),
|
||||||
gtk::FileChooserAction::Open,
|
gtk::FileChooserAction::Open,
|
||||||
Some("Select"),
|
Some("Select"),
|
||||||
@ -187,7 +246,7 @@ fn run_file_chooser(mainwin: >k::ApplicationWindow, widgets: &Widgets) {
|
|||||||
file_chooser.hide();
|
file_chooser.hide();
|
||||||
if response == gtk::ResponseType::Accept {
|
if response == gtk::ResponseType::Accept {
|
||||||
if let Some(filename) = file_chooser.filename() {
|
if let Some(filename) = file_chooser.filename() {
|
||||||
widgets.new_login_command.set_text(&filename.to_string_lossy());
|
widgets.custom_new_login_command_entry.set_text(&filename.to_string_lossy());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -243,7 +302,19 @@ fn build_new_configuration(old_config: &Configuration, widgets: &Widgets) -> (Co
|
|||||||
let mut new_config = old_config.clone();
|
let mut new_config = old_config.clone();
|
||||||
new_config.lock_timeout = Duration::from_secs(widgets.lock_timeout.adjustment().value() as u64 * 60);
|
new_config.lock_timeout = Duration::from_secs(widgets.lock_timeout.adjustment().value() as u64 * 60);
|
||||||
new_config.blank_before_locking = Duration::from_secs(widgets.blank_before_locking.adjustment().value() as u64 * 60);
|
new_config.blank_before_locking = Duration::from_secs(widgets.blank_before_locking.adjustment().value() as u64 * 60);
|
||||||
new_config.new_login_command = Some(widgets.new_login_command.text()).filter(|s| !s.is_empty()).map(|s| s.to_string());
|
|
||||||
|
new_config.new_login_command = match NewLoginCommand::try_from(widgets.new_login_command_combo.active().unwrap_or(0) as u32) {
|
||||||
|
Ok(NewLoginCommand::Custom(_)) => Some(widgets.custom_new_login_command_entry.text())
|
||||||
|
.filter(|s| !s.is_empty())
|
||||||
|
.map(|s| NewLoginCommand::Custom(s.to_string()))
|
||||||
|
.unwrap_or(NewLoginCommand::Auto),
|
||||||
|
Ok(nlc) => nlc,
|
||||||
|
Err(_) => {
|
||||||
|
warn!("BUG: couldn't figure out new login command type from combo box");
|
||||||
|
NewLoginCommand::Auto
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
let changed = old_config != &new_config;
|
let changed = old_config != &new_config;
|
||||||
(new_config, changed)
|
(new_config, changed)
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,8 @@ env_logger = "0.9"
|
|||||||
humantime = "2"
|
humantime = "2"
|
||||||
lazy_static = "1"
|
lazy_static = "1"
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
|
shell-words = "1"
|
||||||
toml = "0.5"
|
toml = "0.5"
|
||||||
xcb = { git = "https://github.com/rust-x-bindings/rust-xcb", rev = "d09b5f91bc07d56673f1bc0d6c7ecd72b5ff7b3e", features = ["randr", "screensaver", "xfixes"] }
|
xcb = { git = "https://github.com/rust-x-bindings/rust-xcb", rev = "d09b5f91bc07d56673f1bc0d6c7ecd72b5ff7b3e", features = ["randr", "screensaver", "xfixes"] }
|
||||||
xdg = "2"
|
xdg = "2"
|
||||||
|
zbus = "2"
|
||||||
|
171
util/src/desktop.rs
Normal file
171
util/src/desktop.rs
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
use std::{env, fmt, process::Command};
|
||||||
|
|
||||||
|
const GDM_CMD: &[&str] = &[ "gdmflexiserver", "-ls" ];
|
||||||
|
const KDM_CMD: &[&str] = &[ "kdmctl", "reserve" ];
|
||||||
|
const LIGHTDM_CMD: &[&str] = &[ "dm-tool", "switch-to-greeter" ];
|
||||||
|
const LXDM_CMD: &[&str] = &[ "lxdm", "-c", "USER_SWITCH" ];
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub enum NewLoginCommand {
|
||||||
|
Auto,
|
||||||
|
DisplayManagerDBus,
|
||||||
|
Gdm,
|
||||||
|
Kdm,
|
||||||
|
LightDm,
|
||||||
|
Lxdm,
|
||||||
|
Custom(String),
|
||||||
|
Disabled,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NewLoginCommand {
|
||||||
|
pub fn run(&self) -> anyhow::Result<()> {
|
||||||
|
match self {
|
||||||
|
Self::Auto => auto_run(),
|
||||||
|
Self::DisplayManagerDBus => call_dbus(),
|
||||||
|
Self::Gdm => run(GDM_CMD),
|
||||||
|
Self::Kdm => run(KDM_CMD),
|
||||||
|
Self::LightDm => run(LIGHTDM_CMD),
|
||||||
|
Self::Lxdm => run(LXDM_CMD),
|
||||||
|
Self::Custom(cmd) => shell_words::split(cmd.as_str())
|
||||||
|
.map_err(|err| err.into())
|
||||||
|
.and_then(|argvec| {
|
||||||
|
let argv: Vec<&str> = argvec.iter().map(|s| s.as_str()).collect();
|
||||||
|
run(&argv).map_err(|err| err.into())
|
||||||
|
}),
|
||||||
|
Self::Disabled => Ok(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_str(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Self::Auto => "Auto",
|
||||||
|
Self::DisplayManagerDBus => "DBus (desktop-agnostic)",
|
||||||
|
Self::Gdm => "GDM (GNOME)",
|
||||||
|
Self::Kdm => "KDM (KDE)",
|
||||||
|
Self::LightDm => "LightDM",
|
||||||
|
Self::Lxdm => "LXDM (LXDE)",
|
||||||
|
Self::Custom(_) => "Custom",
|
||||||
|
Self::Disabled => "Disabled",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ord(&self) -> u32 {
|
||||||
|
match self {
|
||||||
|
Self::Auto => 0,
|
||||||
|
Self::DisplayManagerDBus => 1,
|
||||||
|
Self::Gdm => 2,
|
||||||
|
Self::Kdm => 3,
|
||||||
|
Self::LightDm => 4,
|
||||||
|
Self::Lxdm => 5,
|
||||||
|
Self::Custom(_) => 6,
|
||||||
|
Self::Disabled => 7,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for NewLoginCommand {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.as_str())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<u32> for NewLoginCommand {
|
||||||
|
type Error = anyhow::Error;
|
||||||
|
fn try_from(value: u32) -> Result<Self, Self::Error> {
|
||||||
|
match value {
|
||||||
|
0 => Ok(Self::Auto),
|
||||||
|
1 => Ok(Self::DisplayManagerDBus),
|
||||||
|
2 => Ok(Self::Gdm),
|
||||||
|
3 => Ok(Self::Kdm),
|
||||||
|
4 => Ok(Self::LightDm),
|
||||||
|
5 => Ok(Self::Lxdm),
|
||||||
|
6 => Ok(Self::Custom("".to_string())),
|
||||||
|
7 => Ok(Self::Disabled),
|
||||||
|
other => Err(anyhow::anyhow!("Unknown ordinal for NewLoginCommand: {}", other)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<&toml::Value> for NewLoginCommand {
|
||||||
|
type Error = anyhow::Error;
|
||||||
|
fn try_from(value: &toml::Value) -> Result<Self, Self::Error> {
|
||||||
|
if let Some(s) = value.as_str() {
|
||||||
|
return match s {
|
||||||
|
"auto" => Ok(Self::Auto),
|
||||||
|
"dbus" => Ok(Self::DisplayManagerDBus),
|
||||||
|
"gdm" => Ok(Self::Gdm),
|
||||||
|
"kdm" => Ok(Self::Kdm),
|
||||||
|
"lightdm" => Ok(Self::LightDm),
|
||||||
|
"lxdm" => Ok(Self::Lxdm),
|
||||||
|
"disabled" => Ok(Self::Disabled),
|
||||||
|
other => Err(anyhow::anyhow!("Unknown value '{}' for new login command", other)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(arr) = value.as_array() {
|
||||||
|
let argv = arr.into_iter()
|
||||||
|
.map(|v| v.as_str().map(|s| s.to_string()).ok_or_else(|| anyhow::anyhow!("Custom command must be made of strings")))
|
||||||
|
.collect::<anyhow::Result<Vec<String>>>()?;
|
||||||
|
return Ok(Self::Custom(shell_words::join(argv)))
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(anyhow::anyhow!("Unknown value for new login command"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryInto<toml::Value> for NewLoginCommand {
|
||||||
|
type Error = anyhow::Error;
|
||||||
|
fn try_into(self) -> Result<toml::Value, Self::Error> {
|
||||||
|
match self {
|
||||||
|
Self::Auto => Ok(toml::Value::String("auto".to_string())),
|
||||||
|
Self::DisplayManagerDBus => Ok(toml::Value::String("dbus".to_string())),
|
||||||
|
Self::Gdm => Ok(toml::Value::String("gdm".to_string())),
|
||||||
|
Self::Kdm => Ok(toml::Value::String("kdm".to_string())),
|
||||||
|
Self::LightDm => Ok(toml::Value::String("lightdm".to_string())),
|
||||||
|
Self::Lxdm => Ok(toml::Value::String("lxdm".to_string())),
|
||||||
|
Self::Custom(cmd) => shell_words::split(cmd.as_str())
|
||||||
|
.map_err(|err| err.into())
|
||||||
|
.map(|words| toml::Value::Array(words.into_iter().map(|s| toml::Value::String(s)).collect())),
|
||||||
|
Self::Disabled => Ok(toml::Value::String("disabled".to_string())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn auto_run() -> anyhow::Result<()> {
|
||||||
|
if let Ok(_) = call_dbus() {
|
||||||
|
return Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(session_desktop) = env::var("XDG_SESSION_DESKTOP").map(|s| s.to_lowercase()).ok() {
|
||||||
|
match session_desktop.as_str() {
|
||||||
|
"gnome" | "gdm" => run(GDM_CMD),
|
||||||
|
"kde" | "kdm" => run(KDM_CMD),
|
||||||
|
"lightdm-session" => run(LIGHTDM_CMD),
|
||||||
|
"lxde" | "lxdm" => run(LXDM_CMD),
|
||||||
|
other => Err(anyhow::anyhow!("Couldn't determine how to start a new login session for session type {}", other)),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err(anyhow::anyhow!("Couldn't determine how to start a new login session"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call_dbus() -> anyhow::Result<()> {
|
||||||
|
let seat_path = env::var("XDG_SEAT_PATH")
|
||||||
|
.unwrap_or_else(|_| "/org/freedesktop/DisplayManager/Seat0".to_string());
|
||||||
|
let bus = zbus::blocking::Connection::system()?;
|
||||||
|
let proxy = zbus::blocking::Proxy::new(
|
||||||
|
&bus,
|
||||||
|
"org.freedesktop.DisplayManager",
|
||||||
|
seat_path,
|
||||||
|
"org.freedesktop.DisplayManager.Seat"
|
||||||
|
)?;
|
||||||
|
proxy.call("SwitchToGreeter", &())?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(argv: &[&str]) -> anyhow::Result<()> {
|
||||||
|
Command::new(argv[0])
|
||||||
|
.args(if argv.len() > 1 { &argv[1..argv.len()-1] } else { &[] })
|
||||||
|
.spawn()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
use std::{ffi::CStr, io};
|
use std::{ffi::CStr, io};
|
||||||
use xcb::x;
|
use xcb::x;
|
||||||
|
|
||||||
|
pub mod desktop;
|
||||||
pub mod settings;
|
pub mod settings;
|
||||||
|
|
||||||
pub const BSCREENSAVER_WM_CLASS: &[u8] = b"bscreensaver\0Bscreensaver\0";
|
pub const BSCREENSAVER_WM_CLASS: &[u8] = b"bscreensaver\0Bscreensaver\0";
|
||||||
|
@ -2,6 +2,8 @@ use anyhow::anyhow;
|
|||||||
use std::{fmt, fs::{self, File}, io::{Read, Write}, path::PathBuf, time::Duration};
|
use std::{fmt, fs::{self, File}, io::{Read, Write}, path::PathBuf, time::Duration};
|
||||||
use toml::Value;
|
use toml::Value;
|
||||||
|
|
||||||
|
use crate::desktop::NewLoginCommand;
|
||||||
|
|
||||||
const CONFIG_FILE_RELATIVE_PATH: &str = "bscreensaver/bscreensaver.toml";
|
const CONFIG_FILE_RELATIVE_PATH: &str = "bscreensaver/bscreensaver.toml";
|
||||||
|
|
||||||
const LOCK_TIMEOUT: &str = "lock-timeout";
|
const LOCK_TIMEOUT: &str = "lock-timeout";
|
||||||
@ -51,7 +53,7 @@ pub struct Configuration {
|
|||||||
pub lock_timeout: Duration,
|
pub lock_timeout: Duration,
|
||||||
pub blank_before_locking: Duration,
|
pub blank_before_locking: Duration,
|
||||||
pub dialog_backend: DialogBackend,
|
pub dialog_backend: DialogBackend,
|
||||||
pub new_login_command: Option<String>,
|
pub new_login_command: NewLoginCommand,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Configuration {
|
impl Configuration {
|
||||||
@ -80,7 +82,7 @@ impl Configuration {
|
|||||||
};
|
};
|
||||||
config.new_login_command = match config_toml.get("new-login-command") {
|
config.new_login_command = match config_toml.get("new-login-command") {
|
||||||
None => config.new_login_command,
|
None => config.new_login_command,
|
||||||
Some(val) => val.as_str().map(|s| s.to_string()),
|
Some(val) => val.try_into().unwrap_or(NewLoginCommand::Auto),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,9 +101,7 @@ impl Configuration {
|
|||||||
config_map.insert(LOCK_TIMEOUT.to_string(), Value::String(format_duration(self.lock_timeout).to_string()));
|
config_map.insert(LOCK_TIMEOUT.to_string(), Value::String(format_duration(self.lock_timeout).to_string()));
|
||||||
config_map.insert(BLANK_BEFORE_LOCKING.to_string(), Value::String(format_duration(self.blank_before_locking).to_string()));
|
config_map.insert(BLANK_BEFORE_LOCKING.to_string(), Value::String(format_duration(self.blank_before_locking).to_string()));
|
||||||
config_map.insert(DIALOG_BACKEND.to_string(), Value::String(self.dialog_backend.to_string()));
|
config_map.insert(DIALOG_BACKEND.to_string(), Value::String(self.dialog_backend.to_string()));
|
||||||
if let Some(new_login_command) = &self.new_login_command {
|
config_map.insert(NEW_LOGIN_COMMAND.to_string(), self.new_login_command.clone().try_into()?);
|
||||||
config_map.insert(NEW_LOGIN_COMMAND.to_string(), Value::String(new_login_command.clone()));
|
|
||||||
}
|
|
||||||
|
|
||||||
let config_path = xdg::BaseDirectories::new()?.place_config_file(CONFIG_FILE_RELATIVE_PATH)?;
|
let config_path = xdg::BaseDirectories::new()?.place_config_file(CONFIG_FILE_RELATIVE_PATH)?;
|
||||||
let mut tmp_filename = config_path.file_name().unwrap().to_os_string();
|
let mut tmp_filename = config_path.file_name().unwrap().to_os_string();
|
||||||
@ -122,7 +122,7 @@ impl Default for Configuration {
|
|||||||
lock_timeout: Duration::from_secs(60 * 10),
|
lock_timeout: Duration::from_secs(60 * 10),
|
||||||
blank_before_locking: Duration::ZERO,
|
blank_before_locking: Duration::ZERO,
|
||||||
dialog_backend: DialogBackend::Gtk3,
|
dialog_backend: DialogBackend::Gtk3,
|
||||||
new_login_command: None,
|
new_login_command: NewLoginCommand::Auto,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user