@@ -284,25 +284,22 @@ Result<capture_result_t> capture_full_screen_wayland()
284284 return Ok (std::move (result));
285285}
286286
287- struct portal_capture_t
288- {
289- std::string png_path;
290- std::string error_msg;
291- capture_result_t cap;
292- } cap_portal;
293-
294287struct portal_state_t
295288{
296289 GMainLoop* loop;
297290 guint subscription_id;
298291 guint timeout_id; // tracked so we can cancel it before the stack frame is gone
292+
293+ std::string png_path;
294+ std::string error_msg;
295+ capture_result_t cap;
299296};
300297
301298static gboolean on_timeout (gpointer user_data)
302299{
303- portal_state_t * st = reinterpret_cast <portal_state_t *>(user_data);
304- cap_portal. error_msg = " Timed out waiting for portal response (is xdg-desktop-portal running?)" ;
305- st->timeout_id = 0 ; // GLib will remove the source; mark it gone so cleanup skips it
300+ portal_state_t * st = reinterpret_cast <portal_state_t *>(user_data);
301+ st-> error_msg = " Timed out waiting for portal response (is xdg-desktop-portal running?)" ;
302+ st->timeout_id = 0 ; // GLib will remove the source; mark it gone so cleanup skips it
306303 g_main_loop_quit (st->loop );
307304 return G_SOURCE_REMOVE;
308305}
@@ -343,9 +340,9 @@ static void on_response(GDBusConnection* conn,
343340 g_variant_get (parameters, " (u@a{sv})" , &response, &results);
344341
345342 if (response != 0 )
346- cap_portal. error_msg = fmt::format (" Cancelled or failed (response={})" , (unsigned )response);
343+ st-> error_msg = fmt::format (" Cancelled or failed (response={})" , (unsigned )response);
347344 else if (!(g_variant_lookup (results, " uri" , " &s" , &uri) && uri))
348- cap_portal. error_msg = " Success, but portal returned no uri" ;
345+ st-> error_msg = " Success, but portal returned no uri" ;
349346
350347 if (results)
351348 g_variant_unref (results);
@@ -359,31 +356,30 @@ static void on_response(GDBusConnection* conn,
359356 const Result<std::string>& res = uri_to_path (uri);
360357 if (res.ok ())
361358 {
362- cap_portal. png_path = res.get ();
363- cap_portal. error_msg = " " ;
359+ st-> png_path = res.get ();
360+ st-> error_msg = " " ;
364361 }
365362 else
366363 {
367- cap_portal. png_path = " " ;
368- cap_portal. error_msg = res.error_v ();
364+ st-> png_path = " " ;
365+ st-> error_msg = res.error_v ();
369366 }
370367
371368 g_main_loop_quit (st->loop );
372369}
373370
374371Result<capture_result_t > capture_full_screen_portal ()
375372{
376- cap_portal = {};
373+ portal_state_t st {};
377374 warn (" Fallback to portal capture" );
378375
379376 GError* error = nullptr ;
380377 GDBusConnection* bus = g_bus_get_sync (G_BUS_TYPE_SESSION, nullptr , &error);
381378 if (!bus)
382379 {
383- cap_portal.error_msg =
384- " Failed to connect to session bus: " + std::string (error->message ? error->message : " Unknown" );
380+ st.error_msg = " Failed to connect to session bus: " + std::string (error->message ? error->message : " Unknown" );
385381 g_error_free (error);
386- return Err (cap_portal .error_msg );
382+ return Err (st .error_msg );
387383 }
388384
389385 // Call Screenshot portal synchronously so we can fail loudly if the service isn't there.
@@ -402,10 +398,10 @@ Result<capture_result_t> capture_full_screen_portal()
402398
403399 if (!reply)
404400 {
405- cap_portal .error_msg = " Portal call failed: " + std::string (error->message ? error->message : " Unknown" );
401+ st .error_msg = " Portal call failed: " + std::string (error->message ? error->message : " Unknown" );
406402 g_error_free (error);
407403 g_object_unref (bus);
408- return Err (cap_portal .error_msg );
404+ return Err (st .error_msg );
409405 }
410406
411407 const char * request_path = nullptr ;
@@ -418,7 +414,6 @@ Result<capture_result_t> capture_full_screen_portal()
418414 return Err (" Portal returned an empty request handle" );
419415 }
420416
421- portal_state_t st;
422417 st.loop = g_main_loop_new (nullptr , FALSE );
423418 st.subscription_id = 0 ;
424419 st.timeout_id = 0 ;
@@ -457,73 +452,66 @@ Result<capture_result_t> capture_full_screen_portal()
457452 g_main_loop_unref (st.loop );
458453 g_object_unref (bus);
459454
460- if (cap_portal .png_path .empty ())
455+ if (st .png_path .empty ())
461456 {
462- if (cap_portal .error_msg .empty ())
457+ if (st .error_msg .empty ())
463458 return Err (" Failed to retrieve uri path to screenshot PNG" );
464- return Err (cap_portal .error_msg );
459+ return Err (st .error_msg );
465460 }
466461
467462 int w = 0 , h = 0 , comp = 0 ;
468- uint8_t * rgba = stbi_load (cap_portal .png_path .c_str (), &w, &h, &comp, STBI_rgb_alpha);
463+ uint8_t * rgba = stbi_load (st .png_path .c_str (), &w, &h, &comp, STBI_rgb_alpha);
469464
470465 if (!rgba)
471466 {
472467 const char * reason = stbi_failure_reason ();
473- unlink (cap_portal .png_path .c_str ());
468+ unlink (st .png_path .c_str ());
474469 return Err (" Failed to read PNG data: " + std::string (reason ? reason : " Unknown" ));
475470 }
476471
477- cap_portal .cap .w = w;
478- cap_portal .cap .h = h;
479- cap_portal .cap .data .assign (rgba, rgba + (static_cast <size_t >(w) * h * 4 ));
472+ st .cap .w = w;
473+ st .cap .h = h;
474+ st .cap .data .assign (rgba, rgba + (static_cast <size_t >(w) * h * 4 ));
480475 stbi_image_free (rgba);
481476
482477 // The portal backend (on KDE mostly) writes a permanent file to ~/Pictures named "Screenshot_*.png".
483478 // Delete it now that we have the pixels in memory.
484- unlink (cap_portal .png_path .c_str ());
479+ unlink (st .png_path .c_str ());
485480
486481 // The portal always captures the full virtual desktop on multi-monitor
487482 // setups. Crop down to the monitor that contains the cursor.
488483 // XRandR works on native X11 and on KDE/GNOME Wayland via XWayland.
489484 {
490485 int mx = 0 , my = 0 , mw = 0 , mh = 0 ;
491- if (get_cursor_monitor_xrandr (nullptr , mx, my, mw, mh) && (cap_portal .cap .w > mw || cap_portal .cap .h > mh))
486+ if (get_cursor_monitor_xrandr (nullptr , mx, my, mw, mh) && (st .cap .w > mw || st .cap .h > mh))
492487 {
493- debug (" Portal: cropping {}x{} capture to monitor {}x{}+{}+{}" ,
494- cap_portal.cap .w ,
495- cap_portal.cap .h ,
496- mw,
497- mh,
498- mx,
499- my);
488+ debug (" Portal: cropping {}x{} capture to monitor {}x{}+{}+{}" , st.cap .w , st.cap .h , mw, mh, mx, my);
500489
501490 const int x0 = std::max (0 , mx);
502491 const int y0 = std::max (0 , my);
503- const int x1 = std::min (cap_portal .cap .w , mx + mw);
504- const int y1 = std::min (cap_portal .cap .h , my + mh);
492+ const int x1 = std::min (st .cap .w , mx + mw);
493+ const int y1 = std::min (st .cap .h , my + mh);
505494 const int new_w = x1 - x0;
506495 const int new_h = y1 - y0;
507496
508497 if (new_w > 0 && new_h > 0 )
509498 {
510- const int src_stride = cap_portal .cap .w ;
499+ const int src_stride = st .cap .w ;
511500 std::vector<uint8_t > cropped (static_cast <size_t >(new_w) * new_h * 4 );
512501 for (int row = 0 ; row < new_h; ++row)
513502 {
514- const uint8_t * src =
515- cap_portal.cap .data .data () + (static_cast <size_t >(y0 + row) * src_stride + x0) * 4 ;
516- uint8_t * dst = cropped.data () + static_cast <size_t >(row) * new_w * 4 ;
503+ const uint8_t * src = st.cap .data .data () + (static_cast <size_t >(y0 + row) * src_stride + x0) * 4 ;
504+ uint8_t * dst = cropped.data () + static_cast <size_t >(row) * new_w * 4 ;
517505 std::memcpy (dst, src, static_cast <size_t >(new_w) * 4 );
518506 }
519- cap_portal .cap .data = std::move (cropped);
520- cap_portal .cap .w = new_w;
521- cap_portal .cap .h = new_h;
507+ st .cap .data = std::move (cropped);
508+ st .cap .w = new_w;
509+ st .cap .h = new_h;
522510 }
523511 }
524512 }
525513
526- return Ok (std::move (cap_portal .cap ));
514+ return Ok (std::move (st .cap ));
527515}
528516
529517#else
0 commit comments