input: Add screenshotting shortcut
This commit is contained in:
parent
979e282768
commit
63b252e47d
8 changed files with 193 additions and 14 deletions
|
|
@ -63,7 +63,7 @@ use socket::*;
|
|||
|
||||
pub struct KmsState {
|
||||
devices: HashMap<DrmNode, Device>,
|
||||
api: GpuManager<EglGlesBackend>,
|
||||
pub api: GpuManager<EglGlesBackend>,
|
||||
pub primary: DrmNode,
|
||||
session: AutoSession,
|
||||
signaler: Signaler<Signal>,
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ pub fn render_output<R>(
|
|||
state: &mut Common,
|
||||
output: &Output,
|
||||
hardware_cursor: bool,
|
||||
#[cfg(feature = "debug")] fps: &mut Fps,
|
||||
#[cfg(feature = "debug")] fps: Option<&mut Fps>,
|
||||
) -> Result<Option<Vec<Rectangle<i32, Physical>>>, RenderError<R>>
|
||||
where
|
||||
R: Renderer + ImportAll + AsGles2Renderer,
|
||||
|
|
@ -198,7 +198,7 @@ fn render_desktop<R>(
|
|||
state: &mut Common,
|
||||
output: &Output,
|
||||
hardware_cursor: bool,
|
||||
#[cfg(feature = "debug")] fps: &mut Fps,
|
||||
#[cfg(feature = "debug")] fps: Option<&mut Fps>,
|
||||
) -> Result<Option<Vec<Rectangle<i32, Physical>>>, RenderError<R>>
|
||||
where
|
||||
R: Renderer + ImportAll + AsGles2Renderer,
|
||||
|
|
@ -216,14 +216,16 @@ where
|
|||
.unwrap_or(Rectangle::from_loc_and_size((0, 0), (0, 0)));
|
||||
let scale = output.current_scale().fractional_scale();
|
||||
|
||||
let fps_overlay = fps_ui(
|
||||
_gpu,
|
||||
state,
|
||||
fps,
|
||||
output_geo.to_f64().to_physical(scale),
|
||||
scale,
|
||||
);
|
||||
custom_elements.push(fps_overlay.into());
|
||||
if let Some(fps) = fps {
|
||||
let fps_overlay = fps_ui(
|
||||
_gpu,
|
||||
state,
|
||||
fps,
|
||||
output_geo.to_f64().to_physical(scale),
|
||||
scale,
|
||||
);
|
||||
custom_elements.push(fps_overlay.into());
|
||||
}
|
||||
|
||||
let area = Rectangle::<f64, smithay::utils::Logical>::from_loc_and_size(
|
||||
state
|
||||
|
|
@ -282,7 +284,7 @@ fn render_fullscreen<R>(
|
|||
state: &mut Common,
|
||||
output: &Output,
|
||||
hardware_cursor: bool,
|
||||
#[cfg(feature = "debug")] fps: &mut Fps,
|
||||
#[cfg(feature = "debug")] fps: Option<&mut Fps>,
|
||||
) -> Result<Option<Vec<Rectangle<i32, Physical>>>, RenderError<R>>
|
||||
where
|
||||
R: Renderer + ImportAll + AsGles2Renderer,
|
||||
|
|
@ -296,7 +298,7 @@ where
|
|||
let mut custom_elements = Vec::<CustomElem>::new();
|
||||
|
||||
#[cfg(feature = "debug")]
|
||||
{
|
||||
if let Some(fps) = fps {
|
||||
let output_geo = output.geometry();
|
||||
let fps_overlay = fps_ui(
|
||||
_gpu,
|
||||
|
|
|
|||
|
|
@ -752,5 +752,6 @@ pub enum Action {
|
|||
ToggleTiling,
|
||||
ToggleWindowFloating,
|
||||
Fullscreen,
|
||||
Screenshot,
|
||||
Spawn(String),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -387,6 +387,35 @@ impl State {
|
|||
slog_scope::warn!("Failed to spawn: {}", err);
|
||||
}
|
||||
}
|
||||
Action::Screenshot => {
|
||||
let home = match std::env::var("HOME") {
|
||||
Ok(home) => home,
|
||||
Err(err) => {
|
||||
slog_scope::error!("$HOME is not set, can't save screenshots: {}", err);
|
||||
break;
|
||||
}
|
||||
};
|
||||
let timestamp = match std::time::SystemTime::UNIX_EPOCH.elapsed() {
|
||||
Ok(duration) => duration.as_secs(),
|
||||
Err(err) => {
|
||||
slog_scope::error!("Unable to get timestamp, can't save screenshots: {}", err);
|
||||
break;
|
||||
}
|
||||
};
|
||||
for output in self.common.shell.outputs.clone().into_iter() {
|
||||
match self.backend.offscreen_for_output(&output, &mut self.common) {
|
||||
Ok(buffer) => {
|
||||
let mut path = std::path::PathBuf::new();
|
||||
path.push(&home);
|
||||
path.push(format!("{}_{}.png", output.name(), timestamp));
|
||||
if let Err(err) = buffer.save(&path) {
|
||||
slog_scope::error!("Unable to save screenshot at {}: {}", path.display(), err);
|
||||
}
|
||||
},
|
||||
Err(err) => slog_scope::error!("Could not save screenshot for output {}: {}", output.name(), err),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
|
|||
57
src/state.rs
57
src/state.rs
|
|
@ -8,7 +8,7 @@ use crate::{
|
|||
wayland::protocols::{
|
||||
drm::WlDrmState, output_configuration::OutputConfigurationState,
|
||||
workspace::WorkspaceClientState,
|
||||
},
|
||||
}, utils::prelude::OutputExt,
|
||||
};
|
||||
use smithay::{
|
||||
backend::drm::DrmNode,
|
||||
|
|
@ -199,6 +199,61 @@ impl BackendData {
|
|||
_ => unreachable!("No backend was initialized"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn offscreen_for_output(
|
||||
&mut self,
|
||||
output: &Output,
|
||||
state: &mut Common,
|
||||
) -> anyhow::Result<image::ImageBuffer<image::Rgba<u8>, Vec<u8>>> {
|
||||
use anyhow::Context;
|
||||
use smithay::{
|
||||
backend::{
|
||||
drm::NodeType,
|
||||
renderer::{
|
||||
Bind, Offscreen, ExportMem,
|
||||
gles2::Gles2Renderbuffer,
|
||||
},
|
||||
},
|
||||
utils::Rectangle,
|
||||
};
|
||||
use crate::backend::render::render_output;
|
||||
|
||||
let mut _tmp_multirenderer = None;
|
||||
let (node, renderer) = match self {
|
||||
BackendData::Winit(winit) => (None, winit.backend.renderer()),
|
||||
BackendData::X11(x11) => (None, &mut x11.renderer),
|
||||
BackendData::Kms(kms) => {
|
||||
let node = kms.target_node_for_output(output)
|
||||
.unwrap_or(kms.primary)
|
||||
.node_with_type(NodeType::Render)
|
||||
.with_context(|| "Unable to find node")??;
|
||||
_tmp_multirenderer = Some(kms.api.renderer::<Gles2Renderbuffer>(&node, &node)?);
|
||||
(Some(node), _tmp_multirenderer.as_mut().map(|x| x.as_mut()).unwrap())
|
||||
},
|
||||
BackendData::Unset => unreachable!(),
|
||||
};
|
||||
|
||||
let size = output.geometry().size.to_f64().to_buffer(
|
||||
output.current_scale().fractional_scale(),
|
||||
output.current_transform().into()
|
||||
).to_i32_round();
|
||||
let buffer = Offscreen::<Gles2Renderbuffer>::create_buffer(renderer, size)?;
|
||||
renderer.bind(buffer)?;
|
||||
render_output(
|
||||
node.as_ref(),
|
||||
renderer,
|
||||
0,
|
||||
state,
|
||||
output,
|
||||
false,
|
||||
#[cfg(feature = "debug")]
|
||||
None,
|
||||
)?;
|
||||
let mapping = renderer.copy_framebuffer(Rectangle::from_loc_and_size((0, 0), size))?;
|
||||
let data = Vec::from(renderer.map_texture(&mapping)?);
|
||||
|
||||
Ok(image::ImageBuffer::from_raw(size.w as u32, size.h as u32, data).with_context(|| "buffer smaller then dimensions")?)
|
||||
}
|
||||
}
|
||||
|
||||
impl State {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue