@@ -71,6 +71,7 @@ fn main() {
7171 passed_geometry := fp.string ('geometry' , `g` , '' , 'geometry in the format "400,500 200x300"' )
7272 output_name := fp.string ('output' , `o` , '' , 'name of output to screenshot' )
7373 toplevel_identifier := fp.string ('toplevel' , `t` , '' , 'use a toplevel as the screenshot source by its identifier' )
74+ freeze_screen_cmd := fp.string ('freeze' , `F` , '' , 'freeze the screen until passed command finishes or until the -g command finishes' )
7475 additional_args := fp.finalize () or {
7576 eprintln (err)
7677 println (fp.usage ())
@@ -95,12 +96,16 @@ fn main() {
9596 name
9697 }
9798
98- // get geometry if passed
99- mut geometry := if passed_geometry == '' {
100- Geometry{}
101- } else {
102- Geometry.new (passed_geometry) or { panic ('invalid geometry' ) }
99+ // check if geometry needs command execution (prefix with $)
100+ geometry_is_cmd := passed_geometry.starts_with ('$' ) && ! passed_geometry.starts_with ('$-' )
101+ mut geometry_cmd := ''
102+ if geometry_is_cmd {
103+ geometry_cmd = passed_geometry.trim_left ('$' )
104+ if freeze_screen_cmd != '' {
105+ panic ('ERROR: cannot use both --freeze and command prefix in -g' )
106+ }
103107 }
108+ mut geometry := Geometry{}
104109
105110 // mutual exclusion
106111 if output_name != '' && geometry != Geometry{} {
@@ -153,6 +158,18 @@ fn main() {
153158 if state.outputs.len == 0 {
154159 panic ('no outputs found' )
155160 }
161+ needs_freeze := freeze_screen_cmd != '' || geometry_is_cmd
162+ if needs_freeze {
163+ if state.compositor == none {
164+ panic ('wl_compositor not supported by compositor' )
165+ }
166+ if state.wp_viewporter == none {
167+ panic ('wp_viewporter not supported by compositor' )
168+ }
169+ if state.wlr_layer_shell_v1 == none {
170+ panic ('zwlr_layer_shell_v1 not supported by compositor' )
171+ }
172+ }
156173
157174 // init output manager
158175 if mut manager := state.zxdg_output_manager_v1 {
@@ -180,10 +197,10 @@ fn main() {
180197 mut cm_output := color_manager.get_output (output.wl_output.proxy)
181198 cm_output.add_listener (& cm_output_listener, state)
182199 mut description := cm_output.get_image_description ()
183- description.add_listener (& cm_image_description_listener, output.state)
184- if C.wl_display_roundtrip (display_proxy) < 0 {
185- panic ('wl_display_roundtrip failed' )
186- }
200+ description.add_listener (& cm_image_description_listener, output.state)
201+ if C.wl_display_roundtrip (display_proxy) < 0 {
202+ panic ('wl_display_roundtrip failed' )
203+ }
187204 }
188205 }
189206
@@ -211,7 +228,7 @@ fn main() {
211228 } else {
212229 // capture output
213230 for output in state.outputs {
214- if geometry != Geometry{} && ! geometry.intersect (output.logical_geometry) {
231+ if ! geometry_is_cmd && geometry != Geometry{} && ! geometry.intersect (output.logical_geometry) {
215232 continue
216233 }
217234 if output.logical_scale > scale {
@@ -224,12 +241,98 @@ fn main() {
224241 panic ('no captures found' )
225242 }
226243
227- // dispatch captures
244+ // dispatch initial captures to get buffer data for overlays
228245 mut done := false
229246 expected_cm := if state.wp_color_manager_v1 != none { state.outputs.len } else { 0 }
230247 for ! done && C.wl_display_dispatch (display_proxy) != - 1 {
231248 done = state.n_done == state.captures.len && state.n_cm_done > = expected_cm
232249 }
250+
251+ // run geometry command with freeze
252+ if geometry_is_cmd {
253+ mut geometry_cmd_overlays := []& Overlay{}
254+ for capture in state.captures {
255+ overlay := Overlay.new (capture)
256+ geometry_cmd_overlays << overlay
257+ }
258+
259+ // run command in background thread
260+ result_ch := chan string {cap: 1 }
261+ spawn fn (cmd string , ch chan string ) {
262+ result := os.execute (cmd)
263+ ch < - result.output
264+ }(geometry_cmd, result_ch)
265+
266+ // process Wayland events while waiting for command
267+ mut cmd_output := ''
268+ for {
269+ C.wl_display_dispatch (display_proxy)
270+ C.wl_display_flush (display_proxy)
271+ select {
272+ output := < - result_ch {
273+ cmd_output = output
274+ break
275+ }
276+ }
277+ }
278+ for mut overlay in geometry_cmd_overlays {
279+ overlay.destroy ()
280+ }
281+ geometry = Geometry.new (cmd_output.trim ('\n ' )) or { panic ('invalid geometry from command' ) }
282+ state.captures = []
283+ state.n_done = 0
284+ state.n_cm_done = 0
285+ for output in state.outputs {
286+ if geometry != Geometry{} && ! geometry.intersect (output.logical_geometry) {
287+ continue
288+ }
289+ if output.logical_scale > scale {
290+ scale = output.logical_scale
291+ }
292+ state.capture_output (output, include_cursor)
293+ }
294+ if state.captures.len == 0 {
295+ panic ('no captures found after geometry command' )
296+ }
297+ // re-dispatch for new captures
298+ done = false
299+ for ! done && C.wl_display_dispatch (display_proxy) != - 1 {
300+ done = state.n_done == state.captures.len && state.n_cm_done > = expected_cm
301+ }
302+ }
303+
304+ // freeze screen overlay
305+ mut overlays := []& Overlay{}
306+ if freeze_screen_cmd != '' {
307+ for capture in state.captures {
308+ overlay := Overlay.new (capture)
309+ overlays << overlay
310+ }
311+
312+ // run command in background thread
313+ ch := chan int {cap: 1 }
314+ spawn fn (cmd string , result_ch chan int ) {
315+ result := os.execute (cmd)
316+ result_ch < - result.exit_code
317+ }(freeze_screen_cmd, ch)
318+
319+ // process events while waiting for command
320+ for {
321+ C.wl_display_dispatch (display_proxy)
322+ C.wl_display_flush (display_proxy)
323+ select {
324+ exit_code := < - ch {
325+ for mut overlay in overlays {
326+ overlay.destroy ()
327+ }
328+ if exit_code != 0 {
329+ eprintln ('freeze command exited with code ${exit_code} ' )
330+ }
331+ break
332+ }
333+ }
334+ }
335+ }
233336 if geometry == Geometry{0 , 0 , 0 , 0 } {
234337 geometry = state.get_extents ()
235338 }
@@ -307,5 +410,8 @@ fn main() {
307410 if mut manager := state.zxdg_output_manager_v1 {
308411 manager.destroy ()
309412 }
413+ if mut manager := state.wp_viewporter {
414+ manager.destroy ()
415+ }
310416 C.wl_display_disconnect (display_proxy)
311417}
0 commit comments