mc/gnome/olddnd.c

1795 lines
41 KiB
C

#ifdef OLD_DND
/* This was in the old gdesktop.h */
#define MC_LIB_DESKTOP "mc.desktop"
/* Drag and drop types recognized by us */
enum {
TARGET_URI_LIST,
TARGET_TEXT_PLAIN,
};
/* Types of desktop icons:
*
* o Application: Double click: start up application;
* Dropping: start up program with arguments.
*
* o Directory: Double click: opens the directory in a panel.
* Double click: copies/moves files.
*
* o File: Opens the application according to regex_command
*/
typedef enum {
application,
directory,
file
} icon_t;
/* A structure that describes each icon on the desktop */
typedef struct {
GnomeDesktopEntry *dentry;
GtkWidget *widget;
icon_t type;
int x, y;
int grid_x, grid_y;
char *pathname;
} desktop_icon_t;
/* size of the snap to grid size */
#define SNAP_X 80
#define SNAP_Y 80
/* gtrans.c */
extern int want_transparent_icons;
extern int want_transparent_text;
GtkWidget *make_transparent_window (char *file);
/* gdesktop.c */
void drop_on_directory (GtkSelectionData *sel_data, GdkDragContext *context,
GdkDragAction action, char *dest, int force_manually);
#if 0
void drop_on_directory (GdkEventDropDataAvailable *event, char *dest, int force_manually);
void artificial_drag_start (GdkWindow *source_window, int x, int y);
#endif
void gnome_arrange_icons (void);
void start_desktop (void);
void stop_desktop (void);
/* These get invoked by the context sensitive popup menu in gscreen.c */
void desktop_icon_properties (GtkWidget *widget, desktop_icon_t *di);
void desktop_icon_execute (GtkWidget *widget, desktop_icon_t *di);
void desktop_icon_delete (GtkWidget *widget, desktop_icon_t *di);
/* Pops up the context sensitive menu for a WPanel or a desktop_icon_t */
void file_popup (GdkEventButton *event, void *WPanel_pointer, void *desktop_icon_t_pointer, int row, char *filename);
#endif
#ifdef OLD_DND
/*
* Handler for text/plain and url:ALL drag types
*
* Sets the drag information to the filenames selected on the panel
*/
static void
panel_transfer_file_names (GtkWidget *widget, GdkEventDragRequest *event, WPanel *panel, int *len, char **data)
{
*data = panel_build_selected_file_list (panel, len);
}
/*
* Handler for file:ALL type (target application only understands local pathnames)
*
* Makes local copies of the files and transfers the filenames.
*/
static void
panel_make_local_copies_and_transfer (GtkWidget *widget, GdkEventDragRequest *event, WPanel *panel,
int *len, char **data)
{
char *filename, *localname;
int i;
if (panel->marked){
char **local_names_array, *p;
int j, total_len;
/* First assemble all of the filenames */
local_names_array = g_new (char *, panel->marked);
total_len = j = 0;
for (i = 0; i < panel->count; i++){
char *filename;
if (!panel->dir.list [i].f.marked)
continue;
filename = concat_dir_and_file (panel->cwd, panel->dir.list [i].fname);
localname = mc_getlocalcopy (filename);
total_len += strlen (localname) + 1;
local_names_array [j++] = localname;
g_free (filename);
}
*len = total_len;
*data = p = g_malloc (total_len);
for (i = 0; i < j; i++){
strcpy (p, local_names_array [i]);
g_free (local_names_array [i]);
p += strlen (p) + 1;
}
} else {
filename = concat_dir_and_file (panel->cwd, panel->dir.list [panel->selected].fname);
localname = mc_getlocalcopy (filename);
g_free (filename);
*data = localname;
*len = strlen (localname + 1);
}
}
static void
panel_drag_request (GtkWidget *widget, GdkEventDragRequest *event, WPanel *panel, int *len, char **data)
{
*len = 0;
*data = 0;
if ((strcmp (event->data_type, "text/plain") == 0) ||
(strcmp (event->data_type, "url:ALL") == 0)){
panel_transfer_file_names (widget, event, panel, len, data);
} else if (strcmp (event->data_type, "file:ALL") == 0){
if (vfs_file_is_local (panel->cwd))
panel_transfer_file_names (widget, event, panel, len, data);
else
panel_make_local_copies_and_transfer (widget, event, panel, len, data);
}
}
/*
* Listing mode: drag request handler
*/
static void
panel_clist_drag_request (GtkWidget *widget, GdkEventDragRequest *event, WPanel *panel)
{
GdkWindowPrivate *clist_window = (GdkWindowPrivate *) (GTK_WIDGET (widget)->window);
GdkWindowPrivate *clist_areaw = (GdkWindowPrivate *) (GTK_CLIST (widget)->clist_window);
char *data;
int len;
panel_drag_request (widget, event, panel, &len, &data);
/* Now transfer the DnD information */
if (len && data){
if (clist_window->dnd_drag_accepted)
gdk_window_dnd_data_set ((GdkWindow *)clist_window, (GdkEvent *) event, data, len);
else
gdk_window_dnd_data_set ((GdkWindow *)clist_areaw, (GdkEvent *) event, data, len);
g_free (data);
}
}
/*
* Invoked when a drop has happened on the panel
*/
static void
panel_clist_drop_data_available (GtkWidget *widget, GdkEventDropDataAvailable *data, WPanel *panel)
{
gint winx, winy;
gint dropx, dropy;
gint row;
char *drop_dir;
gdk_window_get_origin (GTK_CLIST (widget)->clist_window, &winx, &winy);
dropx = data->coords.x - winx;
dropy = data->coords.y - winy;
if (dropx < 0 || dropy < 0)
return;
if (gtk_clist_get_selection_info (GTK_CLIST (widget), dropx, dropy, &row, NULL) == 0)
drop_dir = panel->cwd;
else {
g_assert (row < panel->count);
}
#if 0
drop_on_directory (data, drop_dir, 0);
#endif
if (drop_dir != panel->cwd)
g_free (drop_dir);
update_one_panel_widget (panel, 0, UP_KEEPSEL);
panel_update_contents (panel);
}
static void
panel_drag_begin (GtkWidget *widget, GdkEvent *event, WPanel *panel)
{
GdkPoint hotspot = { 15, 15 };
if (panel->marked > 1){
if (drag_multiple && drag_multiple_ok){
gdk_dnd_set_drag_shape (drag_multiple->window, &hotspot,
drag_multiple_ok->window, &hotspot);
gtk_widget_show (drag_multiple);
gtk_widget_show (drag_multiple_ok);
}
} else {
if (drag_directory && drag_directory_ok)
gdk_dnd_set_drag_shape (drag_directory->window, &hotspot,
drag_directory_ok->window, &hotspot);
gtk_widget_show (drag_directory_ok);
gtk_widget_show (drag_directory);
}
}
static void
panel_icon_list_drag_begin (GtkWidget *widget, GdkEvent *event, WPanel *panel)
{
GnomeIconList *icons = GNOME_ICON_LIST (panel->icons);
icons->last_clicked = NULL;
panel_drag_begin (widget, event, panel);
}
static void
panel_artificial_drag_start (GtkCList *window, GdkEventMotion *event)
{
artificial_drag_start (window->clist_window, event->x, event->y);
}
#endif /* OLD_DND */
#if OLD_DND
static void
panel_icon_list_artificial_drag_start (GtkObject *obj, GdkEventMotion *event)
{
artificial_drag_start (GTK_WIDGET (obj)->window, event->x, event->y);
}
/*
* Icon view drag request handler
*/
static void
panel_icon_list_drag_request (GtkWidget *widget, GdkEventDragRequest *event, WPanel *panel)
{
char *data;
int len;
panel_drag_request (widget, event, panel, &len, &data);
if (len && data){
gdk_window_dnd_data_set (widget->window, (GdkEvent *) event, data, len);
g_free (data);
}
}
static void
panel_icon_list_drop_data_available (GtkWidget *widget, GdkEventDropDataAvailable *data, WPanel *panel)
{
GnomeIconList *ilist = GNOME_ICON_LIST (widget);
gint winx, winy;
gint dropx, dropy;
gint item;
char *drop_dir;
gdk_window_get_origin (widget->window, &winx, &winy);
dropx = data->coords.x - winx;
dropy = data->coords.y - winy;
if (dropx < 0 || dropy < 0)
return;
item = gnome_icon_list_get_icon_at (ilist, dropx, dropy);
if (item == -1)
drop_dir = panel->cwd;
else {
g_assert (item < panel->count);
if (S_ISDIR (panel->dir.list [item].buf.st_mode))
drop_dir = concat_dir_and_file (panel->cwd, panel->dir.list [item].fname);
else
drop_dir = panel->cwd;
}
#if 0
drop_on_directory (data, drop_dir, 0);
#endif
if (drop_dir != panel->cwd)
g_free (drop_dir);
update_one_panel_widget (panel, 0, UP_KEEPSEL);
panel_update_contents (panel);
}
#endif
#ifdef THIS_WAS_THE_OLD_DND_FOR_DESKTOP_DOT_C
#include <config.h>
#include "fs.h"
#include <gnome.h>
#include "gdesktop-icon.h"
#include "gdesktop.h"
#include "../vfs/vfs.h"
#include <string.h>
#include "mad.h"
#include "main.h"
#include "file.h"
#include "global.h"
#include "panel.h"
#include "gscreen.h"
#include "ext.h"
#include "dialog.h"
#include "gpageprop.h"
#include <gdk/gdkx.h>
#include <gdk/gdkprivate.h>
#include "gcache.h"
#include "gmain.h"
/* places used in the grid */
static char *spot_array;
/* number of icons that fit along the x and y axis */
static int x_spots, y_spots;
/* operations on drops */
enum {
OPER_COPY,
OPER_MOVE,
OPER_LINK
};
/* The X11 root window */
static GnomeRootWin *root_window;
/* The full name of the desktop directory ~/desktop */
char *desktop_directory;
static void desktop_reload (char *desktop_dir, GdkPoint *drop_position);
static void desktop_icon_context_popup (GdkEventButton *event, desktop_icon_t *di);
/* The list with the filenames we have actually loaded */
static GList *desktop_icons;
#define ELEMENTS(x) (sizeof (x) / sizeof (x[0]))
static void
init_spot_list (void)
{
int size;
x_spots = gdk_screen_width () / SNAP_X;
y_spots = gdk_screen_height () / SNAP_Y;
size = (x_spots * y_spots) / 8;
spot_array = g_malloc (size+1);
memset (spot_array, 0, size);
}
static int
is_spot_set (int x, int y)
{
int o = (x * x_spots + y);
int idx = o / 8;
int bit = o % 8;
return spot_array [idx] & (1 << bit);
}
static void
set_spot_val (int x, int y, int set)
{
int o = (x * x_spots + y);
int idx = o / 8;
int bit = o % 8;
if (set)
spot_array [idx] |= (1 << bit);
else
spot_array [idx] &= ~(1 << bit);
}
static void
allocate_free_spot (int *rx, int *ry)
{
int x, y;
for (x = 0; x < x_spots; x++)
for (y = 0; y < y_spots; y++)
if (!is_spot_set (x, y)){
*rx = x;
*ry = y;
set_spot_val (x, y, 1);
return;
}
}
static void
snap_to (desktop_icon_t *di, int absolute, int x, int y)
{
int nx = x/SNAP_X;
int ny = y/SNAP_Y;
if (!absolute && is_spot_set (nx, ny))
allocate_free_spot (&di->grid_x, &di->grid_y);
else {
set_spot_val (nx, ny, 1);
di->grid_x = nx;
di->grid_y = ny;
}
}
/* Get snapped position for an icon */
static void
get_icon_screen_x_y (desktop_icon_t *di, int *x, int *y)
{
int w, h;
w = DESKTOP_ICON (di->widget)->width;
h = DESKTOP_ICON (di->widget)->height;
if (di->grid_x != -1){
*x = di->grid_x * SNAP_X;
*y = di->grid_y * SNAP_Y;
*x = *x + (SNAP_X - w) / 2;
if (*x < 0)
*x = 0;
if (h > SNAP_Y)
*y = *y + (SNAP_Y - h) / 2;
else
*y = *y + (SNAP_Y - h);
} else {
*x = di->x;
*y = di->y;
}
}
/*
* If the dentry is zero, then no information from the on-disk .desktop file is used
* In this case, we probably will have to store the geometry for a file somewhere
* else.
*/
static int current_x, current_y;
static void
desktop_icon_set_position (desktop_icon_t *di)
{
static int x, y = 10;
x = -1;
if (di->dentry && di->dentry->geometry){
char *comma = strchr (di->dentry->geometry, ',');
if (comma){
x = atoi (di->dentry->geometry);
comma++;
y = atoi (comma);
}
}
if (icons_snap_to_grid){
if (x == -1){
x = current_x;
y = current_y;
current_y += SNAP_Y;
if (current_y > gdk_screen_height ())
current_x += SNAP_X;
snap_to (di, 1, x, y);
} else
snap_to (di, 0, x, y);
get_icon_screen_x_y (di, &x, &y);
} else {
/* This find-spot routine can obviously be improved, left as an excercise
* to the hacker
*/
if (x == -1){
x = current_x;
y = current_y;
current_y += DESKTOP_ICON (di)->height + 8;
if (current_y > gdk_screen_height ()){
current_x += SNAP_X;
current_y = 0;
}
}
x += 6;
di->grid_x = di->grid_y = -1;
}
di->x = x;
di->y = y;
gtk_widget_set_uposition (di->widget, x, y);
}
/*
* Returns the icon associated with the given file name, or app.xpm
* if no icon is defined for this application
*/
static char *
get_desktop_icon (char *pathname)
{
char *fname, *full_fname;
fname = regex_command (x_basename (pathname), "Icon", 0, 0);
/* Try the GNOME icon */
if (fname){
full_fname = gnome_unconditional_pixmap_file (fname);
g_free (fname);
if (exist_file (full_fname))
return full_fname;
g_free (full_fname);
}
/* Try a mc icon */
if (fname){
full_fname = concat_dir_and_file (ICONDIR, fname);
if (exist_file (full_fname))
return full_fname;
g_free (full_fname);
}
return gnome_unconditional_pixmap_file ("launcher-program.png");
}
/*
* Hackisigh routine taken from GDK
*/
#ifdef OLD_DND
static void
gdk_dnd_drag_begin (GdkWindow *initial_window)
{
GdkEventDragBegin tev;
tev.type = GDK_DRAG_BEGIN;
tev.window = initial_window;
tev.u.allflags = 0;
tev.u.flags.protocol_version = DND_PROTOCOL_VERSION;
gdk_event_put ((GdkEvent *) &tev);
}
void
artificial_drag_start (GdkWindow *window, int x, int y)
{
GdkWindowPrivate *wp = (GdkWindowPrivate *) window;
if (!wp->dnd_drag_enabled)
return;
#if 1
if (!gdk_dnd.drag_perhaps)
return;
if (gdk_dnd.dnd_grabbed)
return;
if (gdk_dnd.drag_really)
return;
gdk_dnd_drag_addwindow (window);
gdk_dnd_drag_begin (window);
XGrabPointer (gdk_display, wp->xwindow, False,
ButtonMotionMask | ButtonPressMask | ButtonReleaseMask,
GrabModeAsync, GrabModeAsync, gdk_root_window,
None, CurrentTime);
gdk_dnd.dnd_grabbed = TRUE;
gdk_dnd.drag_really = 1;
gdk_dnd_display_drag_cursor (x, y, FALSE, TRUE);
#else
gdk_dnd.real_sw = wp;
gdk_dnd.dnd_drag_start.x = x;
gdk_dnd.dnd_drag_start.y = y;
gdk_dnd.drag_perhaps = 1;
if(gdk_dnd.drag_startwindows)
{
g_free(gdk_dnd.drag_startwindows);
gdk_dnd.drag_startwindows = NULL;
}
gdk_dnd.drag_numwindows = gdk_dnd.drag_really = 0;
gdk_dnd.dnd_grabbed = FALSE;
{
/* Set motion mask for first DnD'd window, since it
will be the one that is actually dragged */
XWindowAttributes dnd_winattr;
XSetWindowAttributes dnd_setwinattr;
/* We need to get motion events while the button is down, so
we can know whether to really start dragging or not... */
XGetWindowAttributes(gdk_display, (Window)wp->xwindow,
&dnd_winattr);
wp->dnd_drag_savedeventmask = dnd_winattr.your_event_mask;
dnd_setwinattr.event_mask =
wp->dnd_drag_eventmask = ButtonMotionMask | ButtonPressMask | ButtonReleaseMask |
EnterWindowMask | LeaveWindowMask;
XChangeWindowAttributes(gdk_display, wp->xwindow,
CWEventMask, &dnd_setwinattr);
}
#endif
}
#endif /* OLD_DND */
static GdkDragAction operation_value;
static void
set_option (GtkWidget *widget, GdkDragAction value)
{
operation_value = value;
gtk_main_quit ();
}
static void
option_menu_gone ()
{
operation_value = GDK_ACTION_ASK;
gtk_main_quit ();
}
static GdkDragAction
get_operation (guint32 timestamp, int x, int y)
{
static GtkWidget *menu;
if (!menu){
GtkWidget *item;
menu = gtk_menu_new ();
item = gtk_menu_item_new_with_label (_("Copy"));
gtk_signal_connect (GTK_OBJECT (item), "activate",
GTK_SIGNAL_FUNC(set_option), (void *) GDK_ACTION_COPY);
gtk_menu_append (GTK_MENU (menu), item);
gtk_widget_show (item);
item = gtk_menu_item_new_with_label (_("Move"));
gtk_signal_connect (GTK_OBJECT (item), "activate",
GTK_SIGNAL_FUNC(set_option), (void *) GDK_ACTION_MOVE);
gtk_menu_append (GTK_MENU (menu), item);
gtk_widget_show (item);
/* Not yet implemented the Link bits, so better to not show what we dont have */
item = gtk_menu_item_new_with_label (_("Link"));
gtk_signal_connect (GTK_OBJECT (item), "activate",
GTK_SIGNAL_FUNC(set_option), (void *) GDK_ACTION_LINK);
gtk_menu_append (GTK_MENU (menu), item);
gtk_widget_show (item);
gtk_signal_connect (GTK_OBJECT (menu), "hide", GTK_SIGNAL_FUNC(option_menu_gone), 0);
}
gtk_widget_set_uposition (menu, x, y);
/* FIXME: We should catch any events that escape this menu and cancel it */
operation_value = GDK_ACTION_ASK;
gtk_menu_popup (GTK_MENU (menu), NULL, NULL, 0, NULL, 1, timestamp);
gtk_grab_add (menu);
gtk_main ();
gtk_grab_remove (menu);
gtk_widget_hide (menu);
return operation_value;
}
/*
* Used by check_window_id_in_one_panel and find_panel_owning_window_id for finding
* the panel that contains the specified window id (used to figure where the drag
* started)
*/
static WPanel *temp_panel;
static void
check_window_in_one_panel (gpointer data, gpointer user_data)
{
PanelContainer *pc = (PanelContainer *) data;
GdkWindowPrivate *w = (GdkWindowPrivate *) user_data;
WPanel *panel = pc->panel;
if (panel->list_type == list_icons){
GnomeIconList *icon_list = GNOME_ICON_LIST (panel->icons);
GdkWindowPrivate *wp = (GdkWindowPrivate *) GTK_WIDGET (icon_list)->window;
if (w->xwindow == wp->xwindow){
temp_panel = panel;
return;
}
} else {
GtkCList *clist = GTK_CLIST (panel->list);
GdkWindowPrivate *wp = (GdkWindowPrivate *) clist->clist_window;
if (w->xwindow == wp->xwindow){
temp_panel = panel;
return;
}
}
}
static WPanel *
find_panel_owning_window (GdkWindow *window)
{
temp_panel = NULL;
printf ("Looking for window %x\n", window);
g_list_foreach (containers, check_window_in_one_panel, window);
return temp_panel;
}
static void
perform_drop_on_directory (WPanel *source_panel, GdkDragAction action, char *dest)
{
switch (action){
case GDK_ACTION_COPY:
panel_operate (source_panel, OP_COPY, dest);
break;
case GDK_ACTION_MOVE:
panel_operate (source_panel, OP_MOVE, dest);
break;
}
}
static void
perform_drop_manually (GList *names, GdkDragAction action, char *dest)
{
struct stat buf;
switch (action){
case GDK_ACTION_COPY:
create_op_win (OP_COPY, 0);
break;
case GDK_ACTION_MOVE:
create_op_win (OP_MOVE, 0);
break;
default:
g_assert_not_reached ();
}
file_mask_defaults ();
for (; names; names = names->next){
char *p = names->data;
char *tmpf;
int res, v;
if (strncmp (p, "file:", 5) == 0)
p += 5;
switch (action){
case GDK_ACTION_COPY:
tmpf = concat_dir_and_file (dest, x_basename (p));
do {
res = mc_stat (p, &buf);
if (res != 0){
v = file_error (" Could not stat %s \n %s ", tmpf);
if (v != FILE_RETRY)
res = 0;
} else {
if (S_ISDIR (buf.st_mode))
copy_dir_dir (p, tmpf, 1, 0, 0, 0);
else
copy_file_file (p, tmpf, 1);
}
} while (res != 0);
g_free (tmpf);
break;
case GDK_ACTION_MOVE:
tmpf = concat_dir_and_file (dest, x_basename (p));
do {
res = mc_stat (p, &buf);
if (res != 0){
v = file_error (" Could not stat %s \n %s ", tmpf);
if (v != FILE_RETRY)
res = 0;
} else {
if (S_ISDIR (buf.st_mode))
move_dir_dir (p, tmpf);
else
move_file_file (p, tmpf);
}
} while (res != 0);
g_free (tmpf);
break;
default:
g_assert_not_reached ();
}
}
destroy_op_win ();
}
static void
do_symlinks (GList *names, char *dest)
{
for (; names; names = names->next){
char *full_dest_name;
char *name = names->data;
full_dest_name = concat_dir_and_file (dest, x_basename (name));
if (strncmp (name, "file:", 5) == 0)
mc_symlink (name+5, full_dest_name);
else
mc_symlink (name, full_dest_name);
g_free (full_dest_name);
}
}
#if OLD_DND
static char **
drops_from_event (GdkEventDropDataAvailable *event, int *argc)
{
int count, i, len;
int arguments;
char *p, **argv;
/* Count the number of file names received */
count = event->data_numbytes;
p = event->data;
arguments = 0;
while (count){
arguments++;
len = strlen (p) + 1;
count -= len;
p += len;
}
/* Create the exec vector with all of the filenames */
argv = g_new (char *, arguments + 1);
count = event->data_numbytes;
p = event->data;
i = 0;
do {
len = 1 + strlen (p);
count -= len;
argv [i++] = p;
p += len;
} while (count);
argv [i] = 0;
*argc = i;
return argv;
}
#endif /* OLD_DND */
void
drop_on_directory (GtkSelectionData *sel_data, GdkDragContext *context,
GdkDragAction action, char *dest, int force_manually)
{
WPanel *source_panel;
GList *names;
gdk_flush ();
g_warning ("Figure out the data type\n");
if (sel_data->data == NULL)
return;
printf ("action=%d\n", action);
if (action == GDK_ACTION_ASK){
g_warning ("I need the event here\n");
#if 0
action = get_operation (event->timestamp, event->coords.x, event->coords.y);
#endif
}
printf ("action=%d\n", action);
if (action == GDK_ACTION_ASK)
return;
/*
* Optimization: if we are dragging from the same process, we can
* display a nicer status bar.
*/
source_panel = find_panel_owning_window (context->source_window);
printf ("SOurce_Panel=%p\n", source_panel);
names = gnome_uri_list_extract_uris ((char *)sel_data->data);
/* Symlinks do not use any panel/file.c optimization */
if (action == GDK_ACTION_LINK){
do_symlinks (names, dest);
gnome_uri_list_free_strings (names);
return;
}
if (source_panel && !force_manually){
perform_drop_on_directory (source_panel, action, dest);
update_one_panel_widget (source_panel, 0, UP_KEEPSEL);
panel_update_contents (source_panel);
} else
perform_drop_manually (names, action, dest);
gnome_uri_list_free_strings (names);
return;
}
/*
* destroys a desktop_icon_t structure and anything that was held there,
* including the desktop widget.
*/
static void
desktop_release_desktop_icon_t (desktop_icon_t *di, int destroy_dentry)
{
if (di->dentry){
if (destroy_dentry)
gnome_desktop_entry_destroy (di->dentry);
else
gnome_desktop_entry_free (di->dentry);
} else {
g_free (di->pathname);
di->pathname = 0;
}
if (di->widget){
gtk_widget_destroy (di->widget);
di->widget = 0;
}
g_free (di);
}
static int
remove_directory (char *path)
{
int i;
if (confirm_delete){
char *buffer;
if (know_not_what_am_i_doing)
query_set_sel (1);
buffer = g_strconcat (_("Do you want to delete "), path, "?", NULL);
i = query_dialog (_("Delete"), buffer,
D_ERROR, 2, _("&Yes"), _("&No"));
g_free (buffer);
if (i != 0)
return 0;
}
create_op_win (OP_DELETE, 0);
erase_dir (path);
destroy_op_win ();
update_panels (UP_OPTIMIZE, UP_KEEPSEL);
return 1;
}
/*
* Removes an icon from the desktop and kills the ~/desktop file associated with it
*/
static void
desktop_icon_remove (desktop_icon_t *di)
{
desktop_icons = g_list_remove (desktop_icons, di);
if (di->dentry == NULL){
/* launch entry */
mc_unlink (di->pathname);
} else {
/* a .destop file or a directory */
/* Remove the .desktop */
mc_unlink (di->dentry->location);
if (strcmp (di->dentry->type, "Directory") == 0){
struct stat s;
if (mc_lstat (di->dentry->exec[0], &s) == 0){
if (S_ISLNK (s.st_mode))
mc_unlink (di->dentry->exec[0]);
else
if (!remove_directory (di->dentry->exec[0]))
return;
}
} else {
if (strncmp (di->dentry->exec [0], desktop_directory, strlen (desktop_directory)) == 0)
mc_unlink (di->dentry->exec [0]);
}
}
desktop_release_desktop_icon_t (di, 1);
}
#ifdef OLD_DN
static void
drop_on_launch_entry (GtkWidget *widget, GdkEventDropDataAvailable *event, desktop_icon_t *di)
{
struct stat s;
char *r;
char **drops;
int drop_count;
/* try to stat it, if it fails, remove it from desktop */
if (!mc_stat (di->dentry->exec [0], &s) == 0){
desktop_icon_remove (di);
return;
}
drops = drops_from_event (event, &drop_count);
r = regex_command (di->pathname, "Drop", drops, 0);
if (r && strcmp (r, "Success") == 0){
g_free (drops);
return;
}
if (is_exe (s.st_mode))
gnome_desktop_entry_launch_with_args (di->dentry, drop_count, drops);
g_free (drops);
}
static void
url_dropped (GtkWidget *widget, GdkEventDropDataAvailable *event, desktop_icon_t *di)
{
char *p;
int count;
int len;
int is_directory = 0;
/* if DI is set to zero, then it is a drop on the root window */
if (di)
is_directory = g_strcasecmp (di->dentry->type, "directory") == 0;
else {
char *drop_location;
drop_on_directory (event, desktop_directory, 1);
desktop_reload (desktop_directory, &event->coords);
return;
}
if (is_directory){
drop_on_directory (event, di->dentry->exec[0], 0);
return;
}
/* Last case: regular desktop stuff */
drop_on_launch_entry (widget, event, di);
}
static int
drop_cb (GtkWidget *widget, GdkEventDropDataAvailable *event, desktop_icon_t *di)
{
if (strcmp (event->data_type, "icon/root") == 0){
printf ("ICON DROPPED ON ROOT!\n");
} if (strcmp (event->data_type, "url:ALL") == 0 ||
(strcmp (event->data_type, "file:ALL") == 0) ||
(strcmp (event->data_type, "text/plain") == 0)){
url_dropped (widget, event, di);
} else
return FALSE;
return TRUE;
}
static void
drop_enter_leave ()
{
/* printf ("Enter/Leave\n"); */
}
static void
connect_drop_signals (GtkWidget *widget, desktop_icon_t *di)
{
GtkObject *o = GTK_OBJECT (widget);
gtk_signal_connect (o, "drop_enter_event", GTK_SIGNAL_FUNC (drop_enter_leave), di);
gtk_signal_connect (o, "drop_leave_event", GTK_SIGNAL_FUNC (drop_enter_leave), di);
gtk_signal_connect (o, "drop_data_available_event", GTK_SIGNAL_FUNC (drop_cb), di);
}
#endif /* OLD DND */
void
desktop_icon_execute (GtkWidget *ignored, desktop_icon_t *di)
{
/* Ultra lame-o execute. This should be replaced by the fixed regexp_command
* invocation
*/
if (strcmp (di->dentry->type, "Directory") == 0)
new_panel_at (di->dentry->exec[0]);
else
gnome_desktop_entry_launch (di->dentry);
}
static void
start_icon_drag (GtkWidget *wi, GdkEventMotion *event)
{
printf ("MOTION NOTIF!\n");
#ifdef OLD_DND
artificial_drag_start (wi->window, event->x, event->y);
#endif
}
GdkPoint root_icon_drag_hotspot = { 15, 15 };
static void
desktop_icon_configure_position (desktop_icon_t *di, int x, int y)
{
gtk_widget_set_uposition (di->widget, x, y);
if (di->dentry){
char buffer [40];
g_snprintf (buffer, sizeof (buffer), "%d,%d", x, y);
if (di->dentry->geometry)
g_free (di->dentry->geometry);
di->dentry->geometry = g_strdup (buffer);
gnome_desktop_entry_save (di->dentry);
}
}
#ifdef OLD_DND
static void
desktop_icon_drag_request (GtkWidget *widget, GdkEventDragRequest *event, desktop_icon_t *di)
{
printf ("Drag type: %s\n", event->data_type);
if (strcmp (event->data_type, "url:ALL") == 0){
gdk_window_dnd_data_set (widget->window, (GdkEvent *)event, di->pathname, strlen (di->pathname) + 1);
} else {
int drop_x, drop_y;
drop_x = event->drop_coords.x - root_icon_drag_hotspot.x;
drop_y = event->drop_coords.y - root_icon_drag_hotspot.y;
/* Icon dropped on root. We take care of it */
printf ("Dropped at %d %d\n", drop_x, drop_y);
if (di->grid_x != -1)
set_spot_val (di->grid_x, di->grid_y, 0);
if (icons_snap_to_grid){
snap_to (di, 0, drop_x, drop_y);
get_icon_screen_x_y (di, &drop_x, &drop_y);
}
desktop_icon_configure_position (di, drop_x, drop_y);
}
}
#endif
static GtkWidget *root_drag_ok_window;
static GtkWidget *root_drag_not_ok_window;
static void
destroy_shaped_dnd_windows (void)
{
if (root_drag_not_ok_window){
gtk_widget_destroy (root_drag_not_ok_window);
root_drag_not_ok_window = 0;
}
if (root_drag_ok_window){
gtk_widget_destroy (root_drag_ok_window);
root_drag_ok_window = 0;
}
}
void
gnome_arrange_icons (void)
{
GList *l;
current_x = current_y = 0;
memset (spot_array, 0, (x_spots * y_spots)/8);
for (l = desktop_icons; l; l = l->next){
desktop_icon_t *di = l->data;
int x, y;
snap_to (di, 1, current_x, current_y);
get_icon_screen_x_y (di, &x, &y);
desktop_icon_configure_position (di, x, y);
current_y += SNAP_Y;
if (current_y == gdk_screen_height ()){
current_y = 0;
current_x += SNAP_X;
}
}
}
/* As Elliot can not be bothered to fix his DnD code in Gdk and it is an absolute mess */
static int in_desktop_dnd;
static void
desktop_icon_drag_start (GtkWidget *widget, GdkEvent *event, desktop_icon_t *di)
{
char *fname;
if (in_desktop_dnd)
return;
in_desktop_dnd = 1;
/* This should not happen, as the drag end routine should destroy those widgets */
destroy_shaped_dnd_windows ();
if (di->dentry)
fname = g_strdup (di->dentry->icon);
else
fname = get_desktop_icon (di->pathname);
if (fname){
/* FIXME: we are using the same icon for ok and not ok drags */
root_drag_ok_window = make_transparent_window (fname);
root_drag_not_ok_window = make_transparent_window (fname);
if (root_drag_not_ok_window && root_drag_ok_window){
#ifdef OLD_DND
gdk_dnd_set_drag_shape (root_drag_ok_window->window, &root_icon_drag_hotspot,
root_drag_not_ok_window->window, &root_icon_drag_hotspot);
#endif
gtk_widget_show (root_drag_not_ok_window);
gtk_widget_show (root_drag_ok_window);
}
g_free (fname);
}
}
static void
desktop_icon_drag_end (GtkWidget *widget, GdkEvent *event, desktop_icon_t *di)
{
in_desktop_dnd = 0;
destroy_shaped_dnd_windows ();
}
/*
* Bind the signals so that we can make this icon draggable
*/
static void
desktop_icon_make_draggable (desktop_icon_t *di)
{
GtkObject *obj;
GList *child;
char *drag_types [] = { "icon/root", "url:ALL" };
child = gtk_container_children(GTK_CONTAINER(di->widget));
obj = GTK_OBJECT (child->data);
/* To artificially start up drag and drop */
#ifdef OLD_DND
/* gtk_signal_connect (obj, "motion_notify_event", GTK_SIGNAL_FUNC (start_icon_drag), di); */
gtk_widget_dnd_drag_set (GTK_WIDGET(child->data), TRUE, drag_types, ELEMENTS (drag_types));
gtk_signal_connect (obj, "drag_request_event", GTK_SIGNAL_FUNC (desktop_icon_drag_request), di);
gtk_signal_connect (obj, "drag_begin_event", GTK_SIGNAL_FUNC (desktop_icon_drag_start), di);
gtk_signal_connect (obj, "drag_end_event", GTK_SIGNAL_FUNC (desktop_icon_drag_end), di);
#endif
}
/* Called by the pop up menu: removes the icon from the desktop */
void
desktop_icon_delete (GtkWidget *widget, desktop_icon_t *di)
{
desktop_icon_remove (di);
}
GtkWidget *
create_desktop_icon (char *file, char *text)
{
GtkWidget *w;
if (g_file_exists (file))
w = desktop_icon_new (file, text);
else {
static char *default_image;
if (!default_image)
default_image = gnome_unconditional_pixmap_file ("launcher-program.png");
if (g_file_exists (default_image))
w = desktop_icon_new (default_image, text);
else
w = NULL;
}
return w;
}
static GtkWidget *
get_desktop_icon_for_dentry (GnomeDesktopEntry *dentry)
{
GtkWidget *dicon;
char *icon_label;
icon_label = dentry->name ? dentry->name : x_basename (dentry->exec[0]);
if (dentry->icon)
dicon = create_desktop_icon (dentry->icon, icon_label);
else {
static char *default_icon_path;
static char exists;
if (!default_icon_path) {
default_icon_path = gnome_unconditional_pixmap_file ("launcher-program.png");
if (g_file_exists (default_icon_path))
exists = 1;
}
if (exists)
dicon = create_desktop_icon (default_icon_path, icon_label);
else {
dicon = gtk_window_new (GTK_WINDOW_POPUP);
gtk_widget_set_usize (dicon, 20, 20);
}
}
return dicon;
}
static GtkWidget *
get_desktop_icon_for_di (desktop_icon_t *di)
{
GtkWidget *window;
char *icon_label, *icon;
icon_label = x_basename (di->pathname);
icon = get_desktop_icon (di->pathname);
window = create_desktop_icon (icon, icon_label);
g_free (icon);
return window;
}
static int
dentry_button_click (GtkWidget *widget, GdkEventButton *event, desktop_icon_t *di)
{
if (event->button == 1){
if (event->type == GDK_2BUTTON_PRESS)
desktop_icon_execute (widget, di);
return TRUE;
}
if (event->type == GDK_BUTTON_PRESS && event->button == 3){
desktop_icon_context_popup (event, di);
return TRUE;
}
return FALSE;
}
char *drop_types [] = {
"text/plain",
"url:ALL",
};
static void
post_setup_desktop_icon (desktop_icon_t *di, int show)
{
GList *child;
desktop_icon_make_draggable (di);
/* Setup the widget to make it useful: */
#ifdef OLD_DND
/* 1. Drag and drop functionality */
child = gtk_container_children(GTK_CONTAINER(di->widget));
connect_drop_signals (GTK_WIDGET(child->data), di);
gtk_widget_dnd_drop_set (GTK_WIDGET(child->data), TRUE, drop_types, ELEMENTS (drop_types), FALSE);
/* 2. Double clicking executes the command */
gtk_signal_connect (GTK_OBJECT (child->data), "button_press_event", GTK_SIGNAL_FUNC (dentry_button_click), di);
#endif
if (show)
gtk_widget_show (di->widget);
}
/* Pops up the icon properties pages */
void
desktop_icon_properties (GtkWidget *widget, desktop_icon_t *di)
{
int retval;
retval = item_properties (di->widget, di->pathname, di);
if (retval & (GPROP_TITLE | GPROP_ICON | GPROP_FILENAME)) {
gtk_widget_destroy (di->widget);
if (di->dentry)
di->widget = get_desktop_icon_for_dentry (di->dentry);
else
di->widget = get_desktop_icon_for_di (di);
if (icons_snap_to_grid && di->grid_x != -1)
get_icon_screen_x_y (di, &di->x, &di->y);
gtk_widget_set_uposition (di->widget, di->x, di->y);
post_setup_desktop_icon (di, 1);
if (di->dentry)
gnome_desktop_entry_save (di->dentry);
}
}
/*
* Activates the context sensitive menu for this icon
*/
static void
desktop_icon_context_popup (GdkEventButton *event, desktop_icon_t *di)
{
file_popup (event, NULL, di, 0, di->dentry->exec [0]);
}
char *root_drop_types [] = {
"icon/root",
"url:ALL"
};
static void
desktop_load_from_dentry (GnomeDesktopEntry *dentry)
{
GtkWidget *dicon;
desktop_icon_t *di;
dicon = get_desktop_icon_for_dentry (dentry);
if (!dicon)
return;
di = g_new (desktop_icon_t, 1);
di->dentry = dentry;
di->widget = dicon;
di->pathname = dentry->location;
desktop_icons = g_list_prepend (desktop_icons, di);
post_setup_desktop_icon (di, 0);
desktop_icon_set_position (di);
}
/*
* Loads a .desktop file from FILENAME for the desktop.
*/
static void
desktop_load_dentry (char *filename)
{
GnomeDesktopEntry *dentry;
dentry = gnome_desktop_entry_load (filename);
if (!dentry)
return;
desktop_load_from_dentry (dentry);
}
/* Set the drop position to NULL, we only drop the
* first icon on the spot it was dropped, th rest
* get auto-layouted. Perhaps this should be an option.
*/
static void
desktop_setup_geometry_from_point (GnomeDesktopEntry *dentry, GdkPoint **point)
{
char buffer [40];
g_snprintf (buffer, sizeof (buffer), "%d,%d", (*point)->x, (*point)->y);
dentry->geometry = g_strdup (buffer);
*point = NULL;
}
/*
* Creates a new DIRECTORY/.directory file which is just a .dekstop
* on directories. And then loads it into the desktop
*/
static void
desktop_create_directory_entry (char *dentry_path, char *pathname, char *short_name, GdkPoint **pos)
{
GnomeDesktopEntry *dentry;
dentry = g_new (GnomeDesktopEntry, 1);
memset (dentry, 0, sizeof (GnomeDesktopEntry));
dentry->name = g_strdup (short_name);
dentry->exec = g_new (char *, 2);
dentry->exec[0] = g_strdup (pathname);
dentry->exec[1] = NULL;
dentry->exec_length = 1;
dentry->icon = gnome_unconditional_pixmap_file ("gnome-folder.png");
dentry->type = g_strdup ("Directory");
dentry->location = g_strdup (dentry_path);
if (pos && *pos)
desktop_setup_geometry_from_point (dentry, pos);
gnome_desktop_entry_save (dentry);
desktop_load_from_dentry (dentry);
}
static int
file_is_executable (char *path)
{
struct stat s;
if (mc_stat (path, &s) == -1)
return 0;
if (is_exe (s.st_mode))
return 1;
return 0;
}
static int
desktop_file_exec (GtkWidget *widget, GdkEventButton *event, desktop_icon_t *di)
{
if (event->type == GDK_2BUTTON_PRESS && event->button == 1){
if (di->dentry){
printf ("FIXME: No support for dentry loaded stuff yet\n");
} else {
if (file_is_executable (di->pathname)){
char *tmp = name_quote (di->pathname, 0);
if (!confirm_execute || (query_dialog (_(" The Midnight Commander "),
_(" Do you really want to execute? "),
0, 2, _("&Yes"), _("&No")) == 0))
execute (tmp);
g_free (tmp);
} else {
char *result, *command;
result = regex_command (di->pathname, "Open", NULL, 0);
if (result && (strcmp (result, "Success") == 0))
return TRUE;
command = input_expand_dialog (_("Open with..."),
_("Enter extra arguments:"),
di->pathname);
if (command){
execute (command);
g_free (command);
}
}
}
return TRUE;
}
if (event->type == GDK_BUTTON_PRESS && event->button == 3){
desktop_icon_context_popup (event, di);
return TRUE;
}
return FALSE;
}
static void
desktop_create_launch_entry (char *desktop_file, char *pathname, char *short_name, GdkPoint **pos)
{
GnomeDesktopEntry *dentry;
GtkWidget *dicon;
desktop_icon_t *di;
char *icon;
struct stat s;
stat (pathname, &s);
dentry = g_new (GnomeDesktopEntry, 1);
memset (dentry, 0, sizeof (GnomeDesktopEntry));
dentry->name = g_strdup (short_name);
dentry->exec = g_new (char *, 2);
dentry->exec[0] = g_strdup (pathname);
dentry->exec[1] = NULL;
dentry->exec_length = 1;
dentry->icon = get_desktop_icon (short_name);
dentry->type = g_strdup ("File");
dentry->location = g_strdup (desktop_file);
dentry->terminal = 1;
if (pos && *pos)
desktop_setup_geometry_from_point (dentry, pos);
gnome_desktop_entry_save (dentry);
desktop_load_from_dentry (dentry);
#if 0
dicon = create_desktop_icon (icon, x_basename (pathname));
g_free (icon);
if (!dicon)
return;
di = g_new (desktop_icon_t, 1);
di->dentry = NULL;
di->widget = dicon;
di->pathname = g_strdup (pathname);
desktop_icon_set_position (di);
desktop_icon_make_draggable (di);
desktop_icons = g_list_prepend (desktop_icons, (gpointer) di);
/* Double clicking executes the command, single clicking brings up context menu */
gtk_signal_connect (GTK_OBJECT (dicon), "button_press_event", GTK_SIGNAL_FUNC (desktop_file_exec), di);
gtk_widget_realize (dicon);
gtk_signal_connect (GTK_OBJECT (dicon), "drop_data_available_event",
GTK_SIGNAL_FUNC (drop_on_launch_entry), di);
gtk_widget_dnd_drop_set (dicon, TRUE, drop_types, ELEMENTS (drop_types), FALSE);
#endif
}
static int
desktop_pathname_loaded (char *pathname)
{
GList *p = desktop_icons;
for (; p; p = p->next){
desktop_icon_t *di = p->data;
if (strcmp (di->pathname, pathname) == 0)
return 1;
}
return 0;
}
static void
desktop_setup_icon (char *filename, char *full_pathname, GdkPoint **desired_position)
{
struct stat s;
if (mc_stat (full_pathname, &s) == -1)
return;
if (S_ISDIR (s.st_mode)){
char *dir_full = concat_dir_and_file (full_pathname, ".directory");
if (!desktop_pathname_loaded (dir_full)){
if (exist_file (dir_full))
desktop_load_dentry (dir_full);
else
desktop_create_directory_entry (dir_full, full_pathname, filename, desired_position);
}
g_free (dir_full);
} else {
if (strstr (filename, ".desktop")){
if (!desktop_pathname_loaded (full_pathname))
desktop_load_dentry (full_pathname);
} else {
char *desktop_version;
desktop_version = g_strconcat (full_pathname, ".desktop", NULL);
if (!exist_file (desktop_version) && !desktop_pathname_loaded (full_pathname))
desktop_create_launch_entry (desktop_version, full_pathname, filename, desired_position);
g_free (desktop_version);
}
}
}
/*
* Load all of the entries available on the ~/desktop directory
* So far, we support: .desktop files; directories (they get a .directory file);
* sylinks to directories; other programs.
*/
static void
desktop_reload (char *desktop_dir, GdkPoint *drop_position)
{
struct dirent *dent;
GList *l;
DIR *dir;
dir = mc_opendir (desktop_dir);
if (dir == NULL){
message (1, _(" Warning "), _(" Could not open %s directory"), desktop_dir, NULL);
return;
}
while ((dent = mc_readdir (dir)) != NULL){
char *full;
/* ignore '.' */
if (dent->d_name [0] == '.' && dent->d_name [1] == 0)
continue;
/* ignore `..' */
if (dent->d_name [0] == '.' && dent->d_name [1] == '.' && dent->d_name [2] == 0)
continue;
full = concat_dir_and_file (desktop_dir, dent->d_name);
desktop_setup_icon (dent->d_name, full, &drop_position);
g_free (full);
}
mc_closedir (dir);
/* Show all of the widgets */
for (l = desktop_icons; l; l = l->next){
desktop_icon_t *di = l->data;
gtk_widget_show (di->widget);
}
}
static void
desktop_load (char *desktop_dir)
{
desktop_reload (desktop_dir, NULL);
}
/*
* Copy the system defaults to the user ~/desktop directory and setup a
* Home directory link
*/
static void
desktop_setup_default (char *desktop_dir)
{
char *mc_desktop_dir;
char *desktop_dir_home_link;
desktop_dir_home_link = concat_dir_and_file (desktop_dir, "Home directory.desktop");
mc_desktop_dir = concat_dir_and_file (mc_home, MC_LIB_DESKTOP);
if (exist_file (mc_desktop_dir)){
create_op_win (OP_COPY, 0);
file_mask_defaults ();
copy_dir_dir (mc_desktop_dir, desktop_dir, 1, 0, 0, 0);
destroy_op_win ();
} else
mkdir (desktop_dir, 0777);
desktop_create_directory_entry (desktop_dir_home_link, "~", "Home directory", NULL);
g_free (desktop_dir_home_link);
g_free (mc_desktop_dir);
}
/*
* configures the root window dropability
*/
void
desktop_root (void)
{
GtkWidget *rw;
rw = gnome_rootwin_new ();
#ifdef OLD_DND
connect_drop_signals (rw, NULL);
gtk_widget_dnd_drop_set (rw, TRUE, root_drop_types, ELEMENTS (root_drop_types), FALSE);
gtk_widget_realize (rw);
gtk_widget_show (rw);
root_window = GNOME_ROOTWIN (rw);
#endif
}
/*
* entry point to start up the gnome desktop
*/
void
start_desktop (void)
{
init_spot_list ();
desktop_directory = concat_dir_and_file (home_dir, "desktop");
if (!exist_file (desktop_directory))
desktop_setup_default (desktop_directory);
desktop_root ();
desktop_load (desktop_directory);
}
/*
* shutdown the desktop
*/
void
stop_desktop (void)
{
GList *p;
for (p = desktop_icons; p; p = p->next){
desktop_icon_t *di = p->data;
desktop_release_desktop_icon_t (di, 0);
}
image_cache_destroy ();
}
#endif