Skip to content

Commit 8130ba7

Browse files
authored
Merge pull request #60 from devmobasa/fix-capture
Fix capture (screenshot, region)
2 parents ed70511 + c77b887 commit 8130ba7

File tree

16 files changed

+250
-90
lines changed

16 files changed

+250
-90
lines changed

config.example.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,11 @@ format = "png"
332332
# Shortcut-specific actions may override this
333333
copy_to_clipboard = true
334334

335+
# Exit overlay after any capture completes (forces exit for all capture types)
336+
# When false, clipboard-only captures still auto-exit by default.
337+
# Use --no-exit-after-capture to keep the overlay open for a run.
338+
exit_after_capture = false
339+
335340
# ═══════════════════════════════════════════════════════════════════════════════
336341
# SESSION PERSISTENCE
337342
# ═══════════════════════════════════════════════════════════════════════════════

configurator/src/app.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -937,6 +937,12 @@ impl ConfiguratorApp {
937937
self.draft.capture_copy_to_clipboard,
938938
self.defaults.capture_copy_to_clipboard,
939939
ToggleField::CaptureCopyToClipboard,
940+
),
941+
toggle_row(
942+
"Always exit overlay after capture",
943+
self.draft.capture_exit_after,
944+
self.defaults.capture_exit_after,
945+
ToggleField::CaptureExitAfter,
940946
)
941947
]
942948
.spacing(12),

configurator/src/models/config.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ pub struct ConfigDraft {
6666
pub capture_filename_template: String,
6767
pub capture_format: String,
6868
pub capture_copy_to_clipboard: bool,
69+
pub capture_exit_after: bool,
6970

7071
pub session_persist_transparent: bool,
7172
pub session_persist_whiteboard: bool,
@@ -151,6 +152,7 @@ impl ConfigDraft {
151152
capture_filename_template: config.capture.filename_template.clone(),
152153
capture_format: config.capture.format.clone(),
153154
capture_copy_to_clipboard: config.capture.copy_to_clipboard,
155+
capture_exit_after: config.capture.exit_after_capture,
154156

155157
session_persist_transparent: config.session.persist_transparent,
156158
session_persist_whiteboard: config.session.persist_whiteboard,
@@ -369,6 +371,7 @@ impl ConfigDraft {
369371
config.capture.filename_template = self.capture_filename_template.clone();
370372
config.capture.format = self.capture_format.clone();
371373
config.capture.copy_to_clipboard = self.capture_copy_to_clipboard;
374+
config.capture.exit_after_capture = self.capture_exit_after;
372375

373376
config.session.persist_transparent = self.session_persist_transparent;
374377
config.session.persist_whiteboard = self.session_persist_whiteboard;
@@ -434,6 +437,7 @@ impl ConfigDraft {
434437
ToggleField::BoardAutoAdjust => self.board_auto_adjust_pen = value,
435438
ToggleField::CaptureEnabled => self.capture_enabled = value,
436439
ToggleField::CaptureCopyToClipboard => self.capture_copy_to_clipboard = value,
440+
ToggleField::CaptureExitAfter => self.capture_exit_after = value,
437441
ToggleField::SessionPersistTransparent => {
438442
self.session_persist_transparent = value;
439443
}

configurator/src/models/fields.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,7 @@ pub enum ToggleField {
229229
BoardAutoAdjust,
230230
CaptureEnabled,
231231
CaptureCopyToClipboard,
232+
CaptureExitAfter,
232233
SessionPersistTransparent,
233234
SessionPersistWhiteboard,
234235
SessionPersistBlackboard,

docs/CONFIG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,11 @@ format = "png"
333333

334334
# Copy captures to clipboard in addition to saving files
335335
copy_to_clipboard = true
336+
337+
# Exit the overlay after any capture completes (forces exit for all capture types)
338+
# When false, clipboard-only captures still auto-exit by default.
339+
# Use --no-exit-after-capture to keep the overlay open for a run.
340+
exit_after_capture = false
336341
```
337342

338343
**Tips:**

src/backend/mod.rs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,26 @@ pub mod wayland;
55
// Removed: Backend trait - no longer needed with single backend
66
// Removed: BackendChoice enum - Wayland is the only backend
77

8+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9+
pub enum ExitAfterCaptureMode {
10+
Auto,
11+
Always,
12+
Never,
13+
}
14+
815
/// Run Wayland backend with full event loop
916
///
1017
/// # Arguments
1118
/// * `initial_mode` - Optional board mode to start in (overrides config default)
1219
/// * `freeze_on_start` - Whether to start with the overlay frozen for immediate capture pause
13-
pub fn run_wayland(initial_mode: Option<String>, freeze_on_start: bool) -> Result<()> {
14-
let mut backend = wayland::WaylandBackend::new(initial_mode, freeze_on_start)?;
20+
/// * `exit_after_capture_mode` - Exit behavior after a capture completes
21+
pub fn run_wayland(
22+
initial_mode: Option<String>,
23+
freeze_on_start: bool,
24+
exit_after_capture_mode: ExitAfterCaptureMode,
25+
) -> Result<()> {
26+
let mut backend =
27+
wayland::WaylandBackend::new(initial_mode, freeze_on_start, exit_after_capture_mode)?;
1528
backend.init()?;
1629
backend.show()?; // show() calls run() internally
1730
backend.hide()?;
@@ -27,6 +40,7 @@ mod tests {
2740
eprintln!("WAYLAND_DISPLAY not set; skipping Wayland smoke test");
2841
return;
2942
}
30-
super::run_wayland(None, false).expect("Wayland backend should start");
43+
super::run_wayland(None, false, super::ExitAfterCaptureMode::Never)
44+
.expect("Wayland backend should start");
3145
}
3246
}

src/backend/wayland/backend.rs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ use wayland_protocols_wlr::screencopy::v1::client::zwlr_screencopy_manager_v1::Z
4343
use super::state::{OverlaySuppression, WaylandGlobals, WaylandState, WaylandStateInit};
4444
use crate::{
4545
RESUME_SESSION_ENV,
46+
backend::ExitAfterCaptureMode,
4647
capture::{CaptureManager, CaptureOutcome},
4748
config::{Action, Config, ConfigSource},
4849
input::{BoardMode, ClickHighlightSettings, InputState},
@@ -139,17 +140,23 @@ fn resume_override_from_env() -> Option<bool> {
139140
pub struct WaylandBackend {
140141
initial_mode: Option<String>,
141142
freeze_on_start: bool,
143+
exit_after_capture_mode: ExitAfterCaptureMode,
142144
/// Tokio runtime for async capture operations
143145
tokio_runtime: tokio::runtime::Runtime,
144146
}
145147

146148
impl WaylandBackend {
147-
pub fn new(initial_mode: Option<String>, freeze_on_start: bool) -> Result<Self> {
149+
pub fn new(
150+
initial_mode: Option<String>,
151+
freeze_on_start: bool,
152+
exit_after_capture_mode: ExitAfterCaptureMode,
153+
) -> Result<Self> {
148154
let tokio_runtime = tokio::runtime::Runtime::new()
149155
.context("Failed to create Tokio runtime for capture operations")?;
150156
Ok(Self {
151157
initial_mode,
152158
freeze_on_start,
159+
exit_after_capture_mode,
153160
tokio_runtime,
154161
})
155162
}
@@ -259,6 +266,12 @@ impl WaylandBackend {
259266
(Config::default(), ConfigSource::Default)
260267
}
261268
};
269+
let exit_after_capture_mode = match self.exit_after_capture_mode {
270+
ExitAfterCaptureMode::Auto if config.capture.exit_after_capture => {
271+
ExitAfterCaptureMode::Always
272+
}
273+
other => other,
274+
};
262275

263276
info!("Configuration loaded");
264277
debug!(" Color: {:?}", config.drawing.default_color);
@@ -514,6 +527,7 @@ impl WaylandBackend {
514527
capture_manager,
515528
session_options,
516529
tokio_handle,
530+
exit_after_capture_mode,
517531
frozen_enabled: frozen_supported,
518532
preferred_output_identity,
519533
xdg_fullscreen,
@@ -773,6 +787,8 @@ impl WaylandBackend {
773787
state.show_overlay();
774788
state.capture.clear_in_progress();
775789

790+
let exit_on_success = state.capture.take_exit_on_success()
791+
&& matches!(&outcome, CaptureOutcome::Success(_));
776792
match outcome {
777793
CaptureOutcome::Success(result) => {
778794
// Build notification message
@@ -821,6 +837,9 @@ impl WaylandBackend {
821837
log::info!("Capture cancelled: {}", reason);
822838
}
823839
}
840+
if exit_on_success {
841+
state.input_state.should_exit = true;
842+
}
824843
}
825844

826845
// Render if configured and needs redraw, but only if no frame callback pending

src/backend/wayland/capture.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use crate::capture::CaptureManager;
88
pub struct CaptureState {
99
manager: CaptureManager,
1010
in_progress: bool,
11+
exit_on_success: bool,
1112
}
1213

1314
impl CaptureState {
@@ -16,6 +17,7 @@ impl CaptureState {
1617
Self {
1718
manager,
1819
in_progress: false,
20+
exit_on_success: false,
1921
}
2022
}
2123

@@ -38,4 +40,21 @@ impl CaptureState {
3840
pub fn clear_in_progress(&mut self) {
3941
self.in_progress = false;
4042
}
43+
44+
/// Marks whether the current capture should exit the overlay on success.
45+
pub fn set_exit_on_success(&mut self, value: bool) {
46+
self.exit_on_success = value;
47+
}
48+
49+
/// Clears any pending exit request for the current capture.
50+
pub fn clear_exit_on_success(&mut self) {
51+
self.exit_on_success = false;
52+
}
53+
54+
/// Returns and clears the exit-on-success flag for the last capture.
55+
pub fn take_exit_on_success(&mut self) -> bool {
56+
let value = self.exit_on_success;
57+
self.exit_on_success = false;
58+
value
59+
}
4160
}

src/backend/wayland/state.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ use wayland_protocols::wp::{
4545
#[cfg(tablet)]
4646
use crate::input::tablet::TabletSettings;
4747
use crate::{
48+
backend::ExitAfterCaptureMode,
4849
capture::{
4950
CaptureDestination, CaptureManager,
5051
file::{FileSaveConfig, expand_tilde},
@@ -109,6 +110,7 @@ pub(in crate::backend::wayland) struct WaylandStateInit {
109110
pub capture_manager: CaptureManager,
110111
pub session_options: Option<SessionOptions>,
111112
pub tokio_handle: tokio::runtime::Handle,
113+
pub exit_after_capture_mode: ExitAfterCaptureMode,
112114
pub frozen_enabled: bool,
113115
pub preferred_output_identity: Option<String>,
114116
pub xdg_fullscreen: bool,
@@ -150,6 +152,9 @@ pub(super) struct WaylandState {
150152
pub(super) frozen: FrozenState,
151153
pub(super) zoom: ZoomState,
152154

155+
// Overlay behavior
156+
pub(super) exit_after_capture_mode: ExitAfterCaptureMode,
157+
153158
// Pointer cursor
154159
pub(super) themed_pointer: Option<ThemedPointer<PointerData>>,
155160
pub(super) locked_pointer: Option<ZwpLockedPointerV1>,

src/backend/wayland/state/capture.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
11
use super::*;
22

33
impl WaylandState {
4+
fn should_exit_after_capture(&self, destination: CaptureDestination) -> bool {
5+
let is_clipboard_only = matches!(destination, CaptureDestination::ClipboardOnly);
6+
match self.exit_after_capture_mode {
7+
ExitAfterCaptureMode::Always => true,
8+
ExitAfterCaptureMode::Never => false,
9+
ExitAfterCaptureMode::Auto => is_clipboard_only,
10+
}
11+
}
12+
413
pub(in crate::backend::wayland) fn apply_capture_completion(&mut self) {
514
if self.frozen.take_capture_done() {
615
self.exit_overlay_suppression(OverlaySuppression::Frozen);
@@ -117,6 +126,9 @@ impl WaylandState {
117126
})
118127
};
119128

129+
let exit_on_success = self.should_exit_after_capture(destination);
130+
self.capture.set_exit_on_success(exit_on_success);
131+
120132
// Suppress overlay before capture to prevent capturing the overlay itself
121133
self.enter_overlay_suppression(OverlaySuppression::Capture);
122134
self.capture.mark_in_progress();
@@ -133,6 +145,7 @@ impl WaylandState {
133145
// Restore overlay on error
134146
self.show_overlay();
135147
self.capture.clear_in_progress();
148+
self.capture.clear_exit_on_success();
136149
}
137150
}
138151
}

0 commit comments

Comments
 (0)