forked from michael/leanshot
Don't allow 2 processes of leanshot to run at the same time, using a
lockfile.
This commit is contained in:
parent
b75eeae98c
commit
b245c362c4
5 changed files with 87 additions and 4 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -172,7 +172,7 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
|||
|
||||
[[package]]
|
||||
name = "leanshot"
|
||||
version = "0.4.1"
|
||||
version = "0.5.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"image",
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
[package]
|
||||
name = "leanshot"
|
||||
description = "Screenshot capture for Linux."
|
||||
version = "0.4.1"
|
||||
version = "0.5.0"
|
||||
repository = "https://git.mzhang.io/michael/leanshot"
|
||||
license-file = "LICENSE"
|
||||
edition = "2018"
|
||||
|
|
|
@ -223,7 +223,12 @@ impl Gui {
|
|||
match evt.response_type() {
|
||||
xcb::KEY_RELEASE => {
|
||||
let evt = unsafe { xcb::cast_event::<xcb::KeyReleaseEvent>(&evt) };
|
||||
trace!("key released: root={} key={} state={}", evt.root(), evt.detail(), evt.state());
|
||||
trace!(
|
||||
"key released: root={} key={} state={}",
|
||||
evt.root(),
|
||||
evt.detail(),
|
||||
evt.state()
|
||||
);
|
||||
|
||||
if evt.detail() == 9 {
|
||||
if state.dragging {
|
||||
|
@ -255,7 +260,7 @@ impl Gui {
|
|||
|
||||
// left mouse button
|
||||
if state.dragging && evt.detail() == 1 {
|
||||
state.dragging = false;
|
||||
state.dragging = false;
|
||||
if let Some(_) = state.rect() {
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ extern crate log;
|
|||
extern crate anyhow;
|
||||
|
||||
mod gui;
|
||||
mod singleton;
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::process;
|
||||
|
@ -31,6 +32,10 @@ fn main() -> Result<()> {
|
|||
capture.save_to(&opt.outfile)?;
|
||||
}
|
||||
Region::Selection => {
|
||||
info!("Creating lockfile...");
|
||||
let _lockfile = singleton::check_singleton()?;
|
||||
info!("Lockfile: {:?}", _lockfile);
|
||||
|
||||
if let Some(rectangle) = gui.interactive_select(&capture)? {
|
||||
capture.save_cropped_to(&opt.outfile, Some(rectangle))?;
|
||||
} else {
|
||||
|
|
73
src/singleton.rs
Normal file
73
src/singleton.rs
Normal file
|
@ -0,0 +1,73 @@
|
|||
use std::fs::{File, self};
|
||||
use std::io::{Write, Read};
|
||||
use std::path::PathBuf;
|
||||
use std::time::{SystemTime, Duration, UNIX_EPOCH};
|
||||
use std::process;
|
||||
|
||||
use anyhow::{Error, Context, Result};
|
||||
|
||||
const PATHS: &[&str] = &["/var/run", "/tmp"];
|
||||
|
||||
pub fn check_singleton() -> Result<Lockfile> {
|
||||
let (mut file, path) = get_lock_file()?;
|
||||
|
||||
let current_time = SystemTime::now().duration_since(UNIX_EPOCH)?.as_millis();
|
||||
let pid = process::id();
|
||||
let contents = format!("{}:{}", current_time, pid).as_bytes().to_vec();
|
||||
file.write_all(&contents)?;
|
||||
|
||||
Ok(Lockfile(path))
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Lockfile(PathBuf);
|
||||
|
||||
impl Drop for Lockfile {
|
||||
fn drop(&mut self) {
|
||||
info!("Dropping lockfile...");
|
||||
fs::remove_file(&self.0).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn get_lock_file() -> Result<(File, PathBuf)> {
|
||||
for dir_path in PATHS.iter() {
|
||||
use std::io::ErrorKind::*;
|
||||
let dir_path = PathBuf::from(dir_path);
|
||||
let lockfile_path = dir_path.join("leanshot.pid");
|
||||
|
||||
// check if it already exists
|
||||
match File::open(&lockfile_path) {
|
||||
Ok(mut f) => {
|
||||
let mut contents = String::new();
|
||||
f.read_to_string(&mut contents)?;
|
||||
|
||||
let mut parts = contents.split(":");
|
||||
let timestamp = parts.next().unwrap().parse::<u64>()?;
|
||||
let pid = parts.next().unwrap();
|
||||
let time = UNIX_EPOCH + Duration::from_millis(timestamp);
|
||||
|
||||
// if it hasn't been 5 minutes since the last open, then bail
|
||||
if SystemTime::now() - Duration::from_secs(60 * 5) < time {
|
||||
bail!("existing lockfile found for pid {} at time {:?}", pid, time);
|
||||
}
|
||||
}
|
||||
// ignore errors
|
||||
Err(e) => match e.kind() {
|
||||
NotFound => {},
|
||||
_ => return Err(Error::from(e).context("could not open lockfile for reading")),
|
||||
}
|
||||
};
|
||||
|
||||
let file = match File::create(&lockfile_path) {
|
||||
Ok(f) => f,
|
||||
Err(e) => match e.kind() {
|
||||
PermissionDenied => continue,
|
||||
_ => return Err(Error::from(e).context("could not open lockfile for writing")),
|
||||
},
|
||||
};
|
||||
|
||||
return Ok((file, lockfile_path));
|
||||
}
|
||||
|
||||
bail!("could not find a suitable place to place lockfile");
|
||||
}
|
Loading…
Reference in a new issue