diff --git a/.vscode/launch.json b/.vscode/launch.json index 7b9f071..3ed4767 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -52,6 +52,30 @@ } ] }, + { + "name": "swappy - file & stdout", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/build/swappy", + "args": ["-f", "docs/images/screenshot.png", "-o", "-"], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [ + { + "name": "G_MESSAGES_DEBUG", + "value": "all" + } + ], + "externalConsole": false, + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ] + }, { "name": "swappy - stdin", "type": "cppdbg", diff --git a/README.md b/README.md index e468d22..83d7116 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,12 @@ Select a region and swappshot it: swappy -g "$(slurp)" ``` +Print final surface to stdout (useful to pipe with other tools): + +```sh +grim -g "$(slurp)" - | swappy -f - -o - | pngquant - +``` + Grab a swappshot from a specific window under Sway, using `swaymsg` and `jq`: ```sh @@ -92,7 +98,7 @@ The following lines can be used as swappy's default: - `Ctrl+Shift+z` or `Ctrl+y`: Redo - `Ctrl+s`: Save to file (see man page) - `Ctrl+c`: Copy to clipboard -- `Escape` or `q`: Quit swappy +- `Escape` or `q` or `Ctrl+w`: Quit swappy ## Limitations diff --git a/include/pixbuf.h b/include/pixbuf.h index 05a9a18..6d48b75 100644 --- a/include/pixbuf.h +++ b/include/pixbuf.h @@ -2,4 +2,7 @@ #include "swappy.h" -void pixbuf_save_to_file(struct swappy_state *state); \ No newline at end of file +GdkPixbuf *pixbuf_get_from_state(struct swappy_state *state); +void pixbuf_save_state_to_folder(GdkPixbuf *pixbuf, char *folder); +void pixbuf_save_to_file(GdkPixbuf *pixbuf, char *file); +void pixbuf_save_to_stdout(GdkPixbuf *pixbuf); \ No newline at end of file diff --git a/include/swappy.h b/include/swappy.h index 41e2e7e..587e0e7 100644 --- a/include/swappy.h +++ b/include/swappy.h @@ -191,6 +191,7 @@ struct swappy_state { /* Options */ char *geometry_str; char *file_str; + char *output_file; struct swappy_box *geometry; diff --git a/src/application.c b/src/application.c index f781543..35569fd 100644 --- a/src/application.c +++ b/src/application.c @@ -166,6 +166,19 @@ static void action_text_size_increase(struct swappy_state *state) { update_ui_text_size_widget(state); } +static void save_state_to_file_or_folder(struct swappy_state *state, + char *file) { + GdkPixbuf *pixbuf = pixbuf_get_from_state(state); + + if (file == NULL) { + pixbuf_save_state_to_folder(pixbuf, state->config->save_dir); + } else { + pixbuf_save_to_file(pixbuf, file); + } + + g_object_unref(pixbuf); +} + void brush_clicked_handler(GtkWidget *widget, struct swappy_state *state) { switch_mode_to_brush(state); } @@ -187,6 +200,9 @@ void arrow_clicked_handler(GtkWidget *widget, struct swappy_state *state) { } void application_finish(struct swappy_state *state) { + if (state->output_file != NULL) { + save_state_to_file_or_folder(state, state->output_file); + } paint_free_all(state); buffer_free_all(state); cairo_surface_destroy(state->cairo_surface); @@ -201,7 +217,7 @@ void application_finish(struct swappy_state *state) { } void save_clicked_handler(GtkWidget *widget, struct swappy_state *state) { - pixbuf_save_to_file(state); + save_state_to_file_or_folder(state, NULL); } void clear_clicked_handler(GtkWidget *widget, struct swappy_state *state) { @@ -225,11 +241,14 @@ void window_keypress_handler(GtkWidget *widget, GdkEventKey *event, clipboard_copy_drawing_area_to_selection(state); break; case GDK_KEY_s: - pixbuf_save_to_file(state); + save_state_to_file_or_folder(state, NULL); break; case GDK_KEY_b: action_toggle_painting_pane(state); break; + case GDK_KEY_w: + gtk_main_quit(); + break; case GDK_KEY_z: action_undo(state); break; @@ -652,6 +671,14 @@ bool application_init(struct swappy_state *state) { .arg_data = &state->file_str, .description = "Load a file at a specific path", }, + { + .long_name = "output-file", + .short_name = 'o', + .arg = G_OPTION_ARG_STRING, + .arg_data = &state->output_file, + .description = "Print the final surface to the given file when " + "exiting, use - to print to stdout", + }, {NULL}}; state->app = gtk_application_new("me.jtheoof.swappy", diff --git a/src/pixbuf.c b/src/pixbuf.c index b8c8940..79d4c71 100644 --- a/src/pixbuf.c +++ b/src/pixbuf.c @@ -1,12 +1,19 @@ #include "pixbuf.h" +#include + #include "notification.h" -void pixbuf_save_to_file(struct swappy_state *state) { +GdkPixbuf *pixbuf_get_from_state(struct swappy_state *state) { guint width = gtk_widget_get_allocated_width(state->ui->area); guint height = gtk_widget_get_allocated_height(state->ui->area); GdkPixbuf *pixbuf = gdk_pixbuf_get_from_surface(state->cairo_surface, 0, 0, width, height); + + return pixbuf; +} + +void pixbuf_save_state_to_folder(GdkPixbuf *pixbuf, char *folder) { GError *error = NULL; time_t current_time; @@ -17,8 +24,7 @@ void pixbuf_save_to_file(struct swappy_state *state) { c_time_string = ctime(¤t_time); c_time_string[strlen(c_time_string) - 1] = '\0'; char path[MAX_PATH]; - snprintf(path, MAX_PATH, "%s/%s %s.png", state->config->save_dir, "Swappshot", - c_time_string); + snprintf(path, MAX_PATH, "%s/%s %s.png", folder, "Swappshot", c_time_string); gdk_pixbuf_savev(pixbuf, path, "png", NULL, NULL, &error); if (error != NULL) { @@ -32,5 +38,29 @@ void pixbuf_save_to_file(struct swappy_state *state) { snprintf(message, len, "%s%s", msg, path); notification_send("Swappy", message); g_free(message); - g_object_unref(pixbuf); } + +void pixbuf_save_to_stdout(GdkPixbuf *pixbuf) { + GOutputStream *out; + GError *error = NULL; + + out = g_unix_output_stream_new(STDOUT_FILENO, TRUE); + + gdk_pixbuf_save_to_stream(pixbuf, out, "png", NULL, &error); + + if (error != NULL) { + g_warning("unable to save surface to stdout: %s", error->message); + g_error_free(error); + return; + } + + g_object_unref(out); +} + +void pixbuf_save_to_file(GdkPixbuf *pixbuf, char *file) { + if (g_strcmp0(file, "-") == 0) { + pixbuf_save_to_stdout(pixbuf); + } else { + pixbuf_save_to_file(pixbuf, file); + } +} \ No newline at end of file diff --git a/swappy.1.scd b/swappy.1.scd index 912b5df..4e83492 100644 --- a/swappy.1.scd +++ b/swappy.1.scd @@ -39,6 +39,14 @@ to: *$HOME/Desktop*. If set to *-*, read the file from standard input instead. This is grim friendly. +*-o, --output-file * + Print the final surface to ** when exiting the application. + + If set to *-*, prints the final surface to *stdout*. + + Note that the *Save* button will save the image to the config *save_dir* + parameter, as described in the SYNOPSIS section. + # CONFIG FILE The config file is located at *$XDG\_CONFIG\_HOME/swappy/config* or at @@ -93,7 +101,7 @@ The following lines can be used as swappy's default: - *Ctrl+Shift+z* or *Ctrl+y*: Redo - *Ctrl+s*: Save to file (see man page) - *Ctrl+c*: Copy to clipboard -- *Escape* or *q*: Quit swappy +- *Escape* or *q* or *Ctrl+w*: Quit swappy # AUTHORS