Skip to main content

poki_launcher_notifier/
lib.rs

1/***
2 * This file is part of Poki Launcher.
3 *
4 * Poki Launcher is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * Poki Launcher is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with Poki Launcher.  If not, see <https://www.gnu.org/licenses/>.
16 */
17use failure::Error;
18use std::fs::File;
19use std::io::prelude::*;
20use std::path::Path;
21use std::sync::mpsc::{self, Receiver};
22use std::thread;
23
24const LOCK_FILE_PATH: &str = "/tmp/poki-launcher.pid";
25
26pub enum Msg {
27    Show,
28    Exit,
29}
30
31pub fn is_running() -> bool {
32    Path::new(&LOCK_FILE_PATH).exists()
33}
34
35pub struct Notifier(Receiver<Msg>);
36
37impl Notifier {
38    pub fn start() -> Result<Notifier, Error> {
39        use nix::unistd::getpid;
40        use signal_hook::iterator::Signals;
41        use signal_hook::*;
42
43        let mut file = File::create(&LOCK_FILE_PATH)?;
44        write!(file, "{}", getpid())?;
45        drop(file);
46        let signals = Signals::new(&[SIGUSR1, SIGINT, SIGTERM, SIGQUIT])?;
47        let (tx, rx) = mpsc::channel();
48        thread::spawn(move || {
49            for signal in signals.forever() {
50                match signal {
51                    SIGUSR1 => tx.send(Msg::Show).expect("Failed to send show message"),
52                    SIGINT | SIGTERM | SIGQUIT => {
53                        tx.send(Msg::Exit).expect("Failed to send show message");
54                        break;
55                    }
56                    _ => (),
57                }
58            }
59        });
60        Ok(Notifier(rx))
61    }
62
63    pub fn recv(&self) -> Result<Msg, std::sync::mpsc::RecvError> {
64        self.0.recv()
65    }
66}
67
68impl Drop for Notifier {
69    fn drop(&mut self) {
70        if is_running() {
71            std::fs::remove_file(&LOCK_FILE_PATH).expect("Failed to delete lock file");
72        }
73    }
74}
75
76pub fn notify() -> Result<(), Error> {
77    use nix::sys::signal::{kill, Signal};
78    use nix::unistd::Pid;
79
80    let mut file = File::open(&LOCK_FILE_PATH)?;
81    let mut buf = String::new();
82    file.read_to_string(&mut buf)?;
83    kill(Pid::from_raw(buf.parse()?), Signal::SIGUSR1)?;
84    Ok(())
85}