Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added

- Optional `freeze` feature and `--freeze` flag: freezes the screen while a selection is in progress.
- `--edit-selection` / `-e` flag: after making an area/dimensions selection, shows draggable
handles on the 4 corners so the rectangle can be adjusted before confirming with a hotkey
(Enter by default, configurable with `--edit-selection-key <keycode>`). The whole rectangle
can also be dragged from its interior to move it.

## [0.6.1] - 2026-03-24

Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,14 @@ Freeze the screen while selecting, so the visible desktop stays static instead o
waysip --freeze -d
```

Edit the selection before confirming it, like flameshot: drag out a rectangle, then adjust
its 4 corner handles as needed (or drag anywhere inside it to move the whole rectangle),
then press Enter (or the key set with `--edit-selection-key <keycode>`) to confirm:

```bash
waysip -d -e
```

# Optional features

All features except `benchmark` and `freeze` are enabled in the default build. To reduce binary size or compile-time dependencies, features can be selectively disabled, or `freeze` can be opted into:
Expand Down
281 changes: 181 additions & 100 deletions libwaysip/src/dispatch.rs

Large diffs are not rendered by default.

34 changes: 34 additions & 0 deletions libwaysip/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ pub struct WaySip {
#[cfg(feature = "benchmark")]
bench: bool,
background_provider: Option<BackgroundProvider>,
edit_selection: bool,
confirm_key: Option<u32>,
}

impl fmt::Debug for WaySip {
Expand All @@ -72,6 +74,8 @@ impl fmt::Debug for WaySip {
debug.field("bench", &self.bench);
debug
.field("background_provider", &self.background_provider.is_some())
.field("edit_selection", &self.edit_selection)
.field("confirm_key", &self.confirm_key)
.finish()
}
}
Expand Down Expand Up @@ -132,6 +136,24 @@ impl WaySip {
self
}

/// Enable "edit selection before confirming": after the initial drag/click
/// for an area selection finishes, four draggable corner handles appear
/// instead of finishing immediately. The selection is confirmed by
/// pressing the confirm key (see [`WaySip::with_confirm_key`], Enter by
/// default).
pub fn with_edit_selection(mut self) -> Self {
self.edit_selection = true;
self
}

/// Overrides the key (as a Linux evdev keycode) used to confirm an edited
/// selection. Defaults to Enter. Only has an effect when combined with
/// [`WaySip::with_edit_selection`].
pub fn with_confirm_key(mut self, key: u32) -> Self {
self.confirm_key = Some(key);
self
}

#[cfg(feature = "benchmark")]
pub fn with_bench(mut self) -> Self {
self.bench = true;
Expand Down Expand Up @@ -167,6 +189,8 @@ impl WaySip {
#[cfg(feature = "benchmark")]
bench,
self.background_provider,
self.edit_selection,
self.confirm_key,
),
None => {
let connection = Connection::connect_to_env()
Expand All @@ -181,12 +205,15 @@ impl WaySip {
#[cfg(feature = "benchmark")]
bench,
self.background_provider,
self.edit_selection,
self.confirm_key,
)
}
}
}
}

#[allow(clippy::too_many_arguments)]
fn get_area_inner(
connection: &Connection,
selection_type: SelectionType,
Expand All @@ -195,11 +222,18 @@ fn get_area_inner(
aspect_ratio: Option<(f64, f64)>,
#[cfg(feature = "benchmark")] bench: bool,
background_provider: Option<BackgroundProvider>,
edit_selection: bool,
confirm_key: Option<u32>,
) -> Result<Option<state::AreaInfo>, WaySipError> {
let (globals, _) = registry_queue_init::<state::WaysipState>(connection)
.map_err(|e| WaySipError::InitFailed(e.to_string()))?;
let mut state = state::WaysipState::new(selection_type);

state.edit_enabled = edit_selection;
if let Some(key) = confirm_key {
state.confirm_key = key;
}

state.predefined_boxes = boxes;
state.aspect_ratio = aspect_ratio;

Expand Down
37 changes: 36 additions & 1 deletion libwaysip/src/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ impl LayerSurfaceInfo {
draw_text: bool,
opt_boxes: Option<&Vec<BoxInfo>>,
redraw_all: bool,
show_handles: bool,
) {
let cairoinfo = &self.cairo_t;
let frozen = self.frozen_bg.as_ref();
Expand All @@ -129,7 +130,12 @@ impl LayerSurfaceInfo {
[rx1, ry1, rx2, ry2]
};

let border_margin = self.style.border_weight + 2.0;
let handle_radius = (self.style.border_weight * 3.0).max(5.0);
let border_margin = if show_handles {
(self.style.border_weight + 2.0).max(handle_radius + 2.0)
} else {
self.style.border_weight + 2.0
};

let (text_margin_w, text_margin_h) = *self.margin.get_or_init(|| {
if !draw_text {
Expand Down Expand Up @@ -254,6 +260,35 @@ impl LayerSurfaceInfo {
cairoinfo.set_line_width(self.style.border_weight);
cairoinfo.stroke().unwrap();

if show_handles {
let handles = [
(relate_start_x, relate_start_y),
(relate_end_x, relate_start_y),
(relate_start_x, relate_end_y),
(relate_end_x, relate_end_y),
];
for (hx, hy) in handles {
cairoinfo.save().unwrap();
cairoinfo.arc(hx, hy, handle_radius, 0.0, std::f64::consts::TAU);
cairoinfo.set_source_rgba(
self.style.border_text_color.r,
self.style.border_text_color.g,
self.style.border_text_color.b,
self.style.border_text_color.a,
);
cairoinfo.fill_preserve().unwrap();
cairoinfo.set_source_rgba(
self.style.background_color.r,
self.style.background_color.g,
self.style.background_color.b,
1.0,
);
cairoinfo.set_line_width(1.5);
cairoinfo.stroke().unwrap();
cairoinfo.restore().unwrap();
}
}

if draw_text {
let font_size = self.style.font_size;
let pangolayout = self
Expand Down
Loading