/*
* xfdesktop - xfce4 ' s desktop manager
*
* Copyright ( c ) 2006 , 2024 Brian Tarricone , < brian @ tarricone . org >
* Copyright ( c ) 2010 - 2011 Jannis Pohlmann , < jannis @ xfce . org >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU Library General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software Foundation ,
* Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 , USA
*/
#include "libxfce4windowing/libxfce4windowing.h"
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
#ifdef HAVE_PWD_H
#include <pwd.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_TIME_H
#include <time.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <gio/gio.h>
#include <gio/gunixinputstream.h>
#include <gio/gunixmounts.h>
#include <glib.h>
#include <gtk/gtk.h>
#include <libxfce4ui/libxfce4ui.h>
#include <exo/exo.h>
#ifdef HAVE_THUNARX
#include <thunarx/thunarx.h>
#endif
#include "xfdesktop-common.h"
#include "xfdesktop-file-icon.h"
#include "xfdesktop-file-manager-fdo-proxy.h"
#include "xfdesktop-file-manager-proxy.h"
#include "xfdesktop-file-utils.h"
#include "xfdesktop-trash-proxy.h"
#include "xfdesktop-thunar-proxy.h"
typedef struct {
GtkWindow *parent;
GFile *file;
} ExecuteData;
typedef struct {
GFile *dest_file;
GtkWindow *parent;
} TemplateCreateData;
typedef struct {
GCancellable *cancellable;
GString *output_string;
gchar buffer[256 ];
CreateDesktopFileCallback callback;
gpointer callback_data;
} CreateDesktopFileData;
static XfdesktopTrash *xfdesktop_file_utils_peek_trash_proxy(void );
static XfdesktopFileManager *xfdesktop_file_utils_peek_filemanager_proxy(void );
static XfdesktopFileManager1 *xfdesktop_file_utils_peek_filemanager_fdo_proxy(void );
static void xfdesktop_file_utils_trash_proxy_new_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data);
static void xfdesktop_file_utils_file_manager_proxy_new_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data);
static void xfdesktop_file_utils_file_manager_fdo_proxy_new_cb(GObject *source_object,
GAsyncResult *res,
gpointer user_data);
#ifdef HAVE_THUNARX
static void xfdesktop_file_utils_thunar_proxy_new_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data);
static XfdesktopThunar *xfdesktop_file_utils_peek_thunar_proxy(void );
#else
static gpointer xfdesktop_file_utils_peek_thunar_proxy(void );
#endif
gboolean
xfdesktop_file_utils_is_desktop_file(GFileInfo *info)
{
const gchar *content_type;
gboolean is_desktop_file = FALSE ;
content_type = g_file_info_get_content_type(info);
if (content_type)
is_desktop_file = g_content_type_equals(content_type, "application/x-desktop" );
return is_desktop_file
&& !g_str_has_suffix(g_file_info_get_name(info), ".directory" );
}
gboolean
xfdesktop_file_utils_file_is_executable(GFileInfo *info)
{
const gchar *content_type;
gboolean can_execute = FALSE ;
g_return_val_if_fail(G_IS_FILE_INFO(info), FALSE );
if (g_file_info_get_attribute_boolean(info, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE)) {
/* get the content type of the file */
content_type = g_file_info_get_content_type(info);
if (content_type != NULL) {
#ifdef G_OS_WIN32
/* check for .exe, .bar or .com */
can_execute = g_content_type_can_be_executable(content_type);
#else
/* check if the content type is save to execute, we don't use
* g_content_type_can_be_executable ( ) for unix because it also returns
* true for "text/plain" and we don't want that */
if (g_content_type_is_a(content_type, "application/x-executable" )
|| g_content_type_is_a(content_type, "application/x-shellscript" ))
{
can_execute = TRUE ;
}
#endif
}
}
return can_execute || xfdesktop_file_utils_is_desktop_file(info);
}
gchar *
xfdesktop_file_utils_format_time_for_display(guint64 file_time)
{
const gchar *date_format;
struct tm *tfile;
time_t ftime;
GDate dfile;
GDate dnow;
gchar buffer[128 ];
gint diff;
/* check if the file_time is valid */
if (file_time != 0 ) {
ftime = (time_t) file_time;
/* determine the local file time */
tfile = localtime(&ftime);
/* setup the dates for the time values */
g_date_set_time_t(&dfile, (time_t) ftime);
g_date_set_time_t(&dnow, time(NULL));
/* determine the difference in days */
diff = g_date_get_julian(&dnow) - g_date_get_julian(&dfile);
if (diff == 0 ) {
/* TRANSLATORS: file was modified less than one day ago */
strftime(buffer, 128 , _("Today at %X" ), tfile);
return g_strdup(buffer);
} else if (diff == 1 ) {
/* TRANSLATORS: file was modified less than two days ago */
strftime(buffer, 128 , _("Yesterday at %X" ), tfile);
return g_strdup(buffer);
} else {
if (diff > 1 && diff < 7 ) {
/* Days from last week */
date_format = _("%A at %X" );
} else {
/* Any other date */
date_format = _("%x at %X" );
}
/* format the date string accordingly */
strftime(buffer, 128 , date_format, tfile);
return g_strdup(buffer);
}
}
/* the file_time is invalid */
return g_strdup(_("Unknown" ));
}
GKeyFile *
xfdesktop_file_utils_query_key_file(GFile *file,
GCancellable *cancellable,
GError **error)
{
GKeyFile *key_file;
gchar *contents = NULL;
gsize length;
g_return_val_if_fail(G_IS_FILE(file), NULL);
g_return_val_if_fail(cancellable == NULL || G_IS_CANCELLABLE(cancellable), NULL);
g_return_val_if_fail(error == NULL || *error == NULL, NULL);
/* try to load the entire file into memory */
if (!g_file_load_contents(file, cancellable, &contents, &length, NULL, error))
return NULL;
/* allocate a new key file */
key_file = g_key_file_new();
/* try to parse the key file from the contents of the file */
if (length == 0
|| g_key_file_load_from_data(key_file, contents, length,
G_KEY_FILE_KEEP_COMMENTS
| G_KEY_FILE_KEEP_TRANSLATIONS,
error))
{
g_free(contents);
return key_file;
}
else
{
g_free(contents);
g_key_file_free(key_file);
return NULL;
}
}
gchar *
xfdesktop_file_utils_get_display_name(GFile *file,
GFileInfo *info)
{
GKeyFile *key_file;
gchar *display_name = NULL;
g_return_val_if_fail(G_IS_FILE_INFO(info), NULL);
/* check if we have a desktop entry */
if (xfdesktop_file_utils_is_desktop_file(info)) {
/* try to load its data into a GKeyFile */
key_file = xfdesktop_file_utils_query_key_file(file, NULL, NULL);
if (key_file) {
/* try to parse the display name */
display_name = g_key_file_get_locale_string(key_file,
G_KEY_FILE_DESKTOP_GROUP,
G_KEY_FILE_DESKTOP_KEY_NAME,
NULL,
NULL);
/* free the key file */
g_key_file_free (key_file);
}
}
/* use the default display name as a fallback */
if (!display_name
|| *display_name == '\0'
|| !g_utf8_validate(display_name, -1 , NULL))
{
display_name = g_strdup(g_file_info_get_display_name(info));
}
return display_name;
}
/**
* xfdesktop_file_utils_next_new_file_name :
* @ file : the filename which will be used as the basis / default
*
* Returns a filename that is like @ filename with the possible addition of
* a number to differentiate it from other similarly named files . In other words
* it searches @ folder for incrementally named files starting from @ file_name
* and returns the first available increment .
*
* e . g . in a folder with the following files :
* - file
* - empty
* - file_copy
*
* Calling this functions with the above folder and @ filename equal to ' file ' the returned
* filename will be ' file ( copy 1 ) ' .
*
* The caller is responsible to free the returned string using g_free ( ) when no longer needed .
*
* Code extracted and adapted from on thunar_util_next_new_file_name .
*
* Return value : pointer to the new filename .
**/
GFile *
xfdesktop_file_utils_next_new_file_name(GFile *file) {
GFile *folder = g_file_get_parent(file);
gchar *filename = g_file_get_basename(file);
unsigned long file_name_size = strlen(filename);
unsigned count = 0 ;
gchar *extension = NULL;
gchar *new_name = g_strdup(filename);
extension = strrchr(filename, '.' );
if (!extension || extension == filename)
extension = "" ;
else
file_name_size -= strlen(extension);
/* loop until new_name is unique */
while (TRUE )
{
GFile *new_file = g_file_get_child(folder, new_name);
if (!g_file_query_exists(new_file, NULL)) {
g_free(new_name);
g_free(filename);
g_object_unref(folder);
return new_file;
}
g_object_unref(new_file);
g_free(new_name);
new_name = g_strdup_printf(_("%.*s %u%s" ), (int ) file_name_size, filename, ++count, extension);
}
}
GList *
xfdesktop_file_utils_file_icon_list_to_file_list(GList *icon_list)
{
GList *file_list = NULL, *l;
XfdesktopFileIcon *icon;
GFile *file;
for (l = icon_list; l; l = l->next) {
icon = XFDESKTOP_FILE_ICON(l->data);
file = xfdesktop_file_icon_peek_file(icon);
if (file)
file_list = g_list_prepend(file_list, g_object_ref(file));
}
return g_list_reverse(file_list);
}
GList *
xfdesktop_file_utils_file_list_from_string(const gchar *string)
{
GList *list = NULL;
gchar **uris;
gsize n;
uris = g_uri_list_extract_uris(string);
for (n = 0 ; uris != NULL && uris[n] != NULL; ++n)
list = g_list_append(list, g_file_new_for_uri(uris[n]));
g_strfreev (uris);
return list;
}
gchar *
xfdesktop_file_utils_file_list_to_string(GList *list)
{
GString *string;
GList *lp;
gchar *uri;
/* allocate initial string */
string = g_string_new(NULL);
for (lp = list; lp != NULL; lp = lp->next) {
uri = g_file_get_uri(lp->data);
string = g_string_append(string, uri);
g_free(uri);
string = g_string_append(string, "\r\n" );
}
return g_string_free(string, FALSE );
}
gchar **
xfdesktop_file_utils_file_list_to_uri_array(GList *file_list)
{
GList *lp;
gchar **uris = NULL;
guint list_length, n;
list_length = g_list_length(file_list);
uris = g_new0(gchar *, list_length + 1 );
for (n = 0 , lp = file_list; lp != NULL; ++n, lp = lp->next)
uris[n] = g_file_get_uri(lp->data);
uris[n] = NULL;
return uris;
}
void
xfdesktop_file_utils_file_list_free(GList *file_list)
{
g_list_free_full(file_list, g_object_unref);
}
static GdkPixbuf *xfdesktop_fallback_icon = NULL;
static gint xfdesktop_fallback_icon_size = -1 ;
static gint xfdesktop_fallback_icon_scale = -1 ;
GdkPixbuf *
xfdesktop_file_utils_get_fallback_icon(gint size,
gint scale)
{
g_return_val_if_fail(size > 0 , NULL);
if ((size != xfdesktop_fallback_icon_size || scale != xfdesktop_fallback_icon_scale) && xfdesktop_fallback_icon) {
g_object_unref(G_OBJECT(xfdesktop_fallback_icon));
xfdesktop_fallback_icon = NULL;
}
if (!xfdesktop_fallback_icon) {
xfdesktop_fallback_icon = gdk_pixbuf_new_from_file_at_size(DATADIR "/pixmaps/xfdesktop/xfdesktop-fallback-icon.png" ,
size * scale,
size * scale,
NULL);
}
if (G_UNLIKELY(!xfdesktop_fallback_icon)) {
/* this is kinda crappy, but hopefully should never happen */
xfdesktop_fallback_icon = gtk_icon_theme_load_icon_for_scale(gtk_icon_theme_get_default(),
"image-missing" ,
size,
scale,
GTK_ICON_LOOKUP_USE_BUILTIN,
NULL);
if (gdk_pixbuf_get_width(xfdesktop_fallback_icon) != size * scale
|| gdk_pixbuf_get_height(xfdesktop_fallback_icon) != size * scale)
{
GdkPixbuf *tmp = gdk_pixbuf_scale_simple(xfdesktop_fallback_icon,
size * scale, size,
GDK_INTERP_BILINEAR * scale);
g_object_unref(G_OBJECT(xfdesktop_fallback_icon));
xfdesktop_fallback_icon = tmp;
}
}
xfdesktop_fallback_icon_size = size;
xfdesktop_fallback_icon_scale = scale;
return GDK_PIXBUF(g_object_ref(G_OBJECT(xfdesktop_fallback_icon)));
}
void
xfdesktop_file_utils_set_window_cursor(GtkWindow *window,
GdkCursorType cursor_type)
{
GdkCursor *cursor;
if (!window || !gtk_widget_get_window(GTK_WIDGET(window)))
return ;
cursor = gdk_cursor_new_for_display(gtk_widget_get_display(GTK_WIDGET(window)), cursor_type);
if (G_LIKELY(cursor)) {
gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(window)), cursor);
g_object_unref(cursor);
}
}
static void
xfdesktop_file_utils_unset_window_cursor(GtkWindow *window)
{
if (window != NULL) {
GdkWindow *gdk_window = gtk_widget_get_window(GTK_WIDGET(window));
if (gdk_window != NULL) {
gdk_window_set_cursor(gdk_window, NULL);
}
}
}
static gchar *
xfdesktop_file_utils_change_working_directory (const gchar *new_directory)
{
gchar *old_directory;
g_return_val_if_fail(new_directory && *new_directory != '\0' , NULL);
/* allocate a path buffer for the old working directory */
old_directory = g_malloc0(sizeof (gchar) * MAXPATHLEN);
/* try to determine the current working directory */
#ifdef G_PLATFORM_WIN32
if (!_getcwd(old_directory, MAXPATHLEN))
#else
if (!getcwd (old_directory, MAXPATHLEN))
#endif
{
/* working directory couldn't be determined, reset the buffer */
g_free(old_directory);
old_directory = NULL;
}
/* try switching to the new working directory */
#ifdef G_PLATFORM_WIN32
if (_chdir (new_directory))
#else
if (chdir (new_directory))
#endif
{
/* switching failed, we don't need to return the old directory */
g_free(old_directory);
old_directory = NULL;
}
return old_directory;
}
gboolean
xfdesktop_file_utils_app_info_launch(GAppInfo *app_info,
GFile *working_directory,
GList *files,
GAppLaunchContext *context,
GError **error)
{
gboolean result = FALSE ;
gchar *new_path = NULL;
gchar *old_path = NULL;
g_return_val_if_fail(G_IS_APP_INFO(app_info), FALSE );
g_return_val_if_fail(working_directory == NULL || G_IS_FILE(working_directory), FALSE );
g_return_val_if_fail(files != NULL && files->data != NULL, FALSE );
g_return_val_if_fail(G_IS_APP_LAUNCH_CONTEXT(context), FALSE );
g_return_val_if_fail(error == NULL || *error == NULL, FALSE );
/* check if we want to set the working directory of the spawned app */
if (working_directory) {
/* determine the working directory path */
new_path = g_file_get_path(working_directory);
if (new_path) {
/* switch to the desired working directory, remember that
* of xfdesktop itself */
old_path = xfdesktop_file_utils_change_working_directory(new_path);
/* forget about the new working directory path */
g_free(new_path);
}
}
/* launch the paths with the specified app info */
result = g_app_info_launch(app_info, files, context, error);
/* check if we need to reset the working directory to the one xfdesktop was
* opened from */
if (old_path) {
/* switch to xfdesktop's original working directory */
new_path = xfdesktop_file_utils_change_working_directory(old_path);
/* clean up */
g_free (new_path);
g_free (old_path);
}
return result;
}
static void
report_open_folders_error(GtkWindow *parent,
GError *error)
{
xfce_message_dialog(parent,
_("Launch Error" ), "dialog-error" ,
_("The folder could not be opened" ),
error->message,
XFCE_BUTTON_TYPE_MIXED, "window-close" , _("_Close" ), GTK_RESPONSE_ACCEPT,
NULL);
}
static gboolean
xfdesktop_file_utils_open_folders_fallback(const gchar *const *uris,
GdkScreen *screen,
GtkWindow *parent,
gboolean report_errors)
{
gboolean succeeded = TRUE ;
for (gint i = 0 ; uris[i] != NULL; ++i) {
GError *error = NULL;
if (!exo_execute_preferred_application_on_screen("FileManager" ,
uris[i],
NULL,
NULL,
screen,
&error))
{
if (report_errors) {
report_open_folders_error(parent, error);
}
g_clear_error(&error);
succeeded = FALSE ;
}
}
return succeeded;
}
typedef struct {
gchar **uris;
GdkScreen *screen;
GtkWindow *parent;
} ShowFoldersFallbackData;
static void
show_folders_finished(GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
ShowFoldersFallbackData *data = user_data;
GError *error = NULL;
if (!xfdesktop_file_manager1_call_show_folders_finish(XFDESKTOP_FILE_MANAGER1(source_object), res, &error)) {
if (!xfdesktop_file_utils_open_folders_fallback((const gchar *const *)data->uris,
data->screen,
data->parent,
FALSE ))
{
report_open_folders_error(data->parent, error);
}
g_clear_error(&error);
}
g_strfreev(data->uris);
if (data->parent != NULL) {
g_object_unref(data->parent);
}
g_slice_free(ShowFoldersFallbackData, data);
}
void
xfdesktop_file_utils_open_folders(GList *files,
GdkScreen *screen,
GtkWindow *parent)
{
XfdesktopFileManager1 *fileman_fdo_proxy;
gchar **uris;
g_return_if_fail(files != NULL);
g_return_if_fail(GDK_IS_SCREEN(screen) || GTK_IS_WINDOW(parent));
if (!screen)
screen = gtk_widget_get_screen(GTK_WIDGET(parent));
uris = xfdesktop_file_utils_file_list_to_uri_array(files);
g_return_if_fail(uris != NULL && uris[0 ] != NULL);
fileman_fdo_proxy = xfdesktop_file_utils_peek_filemanager_fdo_proxy();
if (fileman_fdo_proxy != NULL) {
ShowFoldersFallbackData *data = g_slice_new0(ShowFoldersFallbackData);
gchar *startup_id = g_strdup_printf("_TIME%d" , gtk_get_current_event_time());
data->uris = uris;
data->screen = screen;
data->parent = parent != NULL ? g_object_ref(parent) : NULL;
xfdesktop_file_manager1_call_show_folders(fileman_fdo_proxy,
(const gchar *const *)uris,
startup_id,
NULL,
show_folders_finished,
data);
g_free(startup_id);
} else {
xfdesktop_file_utils_open_folders_fallback((const gchar *const *)uris,screen, parent, TRUE );
g_strfreev(uris);
}
}
static void
xfdesktop_file_utils_async_handle_error(GError *error, gpointer userdata)
{
GtkWindow *parent = GTK_WINDOW(userdata);
if (error != NULL) {
if (error->domain != G_IO_ERROR || error->code != G_IO_ERROR_TIMED_OUT) {
xfce_message_dialog(parent,
_("Error" ), "dialog-error" ,
_("The requested operation could not be completed" ),
error->message,
XFCE_BUTTON_TYPE_MIXED, "window-close" , _("_Close" ), GTK_RESPONSE_ACCEPT,
NULL);
}
g_clear_error(&error);
}
}
static void
rename_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
GError *error = NULL;
if (!xfdesktop_file_manager_call_rename_file_finish(XFDESKTOP_FILE_MANAGER(source_object), res, &error))
xfdesktop_file_utils_async_handle_error(error, user_data);
}
void
xfdesktop_file_utils_rename_file(GFile *file,
GdkScreen *screen,
GtkWindow *parent)
{
XfdesktopFileManager *fileman_proxy;
g_return_if_fail(G_IS_FILE(file));
g_return_if_fail(GDK_IS_SCREEN(screen) || GTK_IS_WINDOW(parent));
if (!screen)
screen = gtk_widget_get_screen(GTK_WIDGET(parent));
fileman_proxy = xfdesktop_file_utils_peek_filemanager_proxy();
if (fileman_proxy) {
gchar *uri = g_file_get_uri(file);
gchar *display_name = g_strdup(gdk_display_get_name(gdk_screen_get_display(screen)));
gchar *startup_id = g_strdup_printf("_TIME%d" , gtk_get_current_event_time());
xfdesktop_file_utils_set_window_cursor(parent, GDK_WATCH);
xfdesktop_file_manager_call_rename_file(fileman_proxy,
uri, display_name, startup_id,
NULL,
rename_cb,
parent);
xfdesktop_file_utils_unset_window_cursor(parent);
g_free(startup_id);
g_free(uri);
g_free(display_name);
} else {
xfce_message_dialog(parent,
_("Rename Error" ), "dialog-error" ,
_("The file could not be renamed" ),
_("This feature requires a file manager service to "
"be present (such as the one supplied by Thunar)." ),
XFCE_BUTTON_TYPE_MIXED, "window-close" , _("_Close" ), GTK_RESPONSE_ACCEPT,
NULL);
}
}
static void
bulk_rename_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
GError *error = NULL;
if (!xfdesktop_thunar_call_bulk_rename_finish(XFDESKTOP_THUNAR(source_object), res, &error))
xfdesktop_file_utils_async_handle_error(error, user_data);
}
void
xfdesktop_file_utils_bulk_rename(GFile *working_directory,
GList *files,
GdkScreen *screen,
GtkWindow *parent)
{
XfdesktopThunar *thunar_proxy;
g_return_if_fail(G_IS_FILE(working_directory));
g_return_if_fail(GDK_IS_SCREEN(screen) || GTK_IS_WINDOW(parent));
if (!screen)
screen = gtk_widget_get_screen(GTK_WIDGET(parent));
thunar_proxy = xfdesktop_file_utils_peek_thunar_proxy();
if (thunar_proxy) {
gchar *directory = g_file_get_path(working_directory);
guint nfiles = g_list_length(files);
gchar **filenames = g_new0(gchar *, nfiles+1 );
gchar *display_name = g_strdup(gdk_display_get_name(gdk_screen_get_display(screen)));
gchar *startup_id = g_strdup_printf("_TIME%d" , gtk_get_current_event_time());
GList *lp;
gint n;
/* convert GFile list into an array of filenames */
for (n = 0 , lp = files; lp != NULL; ++n, lp = lp->next)
filenames[n] = g_file_get_basename(lp->data);
filenames[n] = NULL;
xfdesktop_file_utils_set_window_cursor(parent, GDK_WATCH);
xfdesktop_thunar_call_bulk_rename(thunar_proxy,
directory, (const gchar **)filenames,
FALSE , display_name, startup_id,
NULL,
bulk_rename_cb,
parent);
xfdesktop_file_utils_unset_window_cursor(parent);
g_free(directory);
g_free(startup_id);
g_strfreev(filenames);
g_free(display_name);
} else {
xfce_message_dialog(parent,
_("Rename Error" ), "dialog-error" ,
_("The files could not be renamed" ),
_("This feature requires a file manager service to "
"be present (such as the one supplied by Thunar)." ),
XFCE_BUTTON_TYPE_MIXED, "window-close" , _("_Close" ), GTK_RESPONSE_ACCEPT,
NULL);
}
}
static void
unlink_files_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
GError *error = NULL;
if (!xfdesktop_file_manager_call_unlink_files_finish(XFDESKTOP_FILE_MANAGER(source_object), res, &error))
xfdesktop_file_utils_async_handle_error(error, user_data);
}
void
xfdesktop_file_utils_unlink_files(GList *files,
GdkScreen *screen,
GtkWindow *parent)
{
XfdesktopFileManager *fileman_proxy;
g_return_if_fail(files != NULL && G_IS_FILE(files->data));
g_return_if_fail(GDK_IS_SCREEN(screen) || GTK_IS_WINDOW(parent));
if (!screen)
screen = gtk_widget_get_screen(GTK_WIDGET(parent));
fileman_proxy = xfdesktop_file_utils_peek_filemanager_proxy();
if (fileman_proxy) {
guint nfiles = g_list_length(files);
gchar **uris = g_new0(gchar *, nfiles+1 );
gchar *display_name = g_strdup(gdk_display_get_name(gdk_screen_get_display(screen)));
gchar *startup_id = g_strdup_printf("_TIME%d" , gtk_get_current_event_time());
GList *lp;
gint n;
/* convert GFile list into an array of URIs */
for (n = 0 , lp = files; lp != NULL; ++n, lp = lp->next)
uris[n] = g_file_get_uri(lp->data);
uris[n] = NULL;
xfdesktop_file_utils_set_window_cursor(parent, GDK_WATCH);
xfdesktop_file_manager_call_unlink_files(fileman_proxy,
"" , (const gchar **)uris,
display_name, startup_id,
NULL,
unlink_files_cb,
parent);
xfdesktop_file_utils_unset_window_cursor(parent);
g_free(startup_id);
g_strfreev(uris);
g_free(display_name);
} else {
xfce_message_dialog(parent,
_("Delete Error" ), "dialog-error" ,
_("The selected files could not be deleted" ),
_("This feature requires a file manager service to "
"be present (such as the one supplied by Thunar)." ),
XFCE_BUTTON_TYPE_MIXED, "window-close" , _("_Close" ), GTK_RESPONSE_ACCEPT,
NULL);
}
}
static void
trash_files_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
GError *error = NULL;
if (!xfdesktop_trash_call_move_to_trash_finish(XFDESKTOP_TRASH(source_object), res, &error))
xfdesktop_file_utils_async_handle_error(error, user_data);
}
void
xfdesktop_file_utils_trash_files(GList *files,
GdkScreen *screen,
GtkWindow *parent)
{
XfdesktopTrash *trash_proxy;
g_return_if_fail(files != NULL && G_IS_FILE(files->data));
g_return_if_fail(GDK_IS_SCREEN(screen) || GTK_IS_WINDOW(parent));
if (!screen)
screen = gtk_widget_get_screen(GTK_WIDGET(parent));
trash_proxy = xfdesktop_file_utils_peek_trash_proxy();
if (trash_proxy) {
guint nfiles = g_list_length(files);
gchar **uris = g_new0(gchar *, nfiles+1 );
gchar *display_name = g_strdup(gdk_display_get_name(gdk_screen_get_display(screen)));
gchar *startup_id = g_strdup_printf("_TIME%d" , gtk_get_current_event_time());
GList *lp;
gint n;
/* convert GFile list into an array of URIs */
for (n = 0 , lp = files; lp != NULL; ++n, lp = lp->next)
uris[n] = g_file_get_uri(lp->data);
uris[n] = NULL;
xfdesktop_file_utils_set_window_cursor(parent, GDK_WATCH);
xfdesktop_trash_call_move_to_trash(trash_proxy,
(const gchar **)uris,
display_name, startup_id,
NULL,
trash_files_cb,
parent);
xfdesktop_file_utils_unset_window_cursor(parent);
g_free(startup_id);
g_strfreev(uris);
g_free(display_name);
} else {
xfce_message_dialog(parent,
_("Trash Error" ), "dialog-error" ,
_("The selected files could not be moved to the trash" ),
_("This feature requires a trash service to "
"be present (such as the one supplied by Thunar)." ),
XFCE_BUTTON_TYPE_MIXED, "window-close" , _("_Close" ), GTK_RESPONSE_ACCEPT,
NULL);
}
}
static void
empty_trash_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
GError *error = NULL;
if (!xfdesktop_trash_call_empty_trash_finish(XFDESKTOP_TRASH(source_object), res, &error))
xfdesktop_file_utils_async_handle_error(error, user_data);
}
void
xfdesktop_file_utils_empty_trash(GdkScreen *screen,
GtkWindow *parent)
{
XfdesktopTrash *trash_proxy;
g_return_if_fail(GDK_IS_SCREEN(screen) || GTK_IS_WINDOW(parent));
if (!screen)
screen = gtk_widget_get_screen(GTK_WIDGET(parent));
trash_proxy = xfdesktop_file_utils_peek_trash_proxy();
if (trash_proxy) {
gchar *display_name = g_strdup(gdk_display_get_name(gdk_screen_get_display(screen)));
gchar *startup_id = g_strdup_printf("_TIME%d" , gtk_get_current_event_time());
xfdesktop_file_utils_set_window_cursor(parent, GDK_WATCH);
xfdesktop_trash_call_empty_trash(trash_proxy,
display_name, startup_id,
NULL,
empty_trash_cb,
parent);
xfdesktop_file_utils_unset_window_cursor(parent);
g_free(startup_id);
g_free(display_name);
} else {
xfce_message_dialog(parent,
_("Trash Error" ), "dialog-error" ,
_("Could not empty the trash" ),
_("This feature requires a trash service to "
"be present (such as the one supplied by Thunar)." ),
XFCE_BUTTON_TYPE_MIXED, "window-close" , _("_Close" ), GTK_RESPONSE_ACCEPT,
NULL);
}
}
static void
show_template_creation_error(GtkWindow *parent, GFile *dest_file, const gchar *template_name, GError *error) {
gchar *secondary = g_strdup_printf(_("Unable to create new file \" %1 $s\" from template file \" %2 $s\": %3$s" ),
g_file_peek_path(dest_file),
template_name,
error->message);
xfce_message_dialog(parent,
_("Create File Error" ),
"dialog-error" ,
_("Could not create a new file" ),
secondary,
XFCE_BUTTON_TYPE_MIXED,
"window-close" ,
_("_Close" ),
GTK_RESPONSE_ACCEPT,
NULL);
g_free(secondary);
}
static GFile *
new_empty_file_name(GFile *folder) {
GFile *file = g_file_get_child(folder, _("New Empty File" ));
GFile *next_file = xfdesktop_file_utils_next_new_file_name(file);
g_object_unref(file);
return next_file;
}
static void
template_create_done(GObject *source, GAsyncResult *res, gpointer data) {
TemplateCreateData *tcdata = data;
GError *error = NULL;
if (!g_file_copy_finish(G_FILE(source), res, &error)) {
gchar *template_name = g_file_get_basename(G_FILE(source));
show_template_creation_error(tcdata->parent, tcdata->dest_file, template_name, error);
g_free(template_name);
g_error_free(error);
}
g_object_unref(tcdata->dest_file);
g_free(tcdata);
}
static void
empty_file_close_done(GObject *source, GAsyncResult *res, gpointer data) {
TemplateCreateData *tcdata = data;
GOutputStream *stream = G_OUTPUT_STREAM(source);
GError *error = NULL;
if (!g_output_stream_close_finish(G_OUTPUT_STREAM(source), res, &error)) {
gchar *name = g_file_get_basename(G_FILE(source));
show_template_creation_error(tcdata->parent, tcdata->dest_file, name, error);
g_free(name);
g_error_free(error);
}
g_object_unref(stream);
g_object_unref(tcdata->dest_file);
g_free(tcdata);
}
static void
empty_file_create_done(GObject *source, GAsyncResult *res, gpointer data) {
TemplateCreateData *tcdata = data;
GError *error = NULL;
GFileOutputStream *stream = g_file_create_finish(G_FILE(source), res, &error);
if (stream != NULL) {
g_output_stream_close_async(G_OUTPUT_STREAM(stream), G_PRIORITY_DEFAULT, NULL, empty_file_close_done, tcdata);
} else {
gchar *name = g_file_get_basename(G_FILE(source));
show_template_creation_error(tcdata->parent, G_FILE(source), name, error);
g_free(name);
g_error_free(error);
g_object_unref(tcdata->dest_file);
g_free(tcdata);
}
}
void
xfdesktop_file_utils_create_file_from_template(GFile *template_file, GFile *dest_file, GtkWindow *parent) {
g_return_if_fail(template_file == NULL || G_IS_FILE(template_file));
g_return_if_fail(G_IS_FILE(dest_file));
g_return_if_fail(parent == NULL || GTK_IS_WINDOW(parent));
TemplateCreateData *tcdata = g_new0(TemplateCreateData, 1 );
tcdata->parent = parent;
tcdata->dest_file = g_object_ref(dest_file);
if (template_file != NULL) {
g_file_copy_async(template_file,
tcdata->dest_file,
G_FILE_COPY_NONE,
G_PRIORITY_DEFAULT,
NULL,
NULL,
NULL,
template_create_done,
tcdata);
} else {
g_file_create_async(dest_file,
G_FILE_CREATE_NONE,
G_PRIORITY_DEFAULT,
NULL,
empty_file_create_done,
tcdata);
}
}
static void
folder_create_done(GObject *source, GAsyncResult *res, gpointer data) {
GError *error = NULL;
if (!g_file_make_directory_finish(G_FILE(source), res, &error)) {
GtkWindow *parent = data;
gchar *folder_name = g_file_get_basename(G_FILE(source));
gchar *secondary = g_strdup_printf(_("Unable to create new folder \" %1 $s\": %2$s" ),
folder_name,
error->message);
xfce_message_dialog(parent,
_("Create File Error" ),
"dialog-error" ,
_("Could not create a new folder" ),
secondary,
XFCE_BUTTON_TYPE_MIXED,
"window-close" ,
_("_Close" ),
GTK_RESPONSE_ACCEPT,
NULL);
g_free(folder_name);
g_free(secondary);
g_error_free(error);
}
g_object_unref(source);
}
void
xfdesktop_file_utils_create_folder(GFile *folder, GtkWindow *parent) {
g_file_make_directory_async(g_object_ref(folder), G_PRIORITY_DEFAULT, NULL, folder_create_done, parent);
}
static gchar *
show_editable_file_create_dialog(const gchar *title,
GIcon *icon,
const gchar *prompt,
const gchar *prefill,
GtkWindow *parent,
const gchar *error_primary_text)
{
GtkWidget *dialog = gtk_dialog_new_with_buttons(title,
parent,
GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
_("_Cancel" ),
GTK_RESPONSE_CANCEL,
_("C_reate" ),
GTK_RESPONSE_ACCEPT,
NULL);
gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT, FALSE );
gtk_window_set_default_size(GTK_WINDOW(dialog), 300 , -1 );
GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6 );
gtk_container_set_border_width(GTK_CONTAINER(hbox), 6 );
gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), hbox);
GtkWidget *image = gtk_image_new_from_gicon(icon, GTK_ICON_SIZE_DIALOG);
gtk_widget_set_margin_start(image, 6 );
gtk_widget_set_margin_end(image, 6 );
gtk_widget_set_margin_top(image, 6 );
gtk_widget_set_margin_bottom(image, 6 );
gtk_box_pack_start(GTK_BOX(hbox), image, FALSE , TRUE , 0 );
GtkWidget *vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 3 );
gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE , TRUE , 0 );
GtkWidget *label = gtk_label_new(prompt);
gtk_label_set_xalign(GTK_LABEL(label), 0 .0 );
gtk_box_pack_start(GTK_BOX(vbox), label, FALSE , FALSE , 0 );
GtkWidget *filename_input = g_object_new(XFCE_TYPE_FILENAME_INPUT,
"original-filename" , prefill,
NULL);
gtk_box_pack_start(GTK_BOX(vbox), filename_input, FALSE , FALSE , 0 );
g_signal_connect_swapped(filename_input, "text-invalid" ,
G_CALLBACK(xfce_filename_input_desensitise_widget),
gtk_dialog_get_widget_for_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT));
g_signal_connect_swapped(filename_input, "text-valid" ,
G_CALLBACK(xfce_filename_input_sensitise_widget),
gtk_dialog_get_widget_for_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT));
xfce_filename_input_check(XFCE_FILENAME_INPUT(filename_input));
GtkEntry *filename_entry = xfce_filename_input_get_entry(XFCE_FILENAME_INPUT(filename_input));
gtk_widget_show_all(hbox);
gtk_widget_grab_focus(GTK_WIDGET(filename_entry));
const gchar *ext = strrchr(prefill, '.' );
if (ext != NULL) {
glong offset = g_utf8_pointer_to_offset(prefill, ext);
if (offset >= 1 ) {
gtk_editable_select_region(GTK_EDITABLE(filename_entry), 0 , offset);
}
}
gint response = gtk_dialog_run(GTK_DIALOG(dialog));
if (response == GTK_RESPONSE_ACCEPT) {
const gchar *text = xfce_filename_input_get_text(XFCE_FILENAME_INPUT(filename_input));
gchar *filename = g_filename_from_utf8(text, -1 , NULL, NULL, NULL);
gtk_widget_destroy(dialog);
if (filename == NULL) {
gchar *secondary = g_strdup_printf(_("Cannot convert filename \" %s\" to the local encoding" ), text);
xfce_message_dialog(parent,
_("Create File Error" ),
"dialog-error" ,
error_primary_text,
secondary,
XFCE_BUTTON_TYPE_MIXED,
"window-close" ,
_("_Close" ),
GTK_RESPONSE_ACCEPT,
NULL);
g_free(secondary);
}
return filename;
} else {
gtk_widget_destroy(dialog);
return NULL;
}
}
GFile *
xfdesktop_file_utils_prompt_for_template_file_name(GFile *parent_folder, GFile *template_file, GtkWindow *parent) {
g_return_val_if_fail(G_IS_FILE(parent_folder), NULL);
g_return_val_if_fail(template_file == NULL || G_IS_FILE(template_file), NULL);
g_return_val_if_fail(parent == NULL || GTK_IS_WINDOW(parent), NULL);
GIcon *icon = NULL;
if (template_file != NULL) {
GFileInfo *info = g_file_query_info(template_file,
G_FILE_ATTRIBUTE_STANDARD_ICON,
G_FILE_QUERY_INFO_NONE,
NULL, NULL);
if (info != NULL) {
if (g_file_info_get_icon(info) != NULL) {
icon = g_object_ref(g_file_info_get_icon(info));
}
g_object_unref(info);
}
}
if (icon == NULL) {
icon = g_content_type_get_icon("text/plain" );
}
gchar *name;
if (template_file != NULL) {
name = g_file_get_basename(template_file);
GFile *new_file = g_file_get_child(parent_folder, name);
g_free(name);
GFile *next_new_file = xfdesktop_file_utils_next_new_file_name(new_file);
name = g_file_get_basename(next_new_file);
g_object_unref(new_file);
g_object_unref(next_new_file);
} else {
GFile *new_file = new_empty_file_name(parent_folder);
name = g_file_get_basename(new_file);
g_object_unref(new_file);
}
gchar *title = g_strdup_printf(_("Create Document from template \" %s\"" ), name);
gchar *filename = show_editable_file_create_dialog(title,
icon,
_("Enter the name:" ),
name,
parent,
_("Could not create a new file" ));
g_free(name);
g_free(title);
g_object_unref(icon);
if (filename != NULL) {
GFile *target_file = g_file_get_child(parent_folder, filename);
g_free(filename);
return target_file;
} else {
return NULL;
}
}
GFile *
xfdesktop_file_utils_prompt_for_new_folder_name(GFile *parent_folder, GtkWindow *parent) {
g_return_val_if_fail(G_IS_FILE(parent_folder), NULL);
g_return_val_if_fail(parent == NULL || GTK_IS_WINDOW(parent), NULL);
GIcon *icon = g_content_type_get_icon("inode/directory" );
GFile *new_folder = g_file_get_child(parent_folder, _("New Folder" ));
GFile *next_new_folder = xfdesktop_file_utils_next_new_file_name(new_folder);
gchar *prefill = g_file_get_basename(next_new_folder);
g_object_unref(new_folder);
g_object_unref(next_new_folder);
gchar *folder_name = show_editable_file_create_dialog(_("Create New Folder" ),
icon,
_("Enter the name:" ),
prefill,
parent,
_("Could not create a new folder" ));
g_object_unref(icon);
g_free(prefill);
if (folder_name != NULL) {
GFile *folder = g_file_get_child(parent_folder, folder_name);
g_free(folder_name);
return folder;
} else {
return NULL;
}
}
static void
show_properties_fdo_cb(GObject *source_object, GAsyncResult *res, gpointer user_data)
{
GError *error = NULL;
if (!xfdesktop_file_manager1_call_show_item_properties_finish(XFDESKTOP_FILE_MANAGER1(source_object), res, &error)) {
xfdesktop_file_utils_async_handle_error(error, user_data);
}
}
static void
show_properties_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
GError *error = NULL;
if (!xfdesktop_file_manager_call_display_file_properties_finish(XFDESKTOP_FILE_MANAGER(source_object), res, &error))
xfdesktop_file_utils_async_handle_error(error, user_data);
}
void
xfdesktop_file_utils_show_properties_dialog(GList *files,
GdkScreen *screen,
GtkWindow *parent)
{
XfdesktopFileManager *fileman_proxy;
XfdesktopFileManager1 *fileman_fdo_proxy;
g_return_if_fail(files != NULL);
g_return_if_fail(GDK_IS_SCREEN(screen) || GTK_IS_WINDOW(parent));
if (!screen)
screen = gtk_widget_get_screen(GTK_WIDGET(parent));
fileman_proxy = xfdesktop_file_utils_peek_filemanager_proxy();
fileman_fdo_proxy = xfdesktop_file_utils_peek_filemanager_fdo_proxy();
if ((files->next != NULL || fileman_proxy == NULL) && fileman_fdo_proxy != NULL) { // multiple files or no xfce fileman proxy
gchar **uris = g_new0(gchar *, g_list_length(files) + 1 );
gchar *startup_id = g_strdup_printf("_TIME%d" , gtk_get_current_event_time());
gint i = 0 ;
for (GList *l = files; l != NULL; l = l->next, ++i) {
uris[i] = g_file_get_uri(G_FILE(l->data));
}
xfdesktop_file_utils_set_window_cursor(parent, GDK_WATCH);
xfdesktop_file_manager1_call_show_item_properties(fileman_fdo_proxy,
(const gchar *const *)uris,
startup_id,
NULL,
show_properties_fdo_cb,
parent);
xfdesktop_file_utils_unset_window_cursor(parent);
g_strfreev(uris);
g_free(startup_id);
} else if (files->next == NULL && fileman_proxy) {
GFile *file = files->data;
gchar *uri = g_file_get_uri(file);
gchar *display_name = g_strdup(gdk_display_get_name(gdk_screen_get_display(screen)));
gchar *startup_id = g_strdup_printf("_TIME%d" , gtk_get_current_event_time());
xfdesktop_file_utils_set_window_cursor(parent, GDK_WATCH);
xfdesktop_file_manager_call_display_file_properties(fileman_proxy,
uri, display_name, startup_id,
NULL,
show_properties_cb,
parent);
xfdesktop_file_utils_unset_window_cursor(parent);
g_free(startup_id);
g_free(uri);
g_free(display_name);
} else {
xfce_message_dialog(parent,
_("File Properties Error" ), "dialog-error" ,
_("The file properties dialog could not be opened" ),
_("This feature requires a file manager service to "
"be present (such as the one supplied by Thunar)." ),
XFCE_BUTTON_TYPE_MIXED, "window-close" , _("_Close" ), GTK_RESPONSE_ACCEPT,
NULL);
}
}
static void
launch_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
GError *error = NULL;
if (!xfdesktop_file_manager_call_launch_files_finish(XFDESKTOP_FILE_MANAGER(source_object), res, &error))
xfdesktop_file_utils_async_handle_error(error, user_data);
}
void
xfdesktop_file_utils_launch(GFile *file,
GdkScreen *screen,
GtkWindow *parent)
{
XfdesktopFileManager *fileman_proxy;
g_return_if_fail(G_IS_FILE(file));
g_return_if_fail(GDK_IS_SCREEN(screen) || GTK_IS_WINDOW(parent));
if (!screen)
screen = gtk_widget_get_screen(GTK_WIDGET(parent));
fileman_proxy = xfdesktop_file_utils_peek_filemanager_proxy();
if (fileman_proxy) {
gchar **uris;
GFile *parent_file = g_file_get_parent(file);
gchar *parent_path = g_file_get_path(parent_file);
gchar *display_name = g_strdup(gdk_display_get_name(gdk_screen_get_display(screen)));
gchar *startup_id = g_strdup_printf("_TIME%d" , gtk_get_current_event_time());
xfdesktop_file_utils_set_window_cursor(parent, GDK_WATCH);
uris = g_new0(gchar *, 2 );
uris[0 ] = g_file_get_uri(file);
uris[1 ] = NULL;
xfdesktop_file_manager_call_launch_files(fileman_proxy, parent_path,
(const gchar * const *)uris,
display_name, startup_id,
NULL,
launch_cb,
parent);
xfdesktop_file_utils_unset_window_cursor(parent);
g_free(startup_id);
g_free(uris[0 ]);
g_free(uris);
g_free(parent_path);
g_object_unref(parent_file);
g_free(display_name);
} else {
xfce_message_dialog(parent,
_("Launch Error" ), "dialog-error" ,
_("The file could not be opened" ),
_("This feature requires a file manager service to "
"be present (such as the one supplied by Thunar)." ),
XFCE_BUTTON_TYPE_MIXED, "window-close" , _("_Close" ), GTK_RESPONSE_ACCEPT,
NULL);
}
}
static void
execute_finished_cb(GObject *source,
GAsyncResult *res,
gpointer user_data)
{
ExecuteData *edata = (ExecuteData *)user_data;
gboolean ret;
GError *error = NULL;
ret = xfdesktop_file_manager_call_execute_finish(XFDESKTOP_FILE_MANAGER(source), res, &error);
if (!ret) {
gchar *filename = g_file_get_uri(edata->file);
gchar *name = g_filename_display_basename(filename);
gchar *primary = g_markup_printf_escaped(_("Failed to run \" %s\"" ), name);
xfce_message_dialog(edata->parent,
_("Launch Error" ), "dialog-error" ,
primary, error->message,
XFCE_BUTTON_TYPE_MIXED, "window-close" , _("_Close" ), GTK_RESPONSE_ACCEPT,
NULL);
g_free(primary);
g_free(name);
g_free(filename);
g_error_free(error);
}
if (edata->parent != NULL) {
g_object_unref(edata->parent);
}
g_object_unref(edata->file);
g_free(edata);
}
gboolean
xfdesktop_file_utils_execute(GFile *working_directory,
GFile *file,
GList *files,
GdkScreen *screen,
GtkWindow *parent)
{
XfdesktopFileManager *fileman_proxy;
gboolean success = TRUE ;
g_return_val_if_fail(working_directory == NULL || G_IS_FILE(working_directory), FALSE );
g_return_val_if_fail(G_IS_FILE(file), FALSE );
g_return_val_if_fail(screen == NULL || GDK_IS_SCREEN(screen), FALSE );
g_return_val_if_fail(parent == NULL || GTK_IS_WINDOW(parent), FALSE );
if (!screen)
screen = gdk_display_get_default_screen(gdk_display_get_default());
fileman_proxy = xfdesktop_file_utils_peek_filemanager_proxy();
if (fileman_proxy) {
ExecuteData *edata;
gchar *working_dir = working_directory != NULL ? g_file_get_uri(working_directory) : NULL;
const gchar *path_prop;
gchar *uri = g_file_get_uri(file);
gchar *display_name = g_strdup(gdk_display_get_name(gdk_screen_get_display(screen)));
gchar *startup_id = g_strdup_printf("_TIME%d" , gtk_get_current_event_time());
GList *lp;
guint n = g_list_length (files);
gchar **uris = g_new0 (gchar *, n + 1 );
for (n = 0 , lp = files; lp != NULL; ++n, lp = lp->next)
uris[n] = g_file_get_uri(lp->data);
uris[n] = NULL;
/* If the working_dir wasn't set check if this is a .desktop file
* we can parse a working dir from */
if (working_dir == NULL) {
GFileInfo *info = g_file_query_info(file,
XFDESKTOP_FILE_INFO_NAMESPACE,
G_FILE_QUERY_INFO_NONE,
NULL, NULL);
if (xfdesktop_file_utils_is_desktop_file(info)) {
XfceRc *rc;
gchar *path = g_file_get_path(file);
if (path != NULL) {
rc = xfce_rc_simple_open(path, TRUE );
if (rc != NULL) {
path_prop = xfce_rc_read_entry(rc, "Path" , NULL);
if (xfce_str_is_empty(path_prop))
working_dir = g_strdup(g_get_user_special_dir(G_USER_DIRECTORY_DESKTOP));
else
working_dir = g_strdup(path_prop);
xfce_rc_close(rc);
}
g_free(path);
}
}
if (info)
g_object_unref(info);
}
edata = g_new0(ExecuteData, 1 );
if (parent != NULL) {
edata->parent = g_object_ref(parent);
}
edata->file = g_object_ref(file);
xfdesktop_file_manager_call_execute(fileman_proxy,
working_dir,
uri,
(const gchar **)uris,
display_name,
startup_id,
NULL,
execute_finished_cb,
edata);
g_free(startup_id);
g_strfreev(uris);
g_free(uri);
g_free(working_dir);
g_free(display_name);
} else {
gchar *filename = g_file_get_uri(file);
gchar *name = g_filename_display_basename(filename);
gchar *primary = g_markup_printf_escaped(_("Failed to run \" %s\"" ), name);
xfce_message_dialog(parent,
_("Launch Error" ), "dialog-error" ,
primary,
_("This feature requires a file manager service to "
"be present (such as the one supplied by Thunar)." ),
XFCE_BUTTON_TYPE_MIXED, "window-close" , _("_Close" ), GTK_RESPONSE_ACCEPT,
NULL);
g_free(primary);
g_free(name);
g_free(filename);
success = FALSE ;
}
return success;
}
static void
display_chooser_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
GError *error = NULL;
if (!xfdesktop_file_manager_call_display_application_chooser_dialog_finish(XFDESKTOP_FILE_MANAGER(source_object), res, &error))
xfdesktop_file_utils_async_handle_error(error, user_data);
}
void
xfdesktop_file_utils_display_app_chooser_dialog(GFile *file,
gboolean open,
gboolean preselect_default_checkbox,
GdkScreen *screen,
GtkWindow *parent)
{
XfdesktopFileManager *fileman_proxy;
g_return_if_fail(G_IS_FILE(file));
g_return_if_fail(GDK_IS_SCREEN(screen) || GTK_IS_WINDOW(parent));
if (!screen)
screen = gtk_widget_get_screen(GTK_WIDGET(parent));
fileman_proxy = xfdesktop_file_utils_peek_filemanager_proxy();
if (fileman_proxy) {
gchar *uri = g_file_get_uri(file);
gchar *display_name = g_strdup(gdk_display_get_name(gdk_screen_get_display(screen)));
gchar *startup_id = g_strdup_printf("_TIME%d" , gtk_get_current_event_time());
xfdesktop_file_utils_set_window_cursor(parent, GDK_WATCH);
xfdesktop_file_manager_call_display_application_chooser_dialog(fileman_proxy,
uri, open,
preselect_default_checkbox,
display_name,
startup_id,
NULL,
display_chooser_cb,
parent);
xfdesktop_file_utils_unset_window_cursor(parent);
g_free(startup_id);
g_free(uri);
g_free(display_name);
} else {
xfce_message_dialog(parent,
_("Launch Error" ), "dialog-error" ,
_("The application chooser could not be opened" ),
_("This feature requires a file manager service to "
"be present (such as the one supplied by Thunar)." ),
XFCE_BUTTON_TYPE_MIXED, "window-close" , _("_Close" ), GTK_RESPONSE_ACCEPT,
NULL);
}
}
/**
* ' out_source_files ' will hold a list owned by caller with contents owned by callee
* ' dest_source_files ' will hold a list and contents owned by caller
*/
void
xfdesktop_file_utils_build_transfer_file_lists(GdkDragAction action,
GList *source_icons,
XfdesktopFileIcon *dest_icon,
GList **out_source_files,
GList **out_dest_files)
{
g_return_if_fail(source_icons != NULL);
g_return_if_fail(XFDESKTOP_IS_FILE_ICON(dest_icon));
g_return_if_fail(out_source_files != NULL && out_dest_files != NULL);
switch (action) {
case GDK_ACTION_MOVE:
case GDK_ACTION_LINK:
*out_dest_files = g_list_append(NULL, g_object_ref(xfdesktop_file_icon_peek_file(dest_icon)));
for (GList *l = source_icons; l != NULL; l = l->next) {
GFile *source_file = xfdesktop_file_icon_peek_file(XFDESKTOP_FILE_ICON(l->data));
if (source_file != NULL) {
*out_source_files = g_list_prepend(*out_source_files, source_file);
}
}
*out_source_files = g_list_reverse(*out_source_files);
break ;
case GDK_ACTION_COPY:
for (GList *l = source_icons; l != NULL; l = l->next) {
GFile *source_file = xfdesktop_file_icon_peek_file(XFDESKTOP_FILE_ICON(l->data));
if (source_file != NULL) {
gchar *name = g_file_get_basename(source_file);
if (name != NULL) {
GFile *dest_file = g_file_get_child(xfdesktop_file_icon_peek_file(dest_icon), name);
*out_dest_files = g_list_prepend(*out_dest_files, dest_file);
*out_source_files = g_list_prepend(*out_source_files, source_file);
g_free(name);
}
}
}
*out_source_files = g_list_reverse(*out_source_files);
*out_dest_files = g_list_reverse(*out_dest_files);
break ;
default :
g_warning("Unsupported drag action: %d" , action);
}
}
static void
transfer_files_cb(GObject *source_object,
GAsyncResult *result,
gpointer user_data)
{
gboolean (*finish_func)(XfdesktopFileManager *, GAsyncResult *, GError **) = user_data;
GError *error = NULL;
gboolean success;
success = finish_func(XFDESKTOP_FILE_MANAGER(source_object), result, &error);
if (!success) {
gchar *message = error != NULL ? error->message : _("Unknown" );
xfce_message_dialog(NULL,
_("Transfer Error" ), "dialog-error" ,
_("The file transfer could not be performed" ),
message,
XFCE_BUTTON_TYPE_MIXED, "window-close" , _("_Close" ), GTK_RESPONSE_ACCEPT,
NULL);
g_clear_error(&error);
}
}
void
xfdesktop_file_utils_transfer_files(GdkDragAction action,
GList *source_files,
GList *target_files,
GdkScreen *screen)
{
XfdesktopFileManager *fileman_proxy;
g_return_if_fail(action == GDK_ACTION_MOVE || action == GDK_ACTION_COPY || action == GDK_ACTION_LINK);
g_return_if_fail(source_files != NULL && G_IS_FILE(source_files->data));
g_return_if_fail(target_files != NULL && G_IS_FILE(target_files->data));
g_return_if_fail(screen == NULL || GDK_IS_SCREEN(screen));
if (!screen)
screen = gdk_display_get_default_screen(gdk_display_get_default());
fileman_proxy = xfdesktop_file_utils_peek_filemanager_proxy();
if (fileman_proxy) {
gchar **source_uris = xfdesktop_file_utils_file_list_to_uri_array(source_files);
gchar **target_uris = xfdesktop_file_utils_file_list_to_uri_array(target_files);
gchar *display_name = g_strdup(gdk_display_get_name(gdk_screen_get_display(screen)));
gchar *startup_id = g_strdup_printf("_TIME%d" , gtk_get_current_event_time());
switch (action) {
case GDK_ACTION_MOVE:
xfdesktop_file_manager_call_move_into(fileman_proxy, "" ,
(const gchar **)source_uris,
(const gchar *)target_uris[0 ],
display_name, startup_id,
NULL,
transfer_files_cb, xfdesktop_file_manager_call_move_into_finish);
break ;
case GDK_ACTION_COPY:
xfdesktop_file_manager_call_copy_to(fileman_proxy, "" ,
(const gchar **)source_uris,
(const gchar **)target_uris,
display_name, startup_id,
NULL,
transfer_files_cb, xfdesktop_file_manager_call_copy_to_finish);
break ;
case GDK_ACTION_LINK:
xfdesktop_file_manager_call_link_into(fileman_proxy, "" ,
(const gchar **)source_uris,
(const gchar *)target_uris[0 ],
display_name, startup_id,
NULL,
transfer_files_cb, xfdesktop_file_manager_call_link_into_finish);
break ;
default :
g_assert_not_reached();
break ;
}
g_free(startup_id);
g_free(display_name);
g_strfreev(target_uris);
g_strfreev(source_uris);
} else {
xfce_message_dialog(NULL,
_("Transfer Error" ), "dialog-error" ,
_("The file transfer could not be performed" ),
_("This feature requires a file manager service to "
"be present (such as the one supplied by Thunar)." ),
XFCE_BUTTON_TYPE_MIXED, "window-close" , _("_Close" ), GTK_RESPONSE_ACCEPT,
NULL);
}
}
static gboolean
exo_desktop_item_edit_has_print_saved_uri_flag(void ) {
const gchar *test_argv[] = {
"exo-desktop-item-edit" ,
"--help" ,
NULL,
};
gboolean has_print_saved_filename = FALSE ;
gchar *cmd_stdout = NULL;
if (g_spawn_sync(NULL,
(gchar **)test_argv,
NULL,
G_SPAWN_SEARCH_PATH | G_SPAWN_STDERR_TO_DEV_NULL,
NULL,
NULL,
&cmd_stdout,
NULL,
NULL,
NULL)
&& cmd_stdout != NULL)
{
has_print_saved_filename = strstr(cmd_stdout, "--print-saved-uri" ) != NULL;
}
g_free(cmd_stdout);
return has_print_saved_filename;
}
static void
create_desktop_file_data_free(CreateDesktopFileData *cdfdata) {
if (cdfdata->cancellable != NULL) {
g_object_unref(cdfdata->cancellable);
}
g_string_free(cdfdata->output_string, TRUE );
g_free(cdfdata);
}
static void
create_desktop_file_stdout_data_ready(GObject *source, GAsyncResult *res, gpointer data) {
GInputStream *stdout_stream = G_INPUT_STREAM(source);
CreateDesktopFileData *cdfdata = data;
GError *error = NULL;
gssize bytes_read = g_input_stream_read_finish(stdout_stream, res, &error);
if (bytes_read < 0 ) {
g_input_stream_close(stdout_stream, NULL, NULL);
g_object_unref(stdout_stream);
cdfdata->callback(NULL, error, cdfdata->callback_data);
g_error_free(error);
create_desktop_file_data_free(cdfdata);
} else if (bytes_read == 0 ) {
g_input_stream_close(stdout_stream, NULL, NULL);
g_object_unref(stdout_stream);
while (g_str_has_suffix(cdfdata->output_string->str, "\n" )) {
g_string_truncate(cdfdata->output_string, cdfdata->output_string->len - 1 );
}
if (cdfdata->output_string->len == 0 ) {
error = g_error_new_literal(G_IO_ERROR, G_IO_ERROR_CANCELLED, "User cancelled dialog" );
cdfdata->callback(NULL, error, cdfdata->callback_data);
g_error_free(error);
} else {
GFile *file = g_file_new_for_uri(cdfdata->output_string->str);
cdfdata->callback(file, NULL, cdfdata->callback_data);
g_object_unref(file);
}
create_desktop_file_data_free(cdfdata);
} else {
g_string_append_len(cdfdata->output_string, cdfdata->buffer, bytes_read);
g_input_stream_read_async(stdout_stream,
cdfdata->buffer,
sizeof (cdfdata->buffer),
G_PRIORITY_DEFAULT,
cdfdata->cancellable,
create_desktop_file_stdout_data_ready,
cdfdata);
}
}
void
xfdesktop_file_utils_create_desktop_file(GdkScreen *screen,
GFile *folder,
const gchar *launcher_type,
const gchar *suggested_name,
const gchar *suggested_command_or_url,
GCancellable *cancellable,
CreateDesktopFileCallback callback,
gpointer callback_data)
{
g_return_if_fail(screen == NULL || GDK_IS_SCREEN(screen));
g_return_if_fail(G_IS_FILE(folder));
g_return_if_fail(g_strcmp0(launcher_type, "Application" ) == 0 || g_strcmp0(launcher_type, "Link" ) == 0 );
GStrvBuilder *argv_builder = g_strv_builder_new();
g_strv_builder_add(argv_builder, "exo-desktop-item-edit" );
if (screen != NULL && xfw_windowing_get() == XFW_WINDOWING_X11) {
const gchar *display_name = gdk_display_get_name(gdk_screen_get_display(screen));
g_strv_builder_add(argv_builder, "--display" );
g_strv_builder_add(argv_builder, display_name);
}
g_strv_builder_add(argv_builder, "--create-new" );
g_strv_builder_add(argv_builder, "--type" );
g_strv_builder_add(argv_builder, launcher_type);
if (suggested_name != NULL) {
g_strv_builder_add(argv_builder, "--name" );
g_strv_builder_add(argv_builder, suggested_name);
}
if (suggested_command_or_url != NULL) {
if (g_strcmp0(launcher_type, "Application" ) == 0 ) {
g_strv_builder_add(argv_builder, "--command" );
} else {
g_strv_builder_add(argv_builder, "--url" );
}
g_strv_builder_add(argv_builder, suggested_command_or_url);
}
gboolean used_print_saved_uri = callback != NULL && exo_desktop_item_edit_has_print_saved_uri_flag();
if (used_print_saved_uri) {
g_strv_builder_add(argv_builder, "--print-saved-uri" );
}
gchar *uri = g_file_get_uri(folder);
g_strv_builder_add(argv_builder, uri);
g_free(uri);
gchar **argv = g_strv_builder_end(argv_builder);
GError *error = NULL;
gint stdout_fd = -1 ;
if (g_spawn_async_with_pipes(NULL,
argv,
NULL,
G_SPAWN_SEARCH_PATH,
NULL,
NULL,
NULL,
NULL,
used_print_saved_uri ? &stdout_fd : NULL,
NULL,
&error))
{
if (used_print_saved_uri && stdout_fd >= 0 ) {
CreateDesktopFileData *cdfdata = g_new0(CreateDesktopFileData, 1 );
cdfdata->cancellable = cancellable != NULL ? g_object_ref(cancellable) : NULL;
cdfdata->output_string = g_string_sized_new(sizeof (cdfdata->buffer));
cdfdata->callback = callback;
cdfdata->callback_data = callback_data;
GInputStream *stdout_stream = g_unix_input_stream_new(stdout_fd, TRUE );
g_input_stream_read_async(stdout_stream,
cdfdata->buffer,
sizeof (cdfdata->buffer),
G_PRIORITY_DEFAULT,
cdfdata->cancellable,
create_desktop_file_stdout_data_ready,
cdfdata);
} else if (callback != NULL) {
error = g_error_new_literal(G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
"exo-desktop-item-edit doesn't support the --print-saved-uri option" );
callback(NULL, error, callback_data);
g_error_free(error);
}
} else {
if (callback != NULL) {
callback(NULL, error, callback_data);
}
g_error_free(error);
}
g_strfreev(argv);
g_strv_builder_unref(argv_builder);
}
static gint dbus_ref_cnt = 0 ;
static GDBusConnection *dbus_gconn = NULL;
static XfdesktopTrash *dbus_trash_proxy = NULL;
static XfdesktopFileManager *dbus_filemanager_proxy = NULL;
static XfdesktopFileManager1 *dbus_filemanager_fdo_proxy = NULL;
#ifdef HAVE_THUNARX
static XfdesktopThunar *dbus_thunar_proxy = NULL;
#else
static GDBusProxy *dbus_thunar_proxy = NULL;
#endif
gboolean
xfdesktop_file_utils_dbus_init(void )
{
gboolean ret = TRUE ;
if (dbus_ref_cnt++)
return TRUE ;
if (!dbus_gconn) {
dbus_gconn = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
}
if (dbus_gconn) {
xfdesktop_trash_proxy_new(dbus_gconn,
G_DBUS_PROXY_FLAGS_NONE,
"org.xfce.FileManager" ,
"/org/xfce/FileManager" ,
NULL,
xfdesktop_file_utils_trash_proxy_new_cb,
NULL);
xfdesktop_file_manager_proxy_new(dbus_gconn,
G_DBUS_PROXY_FLAGS_NONE,
"org.xfce.FileManager" ,
"/org/xfce/FileManager" ,
NULL,
xfdesktop_file_utils_file_manager_proxy_new_cb,
NULL);
xfdesktop_file_manager1_proxy_new(dbus_gconn,
G_DBUS_PROXY_FLAGS_NONE,
"org.freedesktop.FileManager1" ,
"/org/freedesktop/FileManager1" ,
NULL,
xfdesktop_file_utils_file_manager_fdo_proxy_new_cb,
NULL);
#ifdef HAVE_THUNARX
xfdesktop_thunar_proxy_new(dbus_gconn,
G_DBUS_PROXY_FLAGS_NONE,
"org.xfce.FileManager" ,
"/org/xfce/FileManager" ,
NULL,
xfdesktop_file_utils_thunar_proxy_new_cb,
NULL);
#else
dbus_thunar_proxy = NULL;
#endif
} else {
ret = FALSE ;
dbus_ref_cnt = 0 ;
}
return ret;
}
static XfdesktopTrash *
xfdesktop_file_utils_peek_trash_proxy(void )
{
return dbus_trash_proxy;
}
static XfdesktopFileManager *
xfdesktop_file_utils_peek_filemanager_proxy(void )
{
return dbus_filemanager_proxy;
}
static XfdesktopFileManager1 *
xfdesktop_file_utils_peek_filemanager_fdo_proxy(void )
{
return dbus_filemanager_fdo_proxy;
}
#ifdef HAVE_THUNARX
static XfdesktopThunar *
xfdesktop_file_utils_peek_thunar_proxy(void )
{
return dbus_thunar_proxy;
}
#else
static gpointer
xfdesktop_file_utils_peek_thunar_proxy(void )
{
return NULL;
}
#endif
static void
xfdesktop_file_utils_trash_proxy_new_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data) {
dbus_trash_proxy = xfdesktop_trash_proxy_new_finish (res, NULL);
}
static void
xfdesktop_file_utils_file_manager_proxy_new_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data) {
dbus_filemanager_proxy = xfdesktop_file_manager_proxy_new_finish (res, NULL);
}
static void
xfdesktop_file_utils_file_manager_fdo_proxy_new_cb(GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
dbus_filemanager_fdo_proxy = xfdesktop_file_manager1_proxy_new_finish(res, NULL);
}
#ifdef HAVE_THUNARX
static void
xfdesktop_file_utils_thunar_proxy_new_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data) {
dbus_thunar_proxy = xfdesktop_thunar_proxy_new_finish (res, NULL);
}
#endif
void
xfdesktop_file_utils_dbus_cleanup(void )
{
if (dbus_ref_cnt == 0 || --dbus_ref_cnt > 0 )
return ;
if (dbus_trash_proxy)
g_object_unref(G_OBJECT(dbus_trash_proxy));
if (dbus_filemanager_proxy)
g_object_unref(G_OBJECT(dbus_filemanager_proxy));
if (dbus_filemanager_fdo_proxy) {
g_object_unref(G_OBJECT(dbus_filemanager_fdo_proxy));
}
if (dbus_thunar_proxy)
g_object_unref(G_OBJECT(dbus_thunar_proxy));
if (dbus_gconn)
g_object_unref(G_OBJECT(dbus_gconn));
}
#ifdef HAVE_THUNARX
/* thunar extension interface stuff: ThunarxFileInfo implementation */
gchar *
xfdesktop_thunarx_file_info_get_name(ThunarxFileInfo *file_info)
{
XfdesktopFileIcon *icon = XFDESKTOP_FILE_ICON(file_info);
GFile *file = xfdesktop_file_icon_peek_file(icon);
return file ? g_file_get_basename(file) : NULL;
}
gchar *
xfdesktop_thunarx_file_info_get_uri(ThunarxFileInfo *file_info)
{
XfdesktopFileIcon *icon = XFDESKTOP_FILE_ICON(file_info);
GFile *file = xfdesktop_file_icon_peek_file(icon);
return file ? g_file_get_uri(file) : NULL;
}
gchar *
xfdesktop_thunarx_file_info_get_parent_uri(ThunarxFileInfo *file_info)
{
XfdesktopFileIcon *icon = XFDESKTOP_FILE_ICON(file_info);
GFile *file = xfdesktop_file_icon_peek_file(icon);
gchar *uri = NULL;
if (file) {
GFile *parent = g_file_get_parent(file);
if (parent) {
uri = g_file_get_uri(parent);
g_object_unref(parent);
}
}
return uri;
}
gchar *
xfdesktop_thunarx_file_info_get_uri_scheme_file(ThunarxFileInfo *file_info)
{
XfdesktopFileIcon *icon = XFDESKTOP_FILE_ICON(file_info);
GFile *file = xfdesktop_file_icon_peek_file(icon);
return file ? g_file_get_uri_scheme(file) : NULL;
}
gchar *
xfdesktop_thunarx_file_info_get_mime_type(ThunarxFileInfo *file_info)
{
XfdesktopFileIcon *icon = XFDESKTOP_FILE_ICON(file_info);
GFileInfo *info = xfdesktop_file_icon_peek_file_info(icon);
return info ? g_strdup(g_file_info_get_content_type(info)) : NULL;
}
gboolean
xfdesktop_thunarx_file_info_has_mime_type(ThunarxFileInfo *file_info,
const gchar *mime_type)
{
XfdesktopFileIcon *icon = XFDESKTOP_FILE_ICON(file_info);
GFileInfo *info = xfdesktop_file_icon_peek_file_info(icon);
const gchar *content_type;
if (!info)
return FALSE ;
content_type = g_file_info_get_content_type(info);
return g_content_type_is_a(content_type, mime_type);
}
gboolean
xfdesktop_thunarx_file_info_is_directory(ThunarxFileInfo *file_info)
{
XfdesktopFileIcon *icon = XFDESKTOP_FILE_ICON(file_info);
GFileInfo *info = xfdesktop_file_icon_peek_file_info(icon);
return (info && g_file_info_get_file_type(info) == G_FILE_TYPE_DIRECTORY);
}
GFileInfo *
xfdesktop_thunarx_file_info_get_file_info(ThunarxFileInfo *file_info)
{
XfdesktopFileIcon *icon = XFDESKTOP_FILE_ICON(file_info);
GFileInfo *info = xfdesktop_file_icon_peek_file_info(icon);
return info ? g_object_ref (info) : NULL;
}
GFileInfo *
xfdesktop_thunarx_file_info_get_filesystem_info(ThunarxFileInfo *file_info)
{
XfdesktopFileIcon *icon = XFDESKTOP_FILE_ICON(file_info);
GFileInfo *info = xfdesktop_file_icon_peek_filesystem_info(icon);
return info ? g_object_ref (info) : NULL;
}
GFile *
xfdesktop_thunarx_file_info_get_location(ThunarxFileInfo *file_info)
{
XfdesktopFileIcon *icon = XFDESKTOP_FILE_ICON(file_info);
GFile *file = xfdesktop_file_icon_peek_file(icon);
return g_object_ref (file);
}
#endif /* HAVE_THUNARX */
Messung V0.5 in Prozent C=97 H=95 G=95
¤ Dauer der Verarbeitung: 0.35 Sekunden
(vorverarbeitet am 2026-07-10)
¤
*© Formatika GbR, Deutschland