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

* gscreen.c (panel_setup_drag_scroll): Renamed from
	panel_setup_drag_motion().
	(panel_clist_drag_motion): Use gdnd_validate_action().
	(panel_clist_motion): Return immediately if the event window is
	not the clist_window.  Otherwise, forward the event to
	panel_widget_motion().

	* gdnd.c (gdnd_find_panel_by_drag_context): New public function to
	find a panel based on a drag context.  This is basically the old
	find_panel_owning_window() made public.
	(gdnd_drop_on_directory): Test for the source widget being a tree,
	and if so, do not use the default behavior for panels.
	(gdnd_validate_action): New function to compute the final drag
	action given some conditions.  This is now used to make dragging
	behavior consistent across the desktop and the file panels.
This commit is contained in:
Miguel de Icaza 1999-01-26 06:53:48 +00:00
parent 83ab2a7f65
commit f97cb04b55
5 changed files with 239 additions and 88 deletions

View File

@ -1,3 +1,21 @@
1999-01-26 Federico Mena Quintero <federico@nuclecu.unam.mx>
* gscreen.c (panel_setup_drag_scroll): Renamed from
panel_setup_drag_motion().
(panel_clist_drag_motion): Use gdnd_validate_action().
(panel_clist_motion): Return immediately if the event window is
not the clist_window. Otherwise, forward the event to
panel_widget_motion().
* gdnd.c (gdnd_find_panel_by_drag_context): New public function to
find a panel based on a drag context. This is basically the old
find_panel_owning_window() made public.
(gdnd_drop_on_directory): Test for the source widget being a tree,
and if so, do not use the default behavior for panels.
(gdnd_validate_action): New function to compute the final drag
action given some conditions. This is now used to make dragging
behavior consistent across the desktop and the file panels.
1999-01-26 Jonathan Blandford <jrb@redhat.com>
* gnome-file-property-dialog.c: Many Many Many changes. Now it's
@ -11,6 +29,15 @@
1999-01-25 Federico Mena Quintero <federico@nuclecu.unam.mx>
* gscreen.c (panel_create_icon_display): Only use
GTK_DEST_DEFAULT_DROP since we want to do exotic stuff in the
drag_motion handler to validate drops.
(panel_icon_list_drag_motion): Use gdnd_validate_action().
* gdnd.c (gdnd_drop_on_directory): Removed hack that prevented the
user from dropping files on the same panel as the source one.
This should not be done here.
* gdnd.c (get_action): Sensitize the menu items based on the
allowed actions in the drag context.
(actions): Add some underlined accelerators for the action menu.

View File

@ -1645,6 +1645,12 @@ desktop_drag_motion (GtkWidget *widget, GdkDragContext *context, gint x, gint y,
/* If it comes from ourselves, make move the default unless the
* user is explicitly asking for ASK.
*/
printf ("%s\t%s\t%s\t%s\n",
(context->actions & GDK_ACTION_COPY) ? "copy" : "",
(context->actions & GDK_ACTION_MOVE) ? "move" : "",
(context->actions & GDK_ACTION_LINK) ? "link" : "",
(context->actions & GDK_ACTION_ASK) ? "ask" : "");
if (source_widget
&& context->suggested_action != GDK_ACTION_ASK
&& (context->actions & GDK_ACTION_MOVE))

View File

@ -96,56 +96,6 @@ get_action (GdkDragContext *context)
return action;
}
/*
* Looks for a panel that has the specified window for its list
* display. It is used to figure out if we are receiving a drop from
* a panel on this MC process. If no panel is found, it returns NULL.
*/
static WPanel *
find_panel_owning_window (GdkDragContext *context)
{
GList *list;
WPanel *panel;
GtkWidget *source_widget, *toplevel_widget;
source_widget = gtk_drag_get_source_widget (context);
if (!source_widget)
return NULL;
/*
* We will scan the list of existing WPanels. We
* uniformize the thing by pulling the toplevel
* widget for each WPanel and compare this to the
* toplevel source_widget
*/
toplevel_widget = gtk_widget_get_toplevel (source_widget);
for (list = containers; list; list = list->next) {
GtkWidget *panel_toplevel_widget;
panel = ((PanelContainer *) list->data)->panel;
panel_toplevel_widget = panel->xwindow;
if (panel->xwindow == toplevel_widget){
/*
* Now a WPanel actually contains a number of
* drag sources. If the drag source is the
* Tree, we must report that it was not the
* contents of the WPanel
*/
if (source_widget == panel->tree)
return NULL;
return panel;
}
}
return NULL;
}
/*
* Performs a drop action on the specified panel. Only supports copy
* and move operations. The files are moved or copied to the
@ -292,6 +242,7 @@ gdnd_drop_on_directory (GdkDragContext *context, GtkSelectionData *selection_dat
{
GdkDragAction action;
WPanel *source_panel;
GtkWidget *source_widget;
GList *names;
if (context->action == GDK_ACTION_ASK) {
@ -303,14 +254,12 @@ gdnd_drop_on_directory (GdkDragContext *context, GtkSelectionData *selection_dat
} else
action = context->action;
/* If we are dragging from a file panel, we can display a nicer status display */
source_panel = find_panel_owning_window (context);
/* Check if the user did not drag the information to the same directory */
if (source_panel) {
if (strcmp (source_panel->cwd, destdir) == 0)
return FALSE;
}
/* If we are dragging from a file panel, we can display a nicer status
* display. But if the drag was from the tree, we cannot do this.
*/
source_panel = gdnd_find_panel_by_drag_context (context, &source_widget);
if (source_widget == source_panel->tree)
source_panel = NULL;
/* Symlinks do not use file.c */
@ -355,3 +304,98 @@ gdnd_drag_context_has_target (GdkDragContext *context, TargetType type)
return FALSE;
}
/**
* gdnd_find_panel_by_drag_context:
* @context: The context by which to find a panel.
* @source_widget: The source widget is returned here.
*
* Looks in the list of panels for the one that corresponds to the specified
* drag context.
*
* Return value: The sought panel, or NULL if no panel corresponds to the
* context.
**/
WPanel *
gdnd_find_panel_by_drag_context (GdkDragContext *context, GtkWidget **source_widget)
{
GtkWidget *source;
GtkWidget *toplevel;
GList *l;
WPanel *panel;
g_return_val_if_fail (context != NULL, NULL);
source = gtk_drag_get_source_widget (context);
if (source_widget)
*source_widget = source;
if (!source)
return NULL; /* different process */
toplevel = gtk_widget_get_toplevel (source);
for (l = containers; l; l = l->next) {
panel = ((PanelContainer *) l->data)->panel;
if (panel->xwindow == toplevel)
return panel;
}
return NULL;
}
/**
* gdnd_validate_action:
* @context: The drag context for this drag operation.
* @same_process: Whether the drag comes from the same process or not.
* @same_source: If same_process, then whether the source and dest widgets are the same.
* @dest: The destination file entry, or NULL if dropping on empty space.
* @dest_selected: If dest is non-NULL, whether it is selected or not.
*
* Computes the final drag action based on the suggested action of the specified
* context and conditions.
*
* Return value: The computed action, meant to be passed to gdk_drag_action().
**/
GdkDragAction
gdnd_validate_action (GdkDragContext *context, int same_process, int same_source,
file_entry *dest_fe, int dest_selected)
{
int on_directory;
int on_exe;
if (dest_fe) {
on_directory = dest_fe->f.link_to_dir || S_ISDIR (dest_fe->buf.st_mode);
on_exe = is_exe (dest_fe->buf.st_mode) && if_link_is_exe (dest_fe);
}
if (dest_fe) {
if (same_source && dest_selected)
return 0;
if (on_directory) {
if ((same_source || same_process) && (context->actions & GDK_ACTION_MOVE))
return GDK_ACTION_MOVE;
else
return context->suggested_action;
} else if (on_exe) {
if (context->actions & GDK_ACTION_COPY)
return GDK_ACTION_COPY;
} else if (same_source)
return 0;
else if (same_process && (context->actions & GDK_ACTION_MOVE))
return GDK_ACTION_MOVE;
else
return context->suggested_action;
} else {
if (same_source)
return 0;
else if (same_process && (context->actions & GDK_ACTION_MOVE))
return GDK_ACTION_MOVE;
else
return context->suggested_action;
}
return 0;
}

View File

@ -10,6 +10,7 @@
#define GDND_H
#include <gtk/gtk.h>
#include "panel.h"
/* Standard DnD types */
@ -40,4 +41,14 @@ int gdnd_drop_on_directory (GdkDragContext *context, GtkSelectionData *selection
/* Test whether the specified context has a certain target type */
int gdnd_drag_context_has_target (GdkDragContext *context, TargetType type);
/* Look for a panel that corresponds to the specified drag context */
WPanel *gdnd_find_panel_by_drag_context (GdkDragContext *context, GtkWidget **source_widget);
/* Computes the final drag action based on the suggested actions and the
* specified conditions.
*/
GdkDragAction gdnd_validate_action (GdkDragContext *context, int same_process, int same_source,
file_entry *dest_fe, int dest_selected);
#endif

View File

@ -601,7 +601,7 @@ typedef gboolean (*desirable_fn)(WPanel *p, int x, int y);
typedef gboolean (*scroll_fn)(gpointer data);
static gboolean
panel_setup_drag_motion (WPanel *panel, int x, int y, desirable_fn desirable, scroll_fn scroll)
panel_setup_drag_scroll (WPanel *panel, int x, int y, desirable_fn desirable, scroll_fn scroll)
{
if (panel->timer_id != -1){
gtk_timeout_remove (panel->timer_id);
@ -911,7 +911,7 @@ panel_widget_motion (GtkWidget *widget, GdkEventMotion *event, WPanel *panel)
{
GtkTargetList *list;
GdkDragContext *context;
if (!panel->maybe_start_drag)
return FALSE;
@ -952,6 +952,18 @@ panel_drag_end (GtkWidget *widget, GdkDragContext *context, WPanel *panel)
panel->dragging = 0;
}
/* Wrapper for the motion_notify callback; it ignores motion events from the
* clist if they do not come from the clist_window.
*/
static int
panel_clist_motion (GtkWidget *widget, GdkEventMotion *event, gpointer data)
{
if (event->window != GTK_CLIST (widget)->clist_window)
return FALSE;
return panel_widget_motion (widget, event, data);
}
/**
* panel_clist_scrolling_is_desirable:
*
@ -1011,25 +1023,50 @@ panel_clist_scroll (gpointer data)
return TRUE;
}
/**
* panel_clist_drag_motion:
*
* Invoked when an application dragging over us has the the cursor moved.
* If we are close to the top or bottom, we scroll the window
/* Callback used for drag motion events over the clist. We set up
* auto-scrolling and validate the drop to present the user with the correct
* feedback.
*/
static gboolean
panel_clist_drag_motion (GtkWidget *widget, GdkDragContext *ctx, int x, int y, guint time, void *data)
panel_clist_drag_motion (GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time,
gpointer data)
{
WPanel *panel = data;
WPanel *panel;
GdkDragAction action;
GtkWidget *source_widget;
gint idx;
file_entry *fe;
if (ctx->dest_window != GTK_CLIST (widget)->clist_window)
gdk_drag_status (ctx, 0, time);
else {
panel_setup_drag_motion (panel, x, y,
panel_clist_scrolling_is_desirable, panel_clist_scroll);
gdk_drag_status (ctx, ctx->suggested_action, time);
panel = data;
if (context->dest_window != GTK_CLIST (widget)->clist_window) {
printf ("squick\n");
gdk_drag_status (context, 0, time);
return TRUE;
}
/* Set up auto-scrolling */
panel_setup_drag_scroll (panel, x, y,
panel_clist_scrolling_is_desirable,
panel_clist_scroll);
/* Validate the drop */
gdnd_find_panel_by_drag_context (context, &source_widget);
if (!gtk_clist_get_selection_info (GTK_CLIST (widget), x, y, &idx, NULL))
fe = NULL;
else
fe = &panel->dir.list[idx];
action = gdnd_validate_action (context,
source_widget != NULL,
source_widget == widget,
fe,
fe ? fe->f.marked : FALSE);
gdk_drag_status (context, action, time);
return TRUE;
}
@ -1108,18 +1145,42 @@ panel_icon_list_scroll (gpointer data)
return TRUE;
}
/**
* panel_icon_list_drag_motion:
*
* Invoked when an application dragging over us has the the cursor moved.
* If we are close to the top or bottom, we scroll the window
/* Callback used for drag motion events in the icon list. We need to set up
* auto-scrolling and validate the drop to present the user with the correct
* feedback.
*/
static gboolean
panel_icon_list_drag_motion (GtkWidget *widget, GdkDragContext *ctx, int x, int y, guint time, void *data)
panel_icon_list_drag_motion (GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time,
gpointer data)
{
WPanel *panel = data;
panel_setup_drag_motion (panel, x, y, panel_icon_list_scrolling_is_desirable, panel_icon_list_scroll);
WPanel *panel;
GdkDragAction action;
GtkWidget *source_widget;
int idx;
file_entry *fe;
panel = data;
/* Set up auto-scrolling */
panel_setup_drag_scroll (panel, x, y,
panel_icon_list_scrolling_is_desirable,
panel_icon_list_scroll);
/* Validate the drop */
gdnd_find_panel_by_drag_context (context, &source_widget);
idx = gnome_icon_list_get_icon_at (GNOME_ICON_LIST (widget), x, y);
fe = (idx == -1) ? NULL : &panel->dir.list[idx];
action = gdnd_validate_action (context,
source_widget != NULL,
source_widget == widget,
fe,
fe ? fe->f.marked : FALSE);
gdk_drag_status (context, action, time);
return TRUE;
}
@ -1189,15 +1250,16 @@ panel_create_file_list (WPanel *panel)
load_dnd_icons ();
gtk_drag_dest_set (GTK_WIDGET (file_list), GTK_DEST_DEFAULT_DROP,
gtk_drag_dest_set (GTK_WIDGET (file_list),
GTK_DEST_DEFAULT_DROP,
drop_types, ELEMENTS (drop_types),
GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK | GDK_ACTION_ASK);
#if 0
/* Make directories draggable */
gtk_drag_source_set (GTK_WIDGET (file_list), GDK_BUTTON1_MASK | GDK_BUTTON2_MASK,
drag_types, ELEMENTS (drag_types),
GDK_ACTION_LINK | GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_ASK);
#endif
gtk_signal_connect (GTK_OBJECT (file_list), "drag_data_get",
GTK_SIGNAL_FUNC (panel_drag_data_get), panel);
gtk_signal_connect (GTK_OBJECT (file_list), "drag_data_delete",
@ -1226,7 +1288,7 @@ panel_create_file_list (WPanel *panel)
GTK_SIGNAL_FUNC (panel_clist_button_release), panel);
gtk_signal_connect (GTK_OBJECT (file_list), "motion_notify_event",
GTK_SIGNAL_FUNC (panel_widget_motion), panel);
GTK_SIGNAL_FUNC (panel_clist_motion), panel);
gtk_signal_connect (GTK_OBJECT (file_list), "drag_begin",
GTK_SIGNAL_FUNC (panel_drag_begin), panel);
gtk_signal_connect (GTK_OBJECT (file_list), "drag_end",
@ -1385,7 +1447,8 @@ panel_create_icon_display (WPanel *panel)
load_imlib_icons ();
load_dnd_icons ();
gtk_drag_dest_set (GTK_WIDGET (ilist), GTK_DEST_DEFAULT_ALL,
gtk_drag_dest_set (GTK_WIDGET (ilist),
GTK_DEST_DEFAULT_DROP,
drop_types, ELEMENTS (drop_types),
GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK | GDK_ACTION_ASK);
@ -1918,7 +1981,7 @@ panel_tree_drag_motion (GtkWidget *widget, GdkDragContext *ctx, int x, int y, gu
WPanel *panel = data;
int r, row, col;
if (panel_setup_drag_motion (panel, x, y, panel_tree_scrolling_is_desirable, panel_tree_scroll))
if (panel_setup_drag_scroll (panel, x, y, panel_tree_scrolling_is_desirable, panel_tree_scroll))
return TRUE;
r = gtk_clist_get_selection_info (