Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Basic Drawable framework + cropping #88

Merged
merged 54 commits into from
Feb 5, 2024
Merged
Show file tree
Hide file tree
Changes from 53 commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
7abdcf5
WIP cropping
eneoli Jan 24, 2024
61f9a88
added surface as parameter
eneoli Jan 24, 2024
c568ffc
added ToolCommand
eneoli Jan 24, 2024
7c7ff5c
cleanup
eneoli Jan 24, 2024
9fa3eb8
added draw_final
eneoli Jan 28, 2024
cce80bb
cleanup
eneoli Jan 28, 2024
addaac8
erge remote-tracking branch 'origin/main' into feature/cropping
eneoli Jan 28, 2024
78d3f2d
finished cropping
eneoli Jan 28, 2024
3c94d1c
cleanup
eneoli Jan 28, 2024
5e17093
persist canvas after all monitor initialized
eneoli Jan 28, 2024
6b00fff
fix "This application can not open files." error
eneoli Jan 29, 2024
6b84bf0
fix "his application can not open files." error
eneoli Jan 29, 2024
57f15fa
cleanup
eneoli Feb 2, 2024
b387a9b
Bind mouse move event to canvas only
eneoli Feb 2, 2024
c9c7b95
cleanup
eneoli Feb 2, 2024
75c8b79
added draw_active and draw_inactive
eneoli Feb 3, 2024
982cb3e
cleanup
eneoli Feb 3, 2024
739814d
added tool manager
eneoli Feb 3, 2024
3988d27
rename draw to draw_active
eneoli Feb 3, 2024
e4f485a
finished cropping
eneoli Feb 3, 2024
a233906
added ToolIdentifier
eneoli Feb 3, 2024
888b967
added ToolManager
eneoli Feb 3, 2024
6be10f7
use ToolIdentifer, added button group
eneoli Feb 3, 2024
3d11210
added own trait to unlink from drawable states
eneoli Feb 3, 2024
46a9430
added rectangle
eneoli Feb 3, 2024
f60abb0
using rectangle
eneoli Feb 3, 2024
30732f2
using rectangle
eneoli Feb 3, 2024
5cfd8a1
cleanup
eneoli Feb 3, 2024
f73b936
added rectangle
eneoli Feb 3, 2024
8f8ec2e
using rectangle, cleanup
eneoli Feb 3, 2024
9433e23
we are usable!
eneoli Feb 3, 2024
f8900a5
cleanup
eneoli Feb 3, 2024
9171e33
make clippy happy
eneoli Feb 3, 2024
cbb131a
use HashMap::from
eneoli Feb 3, 2024
0686b4e
Automated formatting
Feb 3, 2024
8b9ddbe
cleanup selection assignment
eneoli Feb 3, 2024
80c235f
Automated formatting
Feb 3, 2024
9196b7b
restructuring frontend
eneoli Feb 3, 2024
c32a6d4
erge branch 'feature/cropping' of github.com:eneoli/flakeshot into fe…
eneoli Feb 3, 2024
00967b5
Mouse events as struct variants
eneoli Feb 3, 2024
4c9a339
fix x11 window bugs
eneoli Feb 4, 2024
ba0783a
added gdk4_x11
eneoli Feb 4, 2024
65b8cca
present file chooser
eneoli Feb 4, 2024
b07e4ef
partial fix x11 screenshots
eneoli Feb 4, 2024
460afae
using HashMap::from
eneoli Feb 5, 2024
c9fb16b
using Point struct
eneoli Feb 5, 2024
40c6ce4
Merge remote-tracking branch 'origin/main' into feature/cropping
eneoli Feb 5, 2024
860793f
fixed errors after merge
eneoli Feb 5, 2024
7fb3131
Automated formatting
Feb 5, 2024
8213f41
temporary remove x11 window movement
eneoli Feb 5, 2024
cb7481b
cleanup
eneoli Feb 5, 2024
36074f7
cleanup
eneoli Feb 5, 2024
1754101
Merge branch 'feature/cropping' of github.com:eneoli/flakeshot into f…
eneoli Feb 5, 2024
4fd4dc3
removed deprecated hide call
eneoli Feb 5, 2024
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
411 changes: 319 additions & 92 deletions Cargo.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,4 @@ gtk4-layer-shell = "0.2.0"
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
xdg = "2.5"
gdk4-x11 = "0.8.0"
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ were often only either for X11 *or* Wayland. `flakeshot` should close this gap b
tool which should run on X11 as good as on Wayland.

# Status
`flakeshot` is still under heavy development and not considered useable.
`flakeshot` already has basic screenshot capabilities including cropping. More features are currently being developed.

<!-----------------------{ Links }---------------------------->

Expand Down
33 changes: 22 additions & 11 deletions src/backend/x11.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ pub fn create_screenshots() -> Result<Vec<(OutputInfo, image::DynamicImage)>, Er
let mut images = Vec::with_capacity(setup.roots.len());

for screen in &setup.roots {
let image = get_image(&conn, screen)?;
let monitors = conn.randr_get_monitors(screen.root, true)?.reply()?;

for monitor in &monitors.monitors {
Expand All @@ -65,6 +64,14 @@ pub fn create_screenshots() -> Result<Vec<(OutputInfo, image::DynamicImage)>, Er
"We currently support only one output for each monitor. Please create an issue if you encounter this assert."
);

let image = get_image(
&conn,
screen,
monitor.x,
monitor.y,
monitor.width,
monitor.height,
)?;
let monitor_info = {
let screen_resources = conn
.randr_get_screen_resources_current(screen.root)?
Expand Down Expand Up @@ -102,26 +109,30 @@ pub fn create_screenshots() -> Result<Vec<(OutputInfo, image::DynamicImage)>, Er
Ok(images)
}

fn get_image(conn: &RustConnection, screen: &Screen) -> Result<DynamicImage, Error> {
fn get_image(
conn: &RustConnection,
screen: &Screen,
x: i16,
y: i16,
width: u16,
height: u16,
) -> Result<DynamicImage, Error> {
use x11rb::protocol::xproto::ConnectionExt;
const ALL_BITS: u32 = u32::MAX;

let setup = &conn.setup();
let width_u16 = screen.width_in_pixels;
let height_u16 = screen.height_in_pixels;

let width_u32 = u32::from(width_u16);
let height_u32 = u32::from(height_u16);
let width_u32 = u32::from(width);
let height_u32 = u32::from(height);

let (image_bytes, pixmap_format) = {
let image_reply = conn
.get_image(
ImageFormat::Z_PIXMAP,
screen.root,
0,
0,
width_u16,
height_u16,
x,
y,
width,
height,
eneoli marked this conversation as resolved.
Show resolved Hide resolved
ALL_BITS,
)
.map_err(Error::from)?
Expand Down
6 changes: 2 additions & 4 deletions src/frontend/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
pub mod file_chooser;
pub mod main_window;
pub mod screenshot_window;
pub mod shape;
pub mod ui;
pub mod ui_manager;
pub mod window;
2 changes: 2 additions & 0 deletions src/frontend/shape/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod point;
pub mod rectangle;
12 changes: 12 additions & 0 deletions src/frontend/shape/point.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#[derive(Debug, Copy, Clone, Default)]
pub struct Point {
pub x: f64,
pub y: f64,
}

impl Point {
pub fn add(&mut self, point: Point) {
self.x += point.x;
self.y += point.y;
}
}
37 changes: 37 additions & 0 deletions src/frontend/shape/rectangle.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
use super::point::Point;

#[derive(Copy, Clone, Default)]
pub struct Rectangle {
pub fst: Point,
pub snd: Point,
}

impl Rectangle {
pub fn with_size(width: f64, height: f64) -> Self {
Self {
fst: Point { x: 0.0, y: 0.0 },
snd: Point {
x: width,
y: height,
},
}
}

pub fn get_points_clockwise(&self) -> (Point, Point) {
let x_left = f64::min(self.fst.x, self.snd.x);
let x_right = f64::max(self.fst.x, self.snd.x);
let y_top = f64::min(self.fst.y, self.snd.y);
let y_bottom = f64::max(self.fst.y, self.snd.y);

(
Point {
x: x_left,
y: y_top,
},
Point {
x: x_right,
y: y_bottom,
},
)
}
}
52 changes: 39 additions & 13 deletions src/frontend/ui/canvas.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,30 @@
use gtk4::cairo::{Context, Format, ImageSurface};
use gtk4::cairo::{Context, Filter, Format, ImageSurface};
use image::{DynamicImage, RgbaImage};

use super::drawable::Drawable;
pub trait CanvasDrawable {
fn draw(&self, ctx: &Context, surface: &ImageSurface);
}

pub struct Canvas {
surface: ImageSurface,
drawables: Vec<Box<dyn Drawable>>,
original: ImageSurface,
}

impl Canvas {
pub fn new(width: i32, height: i32) -> anyhow::Result<Self> {
Ok(Canvas {
surface: ImageSurface::create(Format::ARgb32, width, height)?,
drawables: vec![],
original: ImageSurface::create(Format::ARgb32, width, height)?,
})
}

pub fn from_original(&self) -> Self {
Canvas {
surface: self.original.clone(),
original: self.original.clone(),
}
}

pub fn width(&self) -> i32 {
self.surface.width()
}
Expand All @@ -24,21 +33,35 @@ impl Canvas {
self.surface.height()
}

pub fn add_drawable(&mut self, drawable: Box<dyn Drawable>) {
self.drawables.push(drawable);
}

pub fn render(&self) -> anyhow::Result<()> {
pub fn clear(&mut self) -> anyhow::Result<()> {
let ctx = Context::new(&self.surface)?;
ctx.set_source_surface(&self.original, 0.0, 0.0)?;
ctx.paint()?;

for drawable in &self.drawables {
drawable.draw(&ctx);
}
Ok(())
}

pub fn save(&mut self) -> anyhow::Result<()> {
let original_ctx = Context::new(&self.original)?;
original_ctx.set_source_surface(&self.surface, 0.0, 0.0)?;
original_ctx.paint()?;

Ok(())
}

pub fn stamp_image(&self, x: f64, y: f64, image: &DynamicImage) -> anyhow::Result<()> {
pub fn render_drawable(&mut self, drawable: &dyn CanvasDrawable) {
let ctx = Context::new(&self.surface).unwrap();
drawable.draw(&ctx, &self.surface);
}

pub fn stamp_image(
&self,
x: f64,
y: f64,
width: f64,
height: f64,
image: &DynamicImage,
) -> anyhow::Result<()> {
let ctx = Context::new(&self.surface)?;

let mut image_bytes = Vec::from(image.as_bytes());
Expand All @@ -47,6 +70,7 @@ impl Canvas {
for i in (0..image_bytes.len()).step_by(4) {
image_bytes[i..i + 3].reverse();
}

let image_surface = ImageSurface::create_for_data(
image_bytes,
Format::ARgb32,
Expand All @@ -55,7 +79,9 @@ impl Canvas {
Format::stride_for_width(Format::ARgb32, image.width())?,
)?;

ctx.scale(width / image.width() as f64, height / image.height() as f64);
ctx.set_source_surface(&image_surface, x, y)?;
ctx.source().set_filter(Filter::Best);
ctx.paint()?;

Ok(())
Expand Down
6 changes: 4 additions & 2 deletions src/frontend/ui/drawable/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use gtk4::cairo::Context;
use gtk4::cairo::{Context, ImageSurface};

pub trait Drawable {
fn draw(&self, ctx: &Context);
fn draw_active(&self, ctx: &Context, surface: &ImageSurface);
fn draw_inactive(&self, ctx: &Context, surface: &ImageSurface);
fn draw_final(&self, ctx: &Context, surface: &ImageSurface);
}
3 changes: 3 additions & 0 deletions src/frontend/ui/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
pub mod canvas;
pub mod drawable;
pub mod tool;
pub mod tool_manager;
pub mod toolbar;
pub mod ui_manager;
Loading