1
1

1999-01-21 Federico Mena Quintero <federico@nuclecu.unam.mx>

* gdesktop.c (setup_icon_dnd_dest): Always specify ACTION_MOVE,
	since we want to be able to move the icons around.  Connect to the
	drag_motion signal.
	(dnd_icon_targets): List desktop icons as a target to be able to
	move them just a notch in the desktop.
	(icon_drag_motion): Decide which action we can use for dropping
	stuff on a desktop icon.
	(setup_icon_dnd_dest): Always specify all the actions.
	(icon_drag_data_received): Allow for icons to be moved just a
	notch by accepting drops from icons.

	* gdnd.h: Added #defines for the DnD target type names.

	* gdnd.c (gdnd_init): New public function to intern the target
	atom names.
	(gdnd_drag_context_has_target): New public function to see if a
	drag context has a certain target type.

	* gdesktop.c (setup_desktop_dnd): Do not use
	GTK_DEST_DEFAULT_MOVE, and connect to drag_motion.
	(desktop_drag_motion): If we are dragging from a desktop icon,
	indicate the action as MOVE.  Otherwise, force the action to be
	LINK unless the user explicitly requested ASK.
	(setup_desktop_dnd): Intern the atoms for the drop targets.
Этот коммит содержится в:
Miguel de Icaza 1999-01-21 09:46:01 +00:00
родитель a4cd04032f
Коммит 436638f2bd
4 изменённых файлов: 264 добавлений и 116 удалений

Просмотреть файл

@ -1,3 +1,30 @@
1999-01-21 Federico Mena Quintero <federico@nuclecu.unam.mx>
* gdesktop.c (setup_icon_dnd_dest): Always specify ACTION_MOVE,
since we want to be able to move the icons around. Connect to the
drag_motion signal.
(dnd_icon_targets): List desktop icons as a target to be able to
move them just a notch in the desktop.
(icon_drag_motion): Decide which action we can use for dropping
stuff on a desktop icon.
(setup_icon_dnd_dest): Always specify all the actions.
(icon_drag_data_received): Allow for icons to be moved just a
notch by accepting drops from icons.
* gdnd.h: Added #defines for the DnD target type names.
* gdnd.c (gdnd_init): New public function to intern the target
atom names.
(gdnd_drag_context_has_target): New public function to see if a
drag context has a certain target type.
* gdesktop.c (setup_desktop_dnd): Do not use
GTK_DEST_DEFAULT_MOVE, and connect to drag_motion.
(desktop_drag_motion): If we are dragging from a desktop icon,
indicate the action as MOVE. Otherwise, force the action to be
LINK unless the user explicitly requested ASK.
(setup_desktop_dnd): Intern the atoms for the drop targets.
1999-01-20 Miguel de Icaza <miguel@nuclecu.unam.mx> 1999-01-20 Miguel de Icaza <miguel@nuclecu.unam.mx>
* gscreen.c: Selection code now is simpler and should be easier to * gscreen.c: Selection code now is simpler and should be easier to

Просмотреть файл

@ -84,19 +84,20 @@ static DesktopIconInfo *last_selected_icon;
/* Drag and drop sources and targets */ /* Drag and drop sources and targets */
static GtkTargetEntry dnd_icon_sources[] = { static GtkTargetEntry dnd_icon_sources[] = {
{ "application/x-mc-desktop-icon", 0, TARGET_MC_DESKTOP_ICON }, { TARGET_MC_DESKTOP_ICON_TYPE, 0, TARGET_MC_DESKTOP_ICON },
{ "text/uri-list", 0, TARGET_URI_LIST }, { TARGET_URI_LIST_TYPE, 0, TARGET_URI_LIST },
{ "text/plain", 0, TARGET_TEXT_PLAIN }, { TARGET_TEXT_PLAIN_TYPE, 0, TARGET_TEXT_PLAIN },
{ "_NETSCAPE_URL", 0, TARGET_URL } { TARGET_URL_TYPE, 0, TARGET_URL }
}; };
static GtkTargetEntry dnd_icon_targets[] = { static GtkTargetEntry dnd_icon_targets[] = {
{ "text/uri-list", 0, TARGET_URI_LIST } { TARGET_MC_DESKTOP_ICON_TYPE, 0, TARGET_MC_DESKTOP_ICON },
{ TARGET_URI_LIST_TYPE, 0, TARGET_URI_LIST }
}; };
static GtkTargetEntry dnd_desktop_targets[] = { static GtkTargetEntry dnd_desktop_targets[] = {
{ "application/x-mc-desktop-icon", 0, TARGET_MC_DESKTOP_ICON }, { TARGET_MC_DESKTOP_ICON_TYPE, 0, TARGET_MC_DESKTOP_ICON },
{ "text/uri-list", 0, TARGET_URI_LIST } { TARGET_URI_LIST_TYPE, 0, TARGET_URI_LIST }
}; };
static int dnd_icon_nsources = sizeof (dnd_icon_sources) / sizeof (dnd_icon_sources[0]); static int dnd_icon_nsources = sizeof (dnd_icon_sources) / sizeof (dnd_icon_sources[0]);
@ -1112,6 +1113,126 @@ setup_icon_dnd_source (DesktopIconInfo *dii)
dii); dii);
} }
/* Callback used when we get a drag_motion event from a desktop icon. We have
* to decide which operation to perform based on the type of the data the user
* is dragging.
*/
static gboolean
icon_drag_motion (GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time,
gpointer data)
{
DesktopIconInfo *dii;
char *filename;
file_entry *fe;
GdkDragAction action;
dii = data;
filename = g_concat_dir_and_file (desktop_directory, dii->filename);
fe = file_entry_from_file (filename);
g_free (filename);
action = 0; /* be pessimistic by defaulting to nothing */
if (dii->selected
&& gdnd_drag_context_has_target (context, TARGET_MC_DESKTOP_ICON)
&& (context->actions & GDK_ACTION_MOVE))
action = GDK_ACTION_MOVE;
else if (gdnd_drag_context_has_target (context, TARGET_URI_LIST)) {
if (fe->f.link_to_dir)
action = context->suggested_action;
else if (is_exe (fe->buf.st_mode)
&& if_link_is_exe (fe)
&& (context->actions & GDK_ACTION_COPY))
action = GDK_ACTION_COPY;
}
gdk_drag_status (context, action, time);
return TRUE;
}
/* Returns the desktop icon that started the drag from the specified context */
static DesktopIconInfo *
find_icon_by_drag_context (GdkDragContext *context)
{
GtkWidget *source;
int i;
GList *l;
DesktopIconInfo *dii;
source = gtk_drag_get_source_widget (context);
if (!source)
return NULL;
source = gtk_widget_get_toplevel (source);
for (i = 0; i < (layout_cols * layout_rows); i++)
for (l = layout_slots[i].icons; l; l = l->next) {
dii = l->data;
if (dii->dicon == source)
return dii;
}
return NULL;
}
/*
* Performs a drop of desktop icons onto the desktop. It basically moves the icons from their
* original position to the new coordinates.
*/
static void
drop_desktop_icons (GdkDragContext *context, GtkSelectionData *data, int x, int y)
{
DesktopIconInfo *source_dii, *dii;
int dx, dy;
int i;
GList *l;
GSList *sel_icons, *sl;
/* FIXME: this needs to do the right thing (what Windows does) when desktop_auto_placement
* is enabled.
*/
/* Find the icon that the user is dragging */
source_dii = find_icon_by_drag_context (context);
if (!source_dii) {
g_warning ("Eeeeek, could not find the icon that started the drag!");
return;
}
/* Compute the distance to move icons */
if (desktop_snap_icons)
get_icon_snap_pos (&x, &y);
dx = x - source_dii->x - dnd_press_x;
dy = y - source_dii->y - dnd_press_y;
/* Build a list of selected icons */
sel_icons = NULL;
for (i = 0; i < (layout_cols * layout_rows); i++)
for (l = layout_slots[i].icons; l; l = l->next) {
dii = l->data;
if (dii->selected)
sel_icons = g_slist_prepend (sel_icons, l->data);
}
/* Move the icons */
for (sl = sel_icons; sl; sl = sl->next) {
dii = sl->data;
desktop_icon_info_place (dii, FALSE, dii->x + dx, dii->y + dy);
}
/* Clean up */
g_slist_free (sel_icons);
}
/** /**
* drop_on_file_entry * drop_on_file_entry
*/ */
@ -1210,6 +1331,14 @@ icon_drag_data_received (GtkWidget *widget, GdkDragContext *context, gint x, gin
dii = user_data; dii = user_data;
switch (info) { switch (info) {
case TARGET_MC_DESKTOP_ICON:
if (dii->selected)
drop_desktop_icons (context, data, x + dii->x, y + dii->y);
else
printf ("FIXME: what do drop?\n"); /* FIXME */
break;
case TARGET_URI_LIST: case TARGET_URI_LIST:
printf ("Wheeeeee!\n"); printf ("Wheeeeee!\n");
desktop_icon_drop_uri_list (dii, context, data); desktop_icon_drop_uri_list (dii, context, data);
@ -1224,41 +1353,17 @@ icon_drag_data_received (GtkWidget *widget, GdkDragContext *context, gint x, gin
static void static void
setup_icon_dnd_dest (DesktopIconInfo *dii) setup_icon_dnd_dest (DesktopIconInfo *dii)
{ {
char *filename;
file_entry *fe;
int actions;
filename = g_concat_dir_and_file (desktop_directory, dii->filename);
fe = file_entry_from_file (filename);
g_free (filename);
if (!fe)
return; /* eek */
/* See what actions are appropriate for this icon */
if (fe->f.link_to_dir)
actions = GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK | GDK_ACTION_ASK;
else if (is_exe (fe->buf.st_mode) && if_link_is_exe (fe))
actions = GDK_ACTION_COPY;
else
actions = 0;
file_entry_free (fe);
if (!actions)
return;
/* Connect the drop signals */
gtk_drag_dest_set (DESKTOP_ICON (dii->dicon)->canvas, gtk_drag_dest_set (DESKTOP_ICON (dii->dicon)->canvas,
GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP, GTK_DEST_DEFAULT_DROP,
dnd_icon_targets, dnd_icon_targets,
dnd_icon_ntargets, dnd_icon_ntargets,
actions); GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK | GDK_ACTION_ASK);
gtk_signal_connect (GTK_OBJECT (DESKTOP_ICON (dii->dicon)->canvas), "drag_motion",
(GtkSignalFunc) (icon_drag_motion),
dii);
gtk_signal_connect (GTK_OBJECT (DESKTOP_ICON (dii->dicon)->canvas), "drag_data_received", gtk_signal_connect (GTK_OBJECT (DESKTOP_ICON (dii->dicon)->canvas), "drag_data_received",
GTK_SIGNAL_FUNC (icon_drag_data_received), (GtkSignalFunc) icon_drag_data_received,
dii); dii);
} }
@ -1510,86 +1615,33 @@ setup_xdnd_proxy (guint32 xid, GdkWindow *proxy_window)
return FALSE; return FALSE;
} }
/* Returns the desktop icon that started the drag from the specified context */ /* Callback used when we get a drag_motion event from the desktop. We must
static DesktopIconInfo * * decide what kind of operation can be performed with what the user is
find_icon_by_drag_context (GdkDragContext *context) * dragging.
{
GtkWidget *source;
int i;
GList *l;
DesktopIconInfo *dii;
source = gtk_drag_get_source_widget (context);
if (!source)
return NULL;
source = gtk_widget_get_toplevel (source);
for (i = 0; i < (layout_cols * layout_rows); i++)
for (l = layout_slots[i].icons; l; l = l->next) {
dii = l->data;
if (dii->dicon == source)
return dii;
}
return NULL;
}
/*
* Performs a drop of desktop icons onto the desktop. It basically moves the icons from their
* original position to the new coordinates.
*/ */
static void static gboolean
drop_desktop_icons (GdkDragContext *context, GtkSelectionData *data, int x, int y) desktop_drag_motion (GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time,
gpointer data)
{ {
DesktopIconInfo *source_dii, *dii; GdkDragAction action;
int dx, dy; GtkWidget *source_widget;
int i;
GList *l;
GSList *sel_icons, *sl;
/* FIXME: this needs to do the right thing (what Windows does) when desktop_auto_placement action = context->suggested_action; /* this is the default */
* is enabled.
*/
/* Find the icon that the user is dragging */ if (gdnd_drag_context_has_target (context, TARGET_MC_DESKTOP_ICON)) {
if (context->actions & GDK_ACTION_MOVE)
action = GDK_ACTION_MOVE;
} else if (gdnd_drag_context_has_target (context, TARGET_URI_LIST)) {
source_widget = gtk_drag_get_source_widget (context);
source_dii = find_icon_by_drag_context (context); /* If it comes from ourselves, make move the default */
if (!source_dii) { if (source_widget && (context->actions & GDK_ACTION_MOVE))
g_warning ("Eeeeek, could not find the icon that started the drag!"); action = GDK_ACTION_MOVE;
return; } else
} action = 0; /* we cannot handle that type of data */
/* Compute the distance to move icons */ gdk_drag_status (context, action, time);
return TRUE;
if (desktop_snap_icons)
get_icon_snap_pos (&x, &y);
dx = x - source_dii->x - dnd_press_x;
dy = y - source_dii->y - dnd_press_y;
/* Build a list of selected icons */
sel_icons = NULL;
for (i = 0; i < (layout_cols * layout_rows); i++)
for (l = layout_slots[i].icons; l; l = l->next) {
dii = l->data;
if (dii->selected)
sel_icons = g_slist_prepend (sel_icons, l->data);
}
/* Move the icons */
for (sl = sel_icons; sl; sl = sl->next) {
dii = sl->data;
desktop_icon_info_place (dii, FALSE, dii->x + dx, dii->y + dy);
}
/* Clean up */
g_slist_free (sel_icons);
} }
/* Callback used when the root window receives a drop */ /* Callback used when the root window receives a drop */
@ -1643,13 +1695,16 @@ setup_desktop_dnd (void)
g_warning ("There is already a process taking drop windows on the desktop\n"); g_warning ("There is already a process taking drop windows on the desktop\n");
gtk_drag_dest_set (dnd_proxy_window, gtk_drag_dest_set (dnd_proxy_window,
GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP, GTK_DEST_DEFAULT_DROP,
dnd_desktop_targets, dnd_desktop_targets,
dnd_desktop_ntargets, dnd_desktop_ntargets,
GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK | GDK_ACTION_ASK); GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK | GDK_ACTION_ASK);
gtk_signal_connect (GTK_OBJECT (dnd_proxy_window), "drag_motion",
(GtkSignalFunc) desktop_drag_motion,
NULL);
gtk_signal_connect (GTK_OBJECT (dnd_proxy_window), "drag_data_received", gtk_signal_connect (GTK_OBJECT (dnd_proxy_window), "drag_data_received",
GTK_SIGNAL_FUNC (desktop_drag_data_received), (GtkSignalFunc) desktop_drag_data_received,
NULL); NULL);
} }
@ -2141,6 +2196,7 @@ setup_desktop_clicks (void)
void void
desktop_init (void) desktop_init (void)
{ {
gdnd_init ();
create_layout_info (); create_layout_info ();
create_desktop_dir (); create_desktop_dir ();
reload_desktop_icons (0, 0); reload_desktop_icons (0, 0);

Просмотреть файл

@ -19,6 +19,31 @@
#include "gdnd.h" #include "gdnd.h"
/* Atoms for the DnD target types */
GdkAtom dnd_target_atoms[TARGET_NTARGETS];
/**
* gdnd_init:
*
* Initializes the dnd_target_atoms array by interning the DnD target atom names.
**/
void
gdnd_init (void)
{
dnd_target_atoms[TARGET_MC_DESKTOP_ICON] =
gdk_atom_intern (TARGET_MC_DESKTOP_ICON_TYPE, FALSE);
dnd_target_atoms[TARGET_URI_LIST] =
gdk_atom_intern (TARGET_URI_LIST_TYPE, FALSE);
dnd_target_atoms[TARGET_TEXT_PLAIN] =
gdk_atom_intern (TARGET_TEXT_PLAIN_TYPE, FALSE);
dnd_target_atoms[TARGET_URL] =
gdk_atom_intern (TARGET_URL_TYPE, FALSE);
}
/* The menu of DnD actions */ /* The menu of DnD actions */
static GnomeUIInfo actions[] = { static GnomeUIInfo actions[] = {
GNOMEUIINFO_ITEM_NONE (N_("Move here"), NULL, NULL), GNOMEUIINFO_ITEM_NONE (N_("Move here"), NULL, NULL),
@ -296,3 +321,28 @@ gdnd_drop_on_directory (GdkDragContext *context, GtkSelectionData *selection_dat
return TRUE; return TRUE;
} }
/**
* gdnd_drag_context_has_target:
* @context: The context to query for a target type
* @type: The sought target type
*
* Tests whether the specified drag context has a target of the specified type.
*
* Return value: TRUE if the context has the specified target type, FALSE
* otherwise.
**/
int
gdnd_drag_context_has_target (GdkDragContext *context, TargetType type)
{
GList *l;
g_return_val_if_fail (context != NULL, FALSE);
for (l = context->targets; l; l = l->next)
if (dnd_target_atoms[type] == GPOINTER_TO_INT (l->data))
return TRUE;
return FALSE;
}

Просмотреть файл

@ -13,16 +13,31 @@
/* Standard DnD types */ /* Standard DnD types */
enum { typedef enum {
TARGET_MC_DESKTOP_ICON, TARGET_MC_DESKTOP_ICON,
TARGET_URI_LIST, TARGET_URI_LIST,
TARGET_TEXT_PLAIN, TARGET_TEXT_PLAIN,
TARGET_URL TARGET_URL,
}; TARGET_NTARGETS
} TargetType;
/* DnD target names */
#define TARGET_MC_DESKTOP_ICON_TYPE "application/x-mc-desktop-icon"
#define TARGET_URI_LIST_TYPE "text/uri-list"
#define TARGET_TEXT_PLAIN_TYPE "text/plain"
#define TARGET_URL_TYPE "_NETSCAPE_URL"
/* Atoms for the DnD types, indexed per the enum above */
extern GdkAtom dnd_target_atoms[];
/* Initializes drag and drop by interning the target convenience atoms */
void gdnd_init (void);
/* Drop the list of URIs in the selection data to the specified directory */ /* Drop the list of URIs in the selection data to the specified directory */
int gdnd_drop_on_directory (GdkDragContext *context, GtkSelectionData *selection_data, char *dirname); int gdnd_drop_on_directory (GdkDragContext *context, GtkSelectionData *selection_data, char *dirname);
/* Test whether the specified context has a certain target type */
int gdnd_drag_context_has_target (GdkDragContext *context, TargetType type);
#endif #endif