Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ transparency=50
- `Ctrl+z`: Undo
- `Ctrl+Shift+z` or `Ctrl+y`: Redo
- `Ctrl+s`: Save to file (see man page)
- `Ctrl+Shift+s`: Open "Save As" dialog
- `Ctrl+c`: Copy to clipboard
- `Escape` or `q` or `Ctrl+w`: Quit swappy

Expand Down
1 change: 1 addition & 0 deletions include/pixbuf.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

GdkPixbuf *pixbuf_init_from_file(struct swappy_state *state);
GdkPixbuf *pixbuf_get_from_state(struct swappy_state *state);
char *format_filename(char *filename_format);
void pixbuf_save_state_to_folder(GdkPixbuf *pixbuf, char *folder,
char *filename_format);
void pixbuf_save_to_file(GdkPixbuf *pixbuf, char *file);
Expand Down
37 changes: 37 additions & 0 deletions src/application.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include <gdk/gdk.h>
#include <glib-2.0/glib.h>
#include <glib/gi18n-lib.h>
#include <glib/gstdio.h>
#include <gtk/gtk.h>
#include <inttypes.h>
Expand Down Expand Up @@ -377,6 +378,39 @@ void save_clicked_handler(GtkWidget *widget, struct swappy_state *state) {
save_state_to_file_or_folder(state, NULL);
}

void save_as_clicked_handler(GtkWidget *widget, struct swappy_state *state) {
gchar *filename_suggestion;
GtkWidget *dialog;
GtkFileChooser *chooser;
GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_SAVE;
gint res;

commit_state(state);

dialog = gtk_file_chooser_dialog_new(NULL, state->ui->window, action,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("_Save"), GTK_RESPONSE_ACCEPT, NULL);
chooser = GTK_FILE_CHOOSER(dialog);
gtk_file_chooser_set_do_overwrite_confirmation(chooser, TRUE);
gtk_file_chooser_set_current_folder(chooser, state->config->save_dir);
filename_suggestion = format_filename(state->config->save_filename_format);
if (filename_suggestion != NULL) {
gtk_file_chooser_set_current_name(chooser, filename_suggestion);
g_free(filename_suggestion);
}

res = gtk_dialog_run(GTK_DIALOG(dialog));
if (res == GTK_RESPONSE_ACCEPT) {
gchar *filename;

filename = gtk_file_chooser_get_filename(chooser);
save_state_to_file_or_folder(state, filename);
g_free(filename);
}

gtk_widget_destroy(dialog);
}

void clear_clicked_handler(GtkWidget *widget, struct swappy_state *state) {
action_clear(state);
}
Expand Down Expand Up @@ -442,6 +476,9 @@ void window_keypress_handler(GtkWidget *widget, GdkEventKey *event,
case GDK_KEY_s:
save_state_to_file_or_folder(state, NULL);
break;
case GDK_KEY_S:
save_as_clicked_handler(NULL, state);
break;
case GDK_KEY_b:
action_toggle_painting_panel(state, NULL);
break;
Expand Down
10 changes: 10 additions & 0 deletions src/main.c
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
#define _POSIX_C_SOURCE 200809L

#include <libintl.h>
#include <locale.h>

#include "application.h"
#include "config.h"

int main(int argc, char *argv[]) {
struct swappy_state state = {0};
int status;

// set locales according to environment variables
setlocale(LC_ALL, "");
// set base directory for translated messages
bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
// explicitly set encoding of message translations to UTF-8
bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");

state.argc = argc;
state.argv = argv;
state.mode = SWAPPY_PAINT_MODE_BRUSH;
Expand Down
43 changes: 32 additions & 11 deletions src/pixbuf.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,26 +22,47 @@ static void write_file(GdkPixbuf *pixbuf, char *path) {
}
}

void pixbuf_save_state_to_folder(GdkPixbuf *pixbuf, char *folder,
char *filename_format) {
char *format_filename(char *filename_format) {
time_t current_time = time(NULL);
char *c_time_string;
char filename[255];
char path[MAX_PATH];
size_t bytes_formated;
size_t bytes_formatted;

bytes_formatted = strftime(filename, sizeof(filename), filename_format,
localtime(&current_time));

c_time_string = ctime(&current_time);
c_time_string[strlen(c_time_string) - 1] = '\0';
bytes_formated = strftime(filename, sizeof(filename), filename_format,
localtime(&current_time));
if (!bytes_formated) {
/* A return value of 0 does not necessarily indicate an error in strftime.
* An empty format string yields an empty string but as this is our file name,
* there should be at least one character.
*/
if (!bytes_formatted) {
g_warning(
"filename_format: %s overflows filename limit - file cannot be saved",
filename_format);
return NULL;
}

return g_strdup(filename);
}

void pixbuf_save_state_to_folder(GdkPixbuf *pixbuf, char *folder,
char *filename_format) {
char path[MAX_PATH];
char *filename;
int rc;
filename = format_filename(filename_format);
if (filename == NULL) return;

rc = g_snprintf(path, MAX_PATH, "%s/%s", folder, filename);
g_free(filename);
/* valid range of rc is 1 byte to (MAX_PATH-1) */
if (rc < 0) {
g_warning("error while building output file path: %s", g_strerror(errno));
return;
} else if (rc >= MAX_PATH) {
g_warning("not writing file because output file path was truncated");
return;
}

g_snprintf(path, MAX_PATH, "%s/%s", folder, filename);
g_info("saving surface to path: %s", path);
write_file(pixbuf, path);
}
Expand Down
1 change: 1 addition & 0 deletions src/po/POTFILES
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
res/swappy.glade
src/application.c
10 changes: 9 additions & 1 deletion src/po/de.po
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: swappy\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-11-06 23:00+0100\n"
"POT-Creation-Date: 2025-11-09 08:10+0100\n"
"PO-Revision-Date: 2020-11-19 18:03+0300\n"
"Last-Translator: Brodi <me@brodi.ml>\n"
"Language-Team: none\n"
Expand Down Expand Up @@ -68,3 +68,11 @@ msgstr "Fläche kopieren"
#: res/swappy.glade:871
msgid "Save Surface"
msgstr "Fläche speichern"

#: src/application.c:391
msgid "_Cancel"
msgstr "Abbrechen"

#: src/application.c:392
msgid "_Save"
msgstr "Speichern"
10 changes: 9 additions & 1 deletion src/po/en.po
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: swappy\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-11-06 23:00+0100\n"
"POT-Creation-Date: 2025-11-09 08:10+0100\n"
"PO-Revision-Date: 2020-06-21 21:57-0400\n"
"Last-Translator: Automatically generated\n"
"Language-Team: none\n"
Expand Down Expand Up @@ -68,3 +68,11 @@ msgstr "Copy Surface"
#: res/swappy.glade:871
msgid "Save Surface"
msgstr "Save Surface"

#: src/application.c:391
msgid "_Cancel"
msgstr "Cancel"

#: src/application.c:392
msgid "_Save"
msgstr "Save"
10 changes: 9 additions & 1 deletion src/po/fr.po
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: swappy\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-11-06 23:00+0100\n"
"POT-Creation-Date: 2025-11-09 08:10+0100\n"
"PO-Revision-Date: 2021-02-20 21:00-0500\n"
"Last-Translator: Jeremy Attali <contact@jtheoof.me>\n"
"Language-Team: none\n"
Expand Down Expand Up @@ -68,3 +68,11 @@ msgstr "Copier la surface"
#: res/swappy.glade:871
msgid "Save Surface"
msgstr "Sauvegarder la surface"

#: src/application.c:391
msgid "_Cancel"
msgstr ""

#: src/application.c:392
msgid "_Save"
msgstr ""
9 changes: 8 additions & 1 deletion src/po/meson.build
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
i18n = import('i18n')

conf = configuration_data()
# define GETTEXT_PACKAGE
add_project_arguments('-DGETTEXT_PACKAGE="swappy"', language:'c')
conf.set_quoted('GETTEXT_PACKAGE', meson.project_name())
conf.set_quoted('LOCALEDIR', join_paths(get_option('prefix'), get_option('localedir')))

config_h = configure_file(
output : 'generated_config.h',
configuration : conf)
add_project_arguments('-include', 'src/po/generated_config.h', language : 'c')

i18n.gettext(meson.project_name(),
args: '--directory=' + meson.source_root()
Expand Down
10 changes: 9 additions & 1 deletion src/po/pt_BR.po
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: swappy\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-11-06 23:00+0100\n"
"POT-Creation-Date: 2025-11-09 08:10+0100\n"
"PO-Revision-Date: 2021-02-14 20:38-0300\n"
"Last-Translator: Gustavo Costa <xfgusta@gmail.com>\n"
"Language-Team: \n"
Expand Down Expand Up @@ -69,3 +69,11 @@ msgstr "Copiar superfície"
#: res/swappy.glade:871
msgid "Save Surface"
msgstr "Salvar superfície"

#: src/application.c:391
msgid "_Cancel"
msgstr ""

#: src/application.c:392
msgid "_Save"
msgstr ""
10 changes: 9 additions & 1 deletion src/po/swappy.pot
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: swappy\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-11-06 23:00+0100\n"
"POT-Creation-Date: 2025-11-09 08:10+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
Expand Down Expand Up @@ -68,3 +68,11 @@ msgstr ""
#: res/swappy.glade:871
msgid "Save Surface"
msgstr ""

#: src/application.c:391
msgid "_Cancel"
msgstr ""

#: src/application.c:392
msgid "_Save"
msgstr ""
10 changes: 9 additions & 1 deletion src/po/tr.po
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: swappy\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-11-06 23:00+0100\n"
"POT-Creation-Date: 2025-11-09 08:10+0100\n"
"PO-Revision-Date: 2022-11-25 10:36+0300\n"
"Last-Translator: Oğuz Ersen <oguz@ersen.moe>\n"
"Language-Team: Turkish <tr>\n"
Expand Down Expand Up @@ -68,3 +68,11 @@ msgstr "Yüzeyi Kopyala"
#: res/swappy.glade:871
msgid "Save Surface"
msgstr "Yüzeyi Kaydet"

#: src/application.c:391
msgid "_Cancel"
msgstr ""

#: src/application.c:392
msgid "_Save"
msgstr ""
10 changes: 9 additions & 1 deletion src/po/zh_CN.po
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: swappy\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-11-06 23:00+0100\n"
"POT-Creation-Date: 2025-11-09 08:10+0100\n"
"PO-Revision-Date: 2020-06-21 21:57-0400\n"
"Last-Translator: Automatically generated\n"
"Language-Team: none\n"
Expand Down Expand Up @@ -68,3 +68,11 @@ msgstr "复制"
#: res/swappy.glade:871
msgid "Save Surface"
msgstr "保存"

#: src/application.c:391
msgid "_Cancel"
msgstr ""

#: src/application.c:392
msgid "_Save"
msgstr ""
1 change: 1 addition & 0 deletions swappy.1.scd
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ formats are: standard name (one of: https://github.com/rgb-x/system/blob/master/
- *Ctrl+z*: Undo
- *Ctrl+Shift+z* or *Ctrl+y*: Redo
- *Ctrl+s*: Save to file (see man page)
- *Ctrl+Shift+s*: Open "Save As" dialog
- *Ctrl+c*: Copy to clipboard
- *Escape* or *q* or *Ctrl+w*: Quit swappy

Expand Down