Skip to content

Commit

Permalink
feat: don't allow to run multiple instances of the app
Browse files Browse the repository at this point in the history
  • Loading branch information
coffebar committed Mar 25, 2023
1 parent 92b510c commit e6d054f
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 6 deletions.
39 changes: 34 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "hyprland-per-window-layout"
description = "Per window keyboard layout (language) for Hyprland wayland compositor"
version = "0.2.0"
version = "0.2.1"
edition = "2021"
exclude = ["target", "Cargo.lock"]
readme = "README.md"
Expand All @@ -17,3 +17,4 @@ env_logger = "0.10.0"
lazy_static = "1.4.0"
log = "0.4.17"
serde_json = "1.0.93"
nix = "0.23.0"
8 changes: 8 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ use std::os::unix::net::UnixStream;
mod hyprland_event; // work with message from socket
use hyprland_event::{event, fullfill_layouts_list, hyprctl};

mod single; // a struct representing one running instance
use single::SingleInstance;

use env_logger; // debug output with env RUST_LOG='debug'
use log;

Expand Down Expand Up @@ -87,6 +90,11 @@ fn get_default_layout_name() {
fn main() {
// to see logs in output: add env RUST_LOG='debug'
env_logger::init();
let instance_sock = SingleInstance::new("hyprland-per-window-layout").unwrap();
if !instance_sock.is_single() {
println!("Another instance is running.");
std::process::exit(1);
}
// this program make sense if you have 2+ layouts
let layouts_found = get_kb_layouts_count();

Expand Down
50 changes: 50 additions & 0 deletions src/single.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
extern crate nix;

pub use self::inner::*;

mod inner {
use nix::sys::socket::{self, UnixAddr};
use nix::unistd;
use nix::Result;
use std::os::unix::prelude::RawFd;

/// A struct representing one running instance.
pub struct SingleInstance {
maybe_sock: Option<RawFd>,
}

impl SingleInstance {
/// Returns a new SingleInstance object.
pub fn new(name: &str) -> Result<Self> {
let addr = UnixAddr::new_abstract(name.as_bytes())?;
let sock = socket::socket(
socket::AddressFamily::Unix,
socket::SockType::Stream,
socket::SockFlag::empty(),
None,
)?;

let maybe_sock = match socket::bind(sock, &socket::SockAddr::Unix(addr)) {
Ok(()) => Some(sock),
Err(nix::errno::Errno::EADDRINUSE) => None,
Err(e) => return Err(e.into()),
};

Ok(Self { maybe_sock })
}

/// Returns whether this instance is single.
pub fn is_single(&self) -> bool {
self.maybe_sock.is_some()
}
}

impl Drop for SingleInstance {
fn drop(&mut self) {
if let Some(sock) = self.maybe_sock {
// Intentionally discard any close errors.
let _ = unistd::close(sock);
}
}
}
}

0 comments on commit e6d054f

Please sign in to comment.