Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 29 additions & 9 deletions src/state.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (C) 2026, Nathan Gill

use std::sync::{
Arc,
atomic::{AtomicBool, Ordering},
use std::{
fs::File,
io::Seek,
sync::{
Arc,
atomic::{AtomicBool, Ordering},
},
};

use anyhow::{Result, anyhow, bail};
Expand All @@ -27,7 +31,6 @@ use wayland_protocols::ext::session_lock::v1::client::{
};
use zeroize::Zeroizing;

use crate::auth::{AtomicAuthState, AuthState};
use crate::cairo_ext::{ImageSurfaceExt, SubpixelOrderExt};
use crate::config::NLockConfig;
use crate::util::BackgroundType;
Expand All @@ -36,6 +39,10 @@ use crate::{
seat::{NLockSeat, NLockXkb},
surface::NLockSurface,
};
use crate::{
auth::{AtomicAuthState, AuthState},
util::detect_png,
};

pub struct NLockState {
pub config: NLockConfig,
Expand Down Expand Up @@ -191,11 +198,24 @@ impl NLockState {
return Ok(());
}

let pixbuf = Pixbuf::from_file(self.config.image.path.clone())?;
let pixbuf = pixbuf
.apply_embedded_orientation()
.ok_or(anyhow!("Failed to apply embedded image orientation"))?;
self.background_image = Some(ImageSurface::create_from_pixbuf(&pixbuf)?);
let mut image_file = File::open(&self.config.image.path)?;
let is_png = detect_png(&mut image_file)?;
image_file.rewind()?;

// if it's a PNG, Cairo can handle it directly, pixbuf conversion is expensive
if is_png {
let image_surface = ImageSurface::create_from_png(&mut image_file)?;
self.background_image = Some(image_surface);
} else {
let pixbuf = Pixbuf::from_read(image_file)?;
let pixbuf = pixbuf
.apply_embedded_orientation()
.ok_or(anyhow!("Failed to apply embedded image orientation"))?;

let image_surface = ImageSurface::create_from_pixbuf(&pixbuf)?;
self.background_image = Some(image_surface);
}

self.config.general.bg_type = BackgroundType::Image;

Ok(())
Expand Down
24 changes: 23 additions & 1 deletion src/util.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (C) 2026, Nathan Gill

use std::{os::fd::OwnedFd, str::FromStr};
use std::{
io::{self, Read},
os::fd::OwnedFd,
str::FromStr,
};

use clap::ValueEnum;
use nix::{
Expand Down Expand Up @@ -168,3 +172,21 @@ pub fn is_eintr(err: &std::io::Error) -> bool {
None => false,
}
}

const PNG_SIG: [u8; 8] = [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A];

// Detect if a source stream starts with a PNG signature.
// Intended use case is for detecting whether a file is PNG or not.
pub fn detect_png<R>(r: &mut R) -> io::Result<bool>
where
R: Read,
{
let mut buf = [0; 8];
let n = r.read(&mut buf)?;

if n < 8 || !buf.eq(&PNG_SIG) {
return Ok(false);
}

Ok(true)
}