From 118862db1f86a29a27b29af34fa5a62a995137a0 Mon Sep 17 00:00:00 2001 From: rolandlo Date: Wed, 24 Feb 2021 14:46:25 +0100 Subject: [PATCH] Make renaming work across partitions --- plugins/QuickScreenshot/main.lua | 18 +++++++------ src/plugin/luapi_application.h | 46 +++++++++++++++++++++++++++++--- 2 files changed, 53 insertions(+), 11 deletions(-) diff --git a/plugins/QuickScreenshot/main.lua b/plugins/QuickScreenshot/main.lua index 6169ea83..d3da544e 100644 --- a/plugins/QuickScreenshot/main.lua +++ b/plugins/QuickScreenshot/main.lua @@ -51,11 +51,10 @@ end -- This is the callback that gets executed when the user -- activates the plugin via the menu or hotkey. -- --- This function calls 'app.saveAs' to create --- a "Save As" dialog for the user to choose the --- filename where the image should reside. Then --- it executes a screenshot utility to capture the --- region the user selects. +-- This function executes a screenshot utility to capture +-- the region the user selects. Then, it calls 'app.saveAs' +-- to create a "Save As" dialog for the user to choose the +-- filename where the image should reside. function go() local windowsUtilities = {} -- list of windows programs here local macUtilities = {} -- list of macOS programs here @@ -82,19 +81,22 @@ function go() for i,command in ipairs(elseUtilities) do utilityName = command:match("%S+") if existsUtility(utilityName) then - local tmpFilename = os.tmpname() + local tmpFilename = os.tmpname() .. ".png" + -- The file extension is added in order to avoid the giblib error: no image grabbed + -- see https://stackoverflow.com/questions/26326664/scrot-giblib-error-saving-to-file-failed local runCommand = assert(io.popen(command .. tmpFilename .. " &")) runCommand:read('*all') runCommand:close() -- Launch the "Save As" dialog - local filename = app.saveAs() + local filename = app.saveAs("Untitled.png") if not filename then os.remove(tmpFilename) return end - os.rename(tmpFilename, filename) + local res, msg = app.glib_rename(tmpFilename, filename) + if not res then print(msg) end foundUtility = true break end diff --git a/src/plugin/luapi_application.h b/src/plugin/luapi_application.h index 2e424043..ba519415 100644 --- a/src/plugin/luapi_application.h +++ b/src/plugin/luapi_application.h @@ -12,6 +12,8 @@ #include #include +#include + #include "control/Control.h" #include "control/PageBackgroundChangeController.h" #include "control/Tool.h" @@ -25,24 +27,61 @@ #include "XojMsgBox.h" using std::map; +/** + * Renames file 'from' to file 'to' in the file system. + * Overwrites 'to' if it already exists. + * + * Example: + * assert(app.glib_rename("path/to/foo", "other/bar")) + * + * Preferred to os.rename() because it works across + * partitions. Uses glib's rename function. + * + * Returns 1 on success, and (nil, message) on failure. + */ +static int applib_glib_rename(lua_State* L) { + GError* err = nullptr; + GFile* to = g_file_new_for_path(lua_tostring(L, -1)); + GFile* from = g_file_new_for_path(lua_tostring(L, -2)); + + g_file_move(from, to, G_FILE_COPY_OVERWRITE, nullptr, nullptr, nullptr, &err); + g_object_unref(from); + g_object_unref(to); + if (err) { + lua_pushnil(L); + lua_pushfstring(L, "%s (error code: %d)", err->message, err->code); + g_error_free(err); + return 2; + } else { + lua_pushinteger(L, 1); + return 1; + } +} + + /** * Create a 'Save As' native dialog and return as a string * the filepath of the location the user chose to save. * - * Example: local filename = app.saveAs() + * Examples: + * local filename = app.saveAs() -- defaults to suggestion "Untitled" + * local filename = app.saveAs("foo") -- suggests "foo" as filename */ static int applib_saveAs(lua_State* L) { GtkFileChooserNative* native; gint res; int args_returned = 0; // change to 1 if user chooses file + const char* filename = luaL_checkstring(L, -1); + // Create a 'Save As' native dialog native = gtk_file_chooser_native_new(_("Save file"), nullptr, GTK_FILE_CHOOSER_ACTION_SAVE, nullptr, nullptr); // If user tries to overwrite a file, ask if it's OK gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(native), TRUE); - // Offer a suggestion for the filename - gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(native), (std::string{_("Untitled")} += ".png").c_str()); + // Offer a suggestion for the filename if filename absent + gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(native), + filename ? filename : (std::string{_("Untitled")}).c_str()); // Wait until user responds to dialog res = gtk_native_dialog_run(GTK_NATIVE_DIALOG(native)); @@ -836,6 +875,7 @@ static int applib_getDisplayDpi(lua_State* L) { * See above for example usage of each function. */ static const luaL_Reg applib[] = {{"msgbox", applib_msgbox}, + {"glib_rename", applib_glib_rename}, {"saveAs", applib_saveAs}, {"registerUi", applib_registerUi}, {"uiAction", applib_uiAction},