breadpad: capture the reminder window + its snooze popover
Two more views: "reminder" (the alert window from run_reminder_window, normally only reachable via a real due note through `fire <id>`) and "reminder-snooze" (same window, snooze popover open). Screenshot mode builds a throwaway sample Note directly instead of going through cmd_fire's Store lookup — main() checks for these two view names before ever reaching run_popup's dispatch, since the reminder window is a completely separate GApplication entry point, not reachable through the compose-popup path screenshot mode already covered. Same NON_UNIQUE-on-screenshot-mode fix as run_popup already had, applied to the reminder window's own Application builder.
This commit is contained in:
parent
77b402833f
commit
47a4613b5a
2 changed files with 94 additions and 11 deletions
|
|
@ -170,6 +170,21 @@ fn main() -> Result<()> {
|
|||
}
|
||||
|
||||
let screenshot_req = args.screenshot_request();
|
||||
if let Some(req) = &screenshot_req {
|
||||
if req.view == "reminder" || req.view == "reminder-snooze" {
|
||||
// The real path (`fire <id>`, above) needs a real due note from
|
||||
// the Store. A screenshot doesn't have one to work with — and
|
||||
// shouldn't wait for one — so it builds a throwaway sample
|
||||
// instead, never touching the Store at all.
|
||||
let mut sample = Note::new(
|
||||
"Sample reminder text".into(),
|
||||
NoteType::from_str("reminder"),
|
||||
None,
|
||||
);
|
||||
sample.time = Some(chrono::Utc::now());
|
||||
return run_reminder_window(sample, &cfg, screenshot_req);
|
||||
}
|
||||
}
|
||||
run_popup(args.note_type, args.no_classify, cfg, screenshot_req)
|
||||
}
|
||||
|
||||
|
|
@ -326,19 +341,28 @@ fn cmd_fire(id: &str, cfg: &Config) -> Result<()> {
|
|||
}
|
||||
}
|
||||
|
||||
run_reminder_window(note, cfg)
|
||||
run_reminder_window(note, cfg, None)
|
||||
}
|
||||
|
||||
fn run_reminder_window(note: breadpad_shared::types::Note, cfg: &Config) -> Result<()> {
|
||||
let app = gtk4::Application::builder()
|
||||
.application_id("com.breadway.breadpad.reminder")
|
||||
.build();
|
||||
fn run_reminder_window(
|
||||
note: breadpad_shared::types::Note,
|
||||
cfg: &Config,
|
||||
screenshot_req: Option<screenshot::ScreenshotRequest>,
|
||||
) -> Result<()> {
|
||||
let mut builder = gtk4::Application::builder().application_id("com.breadway.breadpad.reminder");
|
||||
if screenshot_req.is_some() {
|
||||
// Same reasoning as run_popup's NON_UNIQUE: a screenshot run must
|
||||
// get its own fresh window, never activate a real reminder that
|
||||
// happens to already be showing.
|
||||
builder = builder.flags(gtk4::gio::ApplicationFlags::NON_UNIQUE);
|
||||
}
|
||||
let app = builder.build();
|
||||
|
||||
let note = Arc::new(note);
|
||||
let cfg = Arc::new(cfg.clone());
|
||||
|
||||
app.connect_activate(move |app| {
|
||||
build_reminder_window(app, note.clone(), cfg.clone());
|
||||
build_reminder_window(app, note.clone(), cfg.clone(), screenshot_req.clone());
|
||||
});
|
||||
|
||||
app.run_with_args::<String>(&[]);
|
||||
|
|
@ -381,6 +405,7 @@ fn build_reminder_window(
|
|||
app: >k4::Application,
|
||||
note: Arc<breadpad_shared::types::Note>,
|
||||
cfg: Arc<Config>,
|
||||
screenshot_req: Option<screenshot::ScreenshotRequest>,
|
||||
) {
|
||||
let window = gtk4::ApplicationWindow::builder()
|
||||
.application(app)
|
||||
|
|
@ -557,6 +582,15 @@ fn build_reminder_window(
|
|||
outer.append(&btn_row);
|
||||
|
||||
window.set_child(Some(&outer));
|
||||
|
||||
if let Some(req) = screenshot_req {
|
||||
if req.view == "reminder-snooze" {
|
||||
screenshot::capture_with_snooze_open(&window, &req, snooze_popover.clone());
|
||||
} else {
|
||||
screenshot::capture_window(&window, &req);
|
||||
}
|
||||
}
|
||||
|
||||
window.present();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,10 +10,13 @@
|
|||
//! `--width`/`--height` are just three more fields on that same `Args`
|
||||
//! struct instead.
|
||||
//!
|
||||
//! Only the "popup" view (the compose window from `run_popup`) is wired up
|
||||
//! — the reminder window (`run_reminder_window`, reached via `fire <id>`)
|
||||
//! needs a real stored `Note` to render, which isn't worth fabricating for
|
||||
//! a screenshot pass.
|
||||
//! Three views: "popup" (the compose window from `run_popup`), "reminder"
|
||||
//! (the alert window from `run_reminder_window`/`build_reminder_window`,
|
||||
//! normally only reachable via a real due note through `fire <id>`, built
|
||||
//! here against a fabricated sample `Note` instead — see `main`'s
|
||||
//! `screenshot_req.view == "reminder"` branch, which skips the Store lookup
|
||||
//! entirely), and "reminder-snooze" (the same window with its snooze
|
||||
//! popover open).
|
||||
|
||||
use gtk4::prelude::*;
|
||||
use std::path::PathBuf;
|
||||
|
|
@ -24,6 +27,11 @@ use std::time::Duration;
|
|||
/// anything has been drawn into it.
|
||||
const SETTLE_DELAY: Duration = Duration::from_millis(300);
|
||||
|
||||
/// Delay before popping the snooze popover open — same reasoning as every
|
||||
/// other app's PRE_POPUP_DELAY: the parent window's own layout needs a beat
|
||||
/// to settle first.
|
||||
const PRE_POPUP_DELAY: Duration = Duration::from_millis(300);
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ScreenshotRequest {
|
||||
pub view: String,
|
||||
|
|
@ -48,12 +56,53 @@ pub fn dispatch(window: >k4::ApplicationWindow, req: ScreenshotRequest) {
|
|||
});
|
||||
}
|
||||
other => {
|
||||
eprintln!("breadpad: unknown screenshot view '{other}' (known: popup)");
|
||||
eprintln!("breadpad: unknown screenshot view '{other}' (known: popup, reminder, reminder-snooze)");
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Same shape as `dispatch`'s "popup" arm, for the reminder window itself
|
||||
/// (view "reminder") — pulled out since `build_reminder_window` calls this
|
||||
/// directly rather than going through `dispatch` (the reminder window is
|
||||
/// built via a completely separate `run_reminder_window` entry point, not
|
||||
/// `run_popup`'s).
|
||||
pub fn capture_window(window: >k4::ApplicationWindow, req: &ScreenshotRequest) {
|
||||
let output = req.output.clone();
|
||||
let (width, height) = (req.width as i32, req.height as i32);
|
||||
window.connect_map(move |_| {
|
||||
let output = output.clone();
|
||||
gtk4::glib::timeout_add_local_once(SETTLE_DELAY, move || {
|
||||
finish(bread_screenshots::capture_region(0, 0, width, height, &output));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/// View "reminder-snooze": force the snooze popover open shortly after the
|
||||
/// window maps, then capture once *it* maps.
|
||||
pub fn capture_with_snooze_open(
|
||||
window: >k4::ApplicationWindow,
|
||||
req: &ScreenshotRequest,
|
||||
snooze_popover: gtk4::Popover,
|
||||
) {
|
||||
let output = req.output.clone();
|
||||
let (width, height) = (req.width as i32, req.height as i32);
|
||||
let popover_to_open = snooze_popover.clone();
|
||||
window.connect_map(move |_| {
|
||||
popover_to_open.set_autohide(false);
|
||||
let popover_to_open = popover_to_open.clone();
|
||||
gtk4::glib::timeout_add_local_once(PRE_POPUP_DELAY, move || {
|
||||
popover_to_open.popup();
|
||||
});
|
||||
});
|
||||
snooze_popover.connect_map(move |_| {
|
||||
let output = output.clone();
|
||||
gtk4::glib::timeout_add_local_once(SETTLE_DELAY, move || {
|
||||
finish(bread_screenshots::capture_region(0, 0, width, height, &output));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fn finish(result: anyhow::Result<()>) {
|
||||
match result {
|
||||
Ok(()) => std::process::exit(0),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue