diff --git a/src/widgets/image_view.rs b/src/widgets/image_view.rs index 05389f1..b5c22c1 100644 --- a/src/widgets/image_view.rs +++ b/src/widgets/image_view.rs @@ -128,6 +128,26 @@ mod imp { PROPERTIES.as_ref() } + fn signals() -> &'static [glib::subclass::Signal] { + static SIGNALS: Lazy> = Lazy::new(|| { + vec![subclass::Signal::builder( + // Called when the dimensions of the image + // have been found. + "dimensions-loaded", + &[ + // The width of the image + i32::static_type().into(), + // The height of the image + i32::static_type().into(), + ], + glib::Type::UNIT.into(), + ) + .build()] + }); + + SIGNALS.as_ref() + } + fn get_property( &self, _obj: &Self::Type, @@ -204,6 +224,21 @@ impl IvImageView { let imp = imp::IvImageView::from_instance(&self); imp.picture.set_file(Some(file)); + + if let Err(e) = self.load_dimensions_from_file(file) { + log::error!("Could not load image dimensions: {}", e); + }; + } + + fn load_dimensions_from_file(&self, file: &gio::File) -> anyhow::Result<()> { + let pb = file.get_path().context("No path for current file")?; + let (_, width, height) = + gdk_pixbuf::Pixbuf::get_file_info(&pb.as_path()).context("Could not get file info")?; + + log::debug!("Image dimensions: {} x {}", width, height); + let _ = self.emit_by_name("dimensions-loaded", &[&width, &height]); + + Ok(()) } pub fn set_wallpaper(&self) -> anyhow::Result<()> { @@ -220,7 +255,7 @@ impl IvImageView { let request = RequestProxy::new(&imp.connection, &request_handle)?; request.on_response(|response: Response| { - log::debug!("Response is OK: {}", response.is_ok()); + log::debug!("Wallpaper set: {}", response.is_ok()); })?; Ok(()) @@ -281,4 +316,20 @@ impl IvImageView { imp.popover.set_pointing_to(&rect); imp.popover.popup(); } + + pub fn connect_dimensions_loaded( + &self, + f: F, + ) -> glib::SignalHandlerId { + self.connect_local("dimensions-loaded", true, move |values| { + let view = values[0].get::().unwrap().unwrap(); + let width = values[1].get::().unwrap().unwrap(); + let height = values[2].get::().unwrap().unwrap(); + + f(&view, width, height); + + None + }) + .unwrap() + } } diff --git a/src/window.rs b/src/window.rs index 4c8f810..36eaee6 100644 --- a/src/window.rs +++ b/src/window.rs @@ -115,6 +115,12 @@ mod imp { .connect_released(clone!(@weak obj => move |_, _, _, _| { obj.pick_file(); })); + + self.image_view.connect_dimensions_loaded( + clone!(@weak obj => move |_, width, height| { + obj.resize_from_dimensions(width, height); + }), + ); } } @@ -243,11 +249,11 @@ impl IvWindow { pub fn set_image_from_file(&self, file: &gio::File) { let imp = imp::IvWindow::from_instance(self); + log::debug!("Loading file: {}", file.get_uri().to_string()); + imp.image_view.set_image_from_file(file); imp.stack.set_visible_child(&*imp.image_view); - log::debug!("Loading file: {}", file.get_uri().to_string()); - if let Some(name) = file.get_basename() { self.set_title(Some( name.file_name().expect("Missing name").to_str().unwrap(), @@ -281,4 +287,40 @@ impl IvWindow { .unwrap() .set_enabled(enabled); } + + // Adapted from https://gitlab.gnome.org/GNOME/eog/-/blob/master/src/eog-window.c:eog_window_obtain_desired_size + pub fn resize_from_dimensions(&self, img_width: i32, img_height: i32) { + let imp = imp::IvWindow::from_instance(self); + let mut final_width = img_width; + let mut final_height = img_height; + + let header_height = imp.headerbar.get_height(); + + // Ensure the window surface exists + if !self.get_realized() { + self.realize(); + } + + let display = gdk::Display::get_default().unwrap(); + let monitor = display + .get_monitor_at_surface(&self.get_native().unwrap().get_surface().unwrap()) + .unwrap(); + let monitor_geometry = monitor.get_geometry(); + + let monitor_width = monitor_geometry.width; + let monitor_height = monitor_geometry.height; + + if img_width > monitor_width || img_height + header_height > monitor_height { + let width_factor = (monitor_width as f32 * 0.85) / img_width as f32; + let height_factor = + (monitor_height as f32 * 0.85 - header_height as f32) / img_height as f32; + let factor = width_factor.min(height_factor); + + final_width = (final_width as f32 * factor).round() as i32; + final_height = (final_height as f32 * factor).round() as i32; + } + + self.set_default_size(final_width, final_height); + log::debug!("Window resized to {} x {}", final_width, final_height); + } }