27#include "absl/status/status.h"
28#include "absl/status/statusor.h"
29#include "absl/strings/str_format.h"
30#include "absl/time/clock.h"
32#include "imgui_internal.h"
40struct ImGui_ImplSDLRenderer2_Data {
41 SDL_Renderer* Renderer;
44std::filesystem::path DefaultScreenshotPath() {
47 std::filesystem::path base_dir;
48 if (base_dir_or.ok()) {
49 base_dir = *base_dir_or;
51 base_dir = std::filesystem::temp_directory_path() /
"yaze" /
"screenshots";
55 std::filesystem::create_directories(base_dir, ec);
57 const int64_t timestamp_ms = absl::ToUnixMillis(absl::Now());
58 return base_dir / std::filesystem::path(absl::StrFormat(
59 "yaze_%lld.bmp",
static_cast<long long>(timestamp_ms)));
62void RevealScreenshot(
const std::string& path) {
65 std::string cmd = absl::StrFormat(
"open \"%s\"", path);
66 int result = system(cmd.c_str());
73absl::StatusOr<ScreenshotArtifact> CaptureHarnessScreenshot(
74 const std::string& preferred_path) {
75 ImGuiIO& io = ImGui::GetIO();
77 static_cast<ImGui_ImplSDLRenderer2_Data*
>(io.BackendRendererUserData);
79 if (!backend_data || !backend_data->Renderer) {
80 return absl::FailedPreconditionError(
"SDL renderer not available");
83 SDL_Renderer* renderer = backend_data->Renderer;
87 return absl::InternalError(
88 absl::StrFormat(
"Failed to get renderer size: %s", SDL_GetError()));
91 std::filesystem::path output_path =
92 preferred_path.empty() ? DefaultScreenshotPath()
93 : std::filesystem::path(preferred_path);
94 if (output_path.has_parent_path()) {
96 std::filesystem::create_directories(output_path.parent_path(), ec);
99 SDL_Surface* surface =
102 return absl::InternalError(absl::StrFormat(
103 "Failed to read pixels to surface: %s", SDL_GetError()));
106 if (SDL_SaveBMP(surface, output_path.string().c_str()) != 0) {
108 return absl::InternalError(
109 absl::StrFormat(
"Failed to save BMP: %s", SDL_GetError()));
115 const int64_t file_size = std::filesystem::file_size(output_path, ec);
117 return absl::InternalError(
118 absl::StrFormat(
"Failed to stat screenshot %s: %s",
119 output_path.string(), ec.message()));
122 ScreenshotArtifact artifact;
123 artifact.file_path = output_path.string();
124 artifact.width = width;
125 artifact.height = height;
126 artifact.file_size_bytes = file_size;
129 RevealScreenshot(artifact.file_path);
134absl::StatusOr<ScreenshotArtifact> CaptureHarnessScreenshotRegion(
135 const std::optional<CaptureRegion>& region,
136 const std::string& preferred_path) {
137 ImGuiIO& io = ImGui::GetIO();
139 static_cast<ImGui_ImplSDLRenderer2_Data*
>(io.BackendRendererUserData);
141 if (!backend_data || !backend_data->Renderer) {
142 return absl::FailedPreconditionError(
"SDL renderer not available");
145 SDL_Renderer* renderer = backend_data->Renderer;
152 return absl::InternalError(
153 absl::StrFormat(
"Failed to get renderer size: %s", SDL_GetError()));
159 int capture_width = full_width;
160 int capture_height = full_height;
162 if (region.has_value()) {
163 capture_x = region->x;
164 capture_y = region->y;
165 capture_width = region->width;
166 capture_height = region->height;
173 if (capture_x + capture_width > full_width) {
174 capture_width = full_width - capture_x;
176 if (capture_y + capture_height > full_height) {
177 capture_height = full_height - capture_y;
180 if (capture_width <= 0 || capture_height <= 0) {
181 return absl::InvalidArgumentError(
"Invalid capture region");
185 std::filesystem::path output_path =
186 preferred_path.empty() ? DefaultScreenshotPath()
187 : std::filesystem::path(preferred_path);
188 if (output_path.has_parent_path()) {
190 std::filesystem::create_directories(output_path.parent_path(), ec);
194 SDL_Rect region_rect = {capture_x, capture_y, capture_width, capture_height};
196 renderer, capture_width, capture_height, ®ion_rect);
199 return absl::InternalError(absl::StrFormat(
200 "Failed to read pixels to surface: %s", SDL_GetError()));
203 if (SDL_SaveBMP(surface, output_path.string().c_str()) != 0) {
205 return absl::InternalError(
206 absl::StrFormat(
"Failed to save BMP: %s", SDL_GetError()));
212 const int64_t file_size = std::filesystem::file_size(output_path, ec);
214 return absl::InternalError(
215 absl::StrFormat(
"Failed to stat screenshot %s: %s",
216 output_path.string(), ec.message()));
219 ScreenshotArtifact artifact;
220 artifact.file_path = output_path.string();
221 artifact.width = capture_width;
222 artifact.height = capture_height;
223 artifact.file_size_bytes = file_size;
226 RevealScreenshot(artifact.file_path);
231absl::StatusOr<ScreenshotArtifact> CaptureActiveWindow(
232 const std::string& preferred_path) {
233 ImGuiContext* ctx = ImGui::GetCurrentContext();
234 if (!ctx || !ctx->NavWindow) {
235 return absl::FailedPreconditionError(
"No active ImGui window");
238 ImGuiWindow* window = ctx->NavWindow;
239 CaptureRegion region;
240 region.x =
static_cast<int>(window->Pos.x);
241 region.y =
static_cast<int>(window->Pos.y);
242 region.width =
static_cast<int>(window->Size.x);
243 region.height =
static_cast<int>(window->Size.y);
245 return CaptureHarnessScreenshotRegion(region, preferred_path);
248absl::StatusOr<ScreenshotArtifact> CaptureWindowByName(
249 const std::string& window_name,
const std::string& preferred_path) {
250 ImGuiContext* ctx = ImGui::GetCurrentContext();
252 return absl::FailedPreconditionError(
"No ImGui context");
255 ImGuiWindow* window = ImGui::FindWindowByName(window_name.c_str());
257 return absl::NotFoundError(
258 absl::StrFormat(
"Window '%s' not found", window_name));
261 CaptureRegion region;
262 region.x =
static_cast<int>(window->Pos.x);
263 region.y =
static_cast<int>(window->Pos.y);
264 region.width =
static_cast<int>(window->Size.x);
265 region.height =
static_cast<int>(window->Size.y);
267 return CaptureHarnessScreenshotRegion(region, preferred_path);
SDL2/SDL3 compatibility layer.