~whynothugo/shotman

3a39ea9ea7da1acbfff494bb5a327527f98c7f42 — Hugo Osvaldo Barrera 3 months ago 49d0747
Move paths-related logic into separate module
2 files changed, 50 insertions(+), 45 deletions(-)

M src/main.rs
A src/paths.rs
M src/main.rs => src/main.rs +6 -45
@@ 1,8 1,8 @@
use std::cell::OnceCell;
use std::cmp::min;
use std::ffi::OsString;
use std::fs::{create_dir, remove_file, File, OpenOptions};
use std::io::{ErrorKind, Write};
use std::fs::{remove_file, File, OpenOptions};
use std::io::Write;
use std::os::unix::io::OwnedFd;
use std::path::PathBuf;
use std::process::Command;


@@ 18,6 18,7 @@ use clap::Parser;
use cli::{Cli, RequestedTarget};
use futures::channel::oneshot::{self, Canceled};
use log::{debug, error, info, trace, warn};
use paths::screenshot_filepath;
use rustix::fs::{fcntl_getfl, fcntl_setfl, OFlags};
use smithay_client_toolkit::output::{OutputHandler, OutputInfo, OutputState};
use smithay_client_toolkit::reexports::calloop::EventLoop;


@@ 26,8 27,6 @@ use smithay_client_toolkit::seat::keyboard::{KeyboardData, KeyboardHandler, Keys
use smithay_client_toolkit::{
    delegate_keyboard, delegate_output, delegate_registry, registry_handlers,
};
use time::format_description::FormatItem;
use time::OffsetDateTime;
use wayland_client::delegate_noop;
use wayland_client::event_created_child;
use wayland_client::globals::{registry_queue_init, GlobalList};


@@ 55,6 54,7 @@ use wayland_protocols_wlr::screencopy::v1::client::{
    zwlr_screencopy_manager_v1::ZwlrScreencopyManagerV1,
};

use crate::paths::screenshots_directory;
use crate::slurp::pick_a_region;
use crate::sway::get_active_window_geom;
use crate::sway::get_focused_output_rect;


@@ 62,52 62,14 @@ use crate::sway::get_focused_output_rect;
mod buffers;
mod cli;
mod encoder;
mod paths;
mod slurp;
mod sway;

const BORDER_WIDTH: u8 = 2;
const FILENAME_FMT: &[FormatItem] = time::macros::format_description!(
    "Screenshot.from.[year]-[month]-[day].at.[hour]_[minute]_[second].[subsecond digits:9].png"
);
// RGB with pre-multiplied alpha.
const BORDER_COLOUR: (u32, u32, u32) = (122 << 24, 162 << 24, 247 << 24);

/// Returns the directory in which screenshots are to be saved.
/// Follows a best-effort fallback pattern.
fn screenshots_directory() -> anyhow::Result<PathBuf> {
    let path = if let Some(s) = std::env::var_os("XDG_SCREENSHOTS_DIR") {
        s.into()
    } else if let Some(s) = std::env::var_os("XDG_PICTURES_DIR") {
        PathBuf::from(s).join("screenshots")
    } else if let Some(home) = std::env::var_os("HOME") {
        let home = PathBuf::from(home);
        let pictures_fallback = home.join("Pictures");
        if pictures_fallback.exists() {
            pictures_fallback
        } else {
            home.join("screenshots")
        }
    } else if let Ok(cwd) = std::env::current_dir() {
        cwd
    } else {
        anyhow::bail!("$HOME isn't defined; no fallback for screenshot location");
    };

    match create_dir(&path) {
        Ok(()) => Ok(path),
        Err(err) if err.kind() == ErrorKind::AlreadyExists => Ok(path),
        Err(err) => Err(err.into()),
    }
}

fn screenshot_filepath() -> anyhow::Result<PathBuf> {
    let filename = OffsetDateTime::now_local()
        .context("Error obtaning local time")?
        .format(FILENAME_FMT)
        .context("Error formatting current time")?;
    Ok(screenshots_directory()?.join(filename))
}

/// The target we want to screenshot.
///
/// For the moment, windows are converted to the region they occupy. This will change in future


@@ 134,8 96,7 @@ fn main() -> anyhow::Result<()> {
    simple_logger::init_with_level(log_level).expect("logger configuration is valid");

    if cli.print_dir {
        let dir = screenshots_directory()
            .expect("screenshot directory requires $HOME or a relevant $XDG_ variable");
        let dir = screenshots_directory()?;
        println!("{}", dir.to_string_lossy());
        return Ok(());
    }

A src/paths.rs => src/paths.rs +44 -0
@@ 0,0 1,44 @@
use std::{fs::create_dir, io::ErrorKind, path::PathBuf};

use anyhow::Context;
use time::{format_description::FormatItem, OffsetDateTime};

const FILENAME_FMT: &[FormatItem] = time::macros::format_description!(
    "Screenshot.from.[year]-[month]-[day].at.[hour]_[minute]_[second].[subsecond digits:9].png"
);

/// Returns the directory in which screenshots are to be saved.
/// Follows a best-effort fallback pattern.
pub(crate) fn screenshots_directory() -> anyhow::Result<PathBuf> {
    let path = if let Some(s) = std::env::var_os("XDG_SCREENSHOTS_DIR") {
        s.into()
    } else if let Some(s) = std::env::var_os("XDG_PICTURES_DIR") {
        PathBuf::from(s).join("screenshots")
    } else if let Some(home) = std::env::var_os("HOME") {
        let home = PathBuf::from(home);
        let pictures_fallback = home.join("Pictures");
        if pictures_fallback.exists() {
            pictures_fallback
        } else {
            home.join("screenshots")
        }
    } else if let Ok(cwd) = std::env::current_dir() {
        cwd
    } else {
        anyhow::bail!("$HOME isn't defined; no fallback for screenshot location");
    };

    match create_dir(&path) {
        Ok(()) => Ok(path),
        Err(err) if err.kind() == ErrorKind::AlreadyExists => Ok(path),
        Err(err) => Err(err.into()),
    }
}

pub(crate) fn screenshot_filepath() -> anyhow::Result<PathBuf> {
    let filename = OffsetDateTime::now_local()
        .context("Error obtaning local time")?
        .format(FILENAME_FMT)
        .context("Error formatting current time")?;
    Ok(screenshots_directory()?.join(filename))
}