310 lines
7.5 KiB
C
310 lines
7.5 KiB
C
/* $Id$ */
|
|
/* Copyright (c) 2008-2015 Pierre Pronchery <khorben@defora.org> */
|
|
/* This file is part of DeforaOS Desktop Browser */
|
|
/* 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, version 3 of the License.
|
|
*
|
|
* 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 General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
#include <libintl.h>
|
|
|
|
|
|
/* macros */
|
|
#ifndef _
|
|
# define _(string) gettext(string)
|
|
#endif
|
|
#define min(a, b) ((a) < (b)) ? (a) : (b)
|
|
|
|
|
|
/* prototypes */
|
|
#ifdef COMMON_CONFIG_FILENAME
|
|
static String * _common_config_filename(String const * name);
|
|
#endif
|
|
|
|
#ifdef COMMON_DND
|
|
static int _common_drag_data_received(GdkDragContext * context,
|
|
GtkSelectionData * seldata, char const * dest);
|
|
#endif
|
|
|
|
#ifdef COMMON_EXEC
|
|
static int _common_exec(char const * program, char const * flags, GList * args);
|
|
#endif
|
|
|
|
#ifdef COMMON_GET_ABSOLUTE_PATH
|
|
static char * _common_get_absolute_path(char const * path);
|
|
#endif
|
|
|
|
#ifdef COMMON_SIZE
|
|
static char const * _common_size(off_t size);
|
|
#endif
|
|
|
|
#ifdef COMMON_SYMLINK
|
|
static int _common_symlink(GtkWidget * window, char const * cur);
|
|
#endif
|
|
|
|
|
|
/* functions */
|
|
#ifdef COMMON_CONFIG_FILENAME
|
|
static String * _common_config_filename(String const * name)
|
|
{
|
|
char const * homedir;
|
|
|
|
if((homedir = getenv("HOME")) == NULL)
|
|
homedir = g_get_home_dir();
|
|
return string_new_append(homedir, "/", name, NULL);
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef COMMON_DND
|
|
/* common_drag_data_received */
|
|
static int _common_drag_data_received(GdkDragContext * context,
|
|
GtkSelectionData * seldata, char const * dest)
|
|
{
|
|
int ret = 0;
|
|
size_t len;
|
|
size_t i;
|
|
GList * selection = NULL;
|
|
char * p;
|
|
GdkDragAction action;
|
|
#ifdef DEBUG
|
|
GList * s;
|
|
#endif
|
|
|
|
#if GTK_CHECK_VERSION(2, 14, 0)
|
|
if(gtk_selection_data_get_length(seldata) <= 0
|
|
|| gtk_selection_data_get_data(seldata) == NULL)
|
|
return 0;
|
|
len = gtk_selection_data_get_length(seldata);
|
|
#else
|
|
if(seldata->length <= 0 || seldata->data == NULL)
|
|
return 0;
|
|
len = seldata->length;
|
|
#endif
|
|
for(i = 0; i < len; i += strlen(p) + 1)
|
|
{
|
|
#if GTK_CHECK_VERSION(2, 14, 0)
|
|
p = (char *)gtk_selection_data_get_data(seldata);
|
|
p = &p[i];
|
|
#else
|
|
p = (char *)&seldata->data[i];
|
|
#endif
|
|
selection = g_list_append(selection, p);
|
|
}
|
|
#if GTK_CHECK_VERSION(2, 22, 0)
|
|
action = gdk_drag_context_get_suggested_action(context);
|
|
#else
|
|
action = context->suggested_action;
|
|
#endif
|
|
#ifdef DEBUG
|
|
fprintf(stderr, "%s%s%s%s%s", "DEBUG: ", action == GDK_ACTION_COPY
|
|
? _("copying") : _("moving"), _(" to \""), dest,
|
|
"\":\n");
|
|
for(s = selection; s != NULL; s = s->next)
|
|
fprintf(stderr, "DEBUG: \"%s\"\n", (char const *)s->data);
|
|
#else
|
|
selection = g_list_append(selection, (char *)dest); /* XXX */
|
|
if(action == GDK_ACTION_COPY)
|
|
ret = _common_exec("copy", "-iR", selection);
|
|
else if(action == GDK_ACTION_MOVE)
|
|
ret = _common_exec("move", "-i", selection);
|
|
#endif
|
|
g_list_free(selection);
|
|
return ret;
|
|
}
|
|
#endif /* COMMON_DND */
|
|
|
|
|
|
#ifdef COMMON_EXEC
|
|
/* common_exec */
|
|
static int _common_exec(char const * program, char const * flags, GList * args)
|
|
{
|
|
int ret = 0;
|
|
unsigned long i = (flags != NULL) ? 3 : 2;
|
|
char ** argv = NULL;
|
|
GList * a;
|
|
char ** p;
|
|
GError * error = NULL;
|
|
|
|
if(args == NULL)
|
|
return 0;
|
|
for(a = args; a != NULL; a = a->next)
|
|
{
|
|
if(a->data == NULL)
|
|
continue;
|
|
if((p = realloc(argv, sizeof(*argv) * (i + 2))) == NULL)
|
|
break;
|
|
argv = p;
|
|
argv[i++] = a->data;
|
|
}
|
|
if(a != NULL)
|
|
{
|
|
free(argv);
|
|
return -error_set_code(1, "%s: %s", program, strerror(errno));
|
|
}
|
|
if(argv == NULL)
|
|
return 0;
|
|
#ifdef DEBUG
|
|
argv[0] = strdup("echo");
|
|
#else
|
|
argv[0] = strdup(program);
|
|
#endif
|
|
if(argv[0] == NULL)
|
|
{
|
|
free(argv);
|
|
return -error_set_code(1, "%s: %s", program, strerror(errno));
|
|
}
|
|
argv[i] = NULL;
|
|
i = 0;
|
|
if(flags != NULL)
|
|
argv[++i] = strdup(flags); /* XXX may fail too */
|
|
argv[i + 1] = "--";
|
|
if(g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL,
|
|
NULL, &error) != TRUE)
|
|
{
|
|
ret = error_set_code(1, "%s", error->message);
|
|
g_error_free(error);
|
|
}
|
|
free(argv[0]);
|
|
if(flags != NULL)
|
|
free(argv[i]);
|
|
return ret;
|
|
}
|
|
#endif /* COMMON_EXEC */
|
|
|
|
|
|
#ifdef COMMON_GET_ABSOLUTE_PATH
|
|
/* common_get_absolute_path */
|
|
static char * _common_get_absolute_path(char const * path)
|
|
{
|
|
char * p;
|
|
char * cur;
|
|
size_t i;
|
|
|
|
if(path == NULL)
|
|
return NULL;
|
|
if(g_path_is_absolute(path))
|
|
{
|
|
if((p = strdup(path)) == NULL)
|
|
return NULL;
|
|
}
|
|
else
|
|
{
|
|
cur = g_get_current_dir();
|
|
p = g_build_filename(cur, path, NULL);
|
|
g_free(cur);
|
|
}
|
|
/* replace "/./" by "/" */
|
|
for(i = strlen(p); (cur = strstr(p, "/./")) != NULL; i = strlen(p))
|
|
memmove(cur, &cur[2], (p + i) - (cur + 1));
|
|
/* replace "//" by "/" */
|
|
for(i = strlen(p); (cur = strstr(p, "//")) != NULL; i = strlen(p))
|
|
memmove(cur, &cur[1], (p + i) - (cur));
|
|
/* remove single dots at the end of the address */
|
|
i = strlen(p);
|
|
if(i >= 2 && strcmp(&p[i - 2], "/.") == 0)
|
|
p[i - 1] = '\0';
|
|
/* trim slashes in the end if relevant */
|
|
if(string_compare(p, "/") != 0)
|
|
string_rtrim(p, "/");
|
|
#ifdef DEBUG
|
|
fprintf(stderr, "DEBUG: %s(\"%s\") => \"%s\"\n", __func__, path, p);
|
|
#endif
|
|
return p;
|
|
}
|
|
#endif /* COMMON_GET_ABSOLUTE_PATH */
|
|
|
|
|
|
#ifdef COMMON_SIZE
|
|
/* common_size */
|
|
static char const * _common_size(off_t size)
|
|
{
|
|
static char buf[16];
|
|
double sz = size;
|
|
char * unit;
|
|
|
|
if(sz < 1024)
|
|
{
|
|
snprintf(buf, sizeof(buf), "%.0f %s", sz, _("bytes"));
|
|
return buf;
|
|
}
|
|
else if((sz /= 1024) < 1024)
|
|
unit = N_("kB");
|
|
else if((sz /= 1024) < 1024)
|
|
unit = N_("MB");
|
|
else if((sz /= 1024) < 1024)
|
|
unit = N_("GB");
|
|
else
|
|
{
|
|
sz /= 1024;
|
|
unit = N_("TB");
|
|
}
|
|
snprintf(buf, sizeof(buf), "%.1f %s", sz, _(unit));
|
|
return buf;
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef COMMON_SYMLINK
|
|
/* common_symlink */
|
|
static int _common_symlink(GtkWidget * window, char const * cur)
|
|
{
|
|
static char const * newsymlink = NULL;
|
|
int ret = 0;
|
|
size_t len;
|
|
char * path;
|
|
GtkWidget * dialog;
|
|
GtkWidget * hbox;
|
|
GtkWidget * widget;
|
|
char const * to = NULL;
|
|
|
|
if(newsymlink == NULL)
|
|
newsymlink = _("New symbolic link");
|
|
len = strlen(cur) + strlen(newsymlink) + 2;
|
|
if((path = malloc(len)) == NULL)
|
|
return 1;
|
|
snprintf(path, len, "%s/%s", cur, newsymlink);
|
|
dialog = gtk_dialog_new_with_buttons(newsymlink,
|
|
(window != NULL) ? GTK_WINDOW(window) : NULL,
|
|
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
|
|
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
|
GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
|
|
if(window == NULL)
|
|
gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
|
|
#if GTK_CHECK_VERSION(3, 0, 0)
|
|
hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
|
|
#else
|
|
hbox = gtk_hbox_new(FALSE, 0);
|
|
#endif
|
|
widget = gtk_label_new(_("Destination:"));
|
|
gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, TRUE, 4);
|
|
widget = gtk_entry_new();
|
|
gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 4);
|
|
gtk_widget_show_all(hbox);
|
|
#if GTK_CHECK_VERSION(2, 14, 0)
|
|
gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(
|
|
dialog))), hbox, TRUE, TRUE, 4);
|
|
#else
|
|
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox, TRUE, TRUE,
|
|
4);
|
|
#endif
|
|
if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
|
|
to = gtk_entry_get_text(GTK_ENTRY(widget));
|
|
if(to != NULL && strlen(to) > 0 && symlink(to, path) != 0)
|
|
ret = 1;
|
|
gtk_widget_destroy(dialog);
|
|
free(path);
|
|
return ret;
|
|
}
|
|
#endif /* COMMON_SYMLINK */
|