diff --git a/src/main.rs b/src/main.rs index bea9d88..bc049de 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,5 @@ // Copyright (c) 2020-2022 Christopher Davis -// Copyright (c) 2022-2023 Sophie Herold +// Copyright (c) 2023 Sophie Herold // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/src/metadata/file.rs b/src/metadata/file.rs index 78d2b40..f2856f9 100644 --- a/src/metadata/file.rs +++ b/src/metadata/file.rs @@ -1,3 +1,20 @@ +// Copyright (c) 2023 Sophie Herold +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// SPDX-License-Identifier: GPL-3.0-or-later + use crate::deps::*; pub struct FileInfo { diff --git a/src/metadata/format.rs b/src/metadata/format.rs index a6d001f..8b5b22f 100644 --- a/src/metadata/format.rs +++ b/src/metadata/format.rs @@ -1,3 +1,20 @@ +// Copyright (c) 2023 Sophie Herold +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// SPDX-License-Identifier: GPL-3.0-or-later + #[derive(Clone, Debug)] pub struct ImageFormat { mime_type: glycin::MimeType, diff --git a/src/widgets/image.rs b/src/widgets/image.rs index 95171bf..0e8f9d8 100644 --- a/src/widgets/image.rs +++ b/src/widgets/image.rs @@ -113,7 +113,7 @@ mod imp { #[derive(Debug, Default, Properties)] #[properties(wrapper_type = super::LpImage)] pub struct LpImage { - #[property(get, set = LpImage::set_file, explicit_notify)] + #[property(get, explicit_notify)] pub(super) file: RefCell>, #[property(get)] pub(super) is_deleted: Cell, @@ -520,28 +520,6 @@ mod imp { zoom_gesture.group_with(&rotation_gesture); } - fn set_file(&self, file: &gio::File) { - let obj = self.obj(); - - if obj.file().map_or(false, |x| file.equal(&x)) { - return; - } - - self.file.replace(Some(file.clone())); - - let monitor = - file.monitor_file(gio::FileMonitorFlags::WATCH_MOVES, gio::Cancellable::NONE); - if let Ok(m) = &monitor { - m.connect_changed(glib::clone!(@weak obj => move |_, file_a, file_b, event| { - obj.file_changed(event, file_a, file_b); - })); - } - - self.file_monitor.replace(monitor.ok()); - - obj.notify_file(); - } - fn set_mirrored(&self, mirrored: bool) { let obj = self.obj(); @@ -813,20 +791,17 @@ glib::wrapper! { } impl LpImage { + pub fn init(&self, file: &gio::File) { + self.imp().file.replace(Some(file.clone())); + } + pub async fn load(&self, file: &gio::File) { let imp = self.imp(); log::debug!("Loading file {}", file.uri()); - self.set_file(file); imp.metadata.replace(Metadata::default()); self.emmit_metadata_changed(); - - let file_info = metadata::FileInfo::new(file).await; - match file_info { - Ok(file_info) => imp.metadata.borrow_mut().set_file_info(file_info), - Err(err) => log::warn!("Failed to load file information: {err}"), - } - self.emmit_metadata_changed(); + self.set_file_loaded(file).await; let tiles = &self.imp().frame_buffer; // Delete all stored textures for reloads @@ -850,6 +825,68 @@ impl LpImage { imp.decoder.replace(Some(Arc::new(decoder))); } + // Set filename when (re)loading image + async fn set_file_loaded(&self, file: &gio::File) { + let imp = self.imp(); + + // Do not check if same file since it might be set via initialized with `Self::init` before + imp.file.replace(Some(file.clone())); + self.reload_file_info().await; + self.setup_file_monitor().await; + + self.notify_file(); + } + + /// Set filename after filename changed + async fn set_file_changed(&self, file: &gio::File) { + let imp = self.imp(); + let prev_mime_type = self.metadata().mime_type(); + + imp.file.replace(Some(file.clone())); + self.reload_file_info().await; + + // Reload if mime type changed since other decoding path might be responsible now + if self.metadata().mime_type() != prev_mime_type { + self.load(file).await; + return; + } + + self.setup_file_monitor().await; + + self.notify_file(); + } + + async fn reload_file_info(&self) { + let imp = self.imp(); + + if let Some(file) = self.file() { + let file_info = metadata::FileInfo::new(&file).await; + match file_info { + Ok(file_info) => imp.metadata.borrow_mut().set_file_info(file_info), + Err(err) => log::warn!("Failed to load file information: {err}"), + } + self.emmit_metadata_changed(); + } + } + + async fn setup_file_monitor(&self) { + let imp = self.imp(); + + if let Some(file) = self.file() { + let monitor = + file.monitor_file(gio::FileMonitorFlags::WATCH_MOVES, gio::Cancellable::NONE); + if let Ok(m) = &monitor { + m.connect_changed( + glib::clone!(@weak self as obj => move |_, file_a, file_b, event| { + obj.file_changed(event, file_a, file_b); + }), + ); + } + + imp.file_monitor.replace(monitor.ok()); + } + } + /// Called when decoder sends update pub fn update(&self, update: DecoderUpdate) { let imp = self.imp(); @@ -991,14 +1028,17 @@ impl LpImage { log::debug!("Moved to {}", file.uri()); // current file got replaced with a new one let file_replace = self.file().map_or(false, |x| x.equal(&file)); - self.set_file(&file); + let obj = self.clone(); if file_replace { log::debug!("Image got replaced {}", file.uri()); - let obj = self.clone(); // TODO: error handling is missing glib::spawn_future_local(async move { obj.load(&file).await; }); + } else { + glib::spawn_future_local(async move { + obj.set_file_changed(&file).await; + }); } } } diff --git a/src/widgets/image_page.rs b/src/widgets/image_page.rs index a1079ef..b4eafad 100644 --- a/src/widgets/image_page.rs +++ b/src/widgets/image_page.rs @@ -153,7 +153,7 @@ impl LpImagePage { pub fn from_file(file: &gio::File) -> Self { let obj = glib::Object::new::(); - obj.imp().image.set_file(file); + obj.imp().image.init(file); glib::spawn_future_local(clone!(@weak obj, @strong file => async move { let imp = obj.imp();