Commit c2cfad09 authored by Pavel Cisler's avatar Pavel Cisler Committed by Pavel Cisler
Browse files

Clean fix up action handling - respect suggested actions, handle actions

2000-07-07  Pavel Cisler <pavel@eazel.com>

	* libnautilus-extensions/nautilus-drag.c:
	(nautilus_drag_default_drop_action),
	(nautilus_drag_drop_action_ask):
	Clean fix up action handling - respect suggested actions, handle
	actions better if they are different than GDK_ACTION_COPY and GDK_ACTION_MOVE.

	* libnautilus-extensions/nautilus-drag.c:
	(nautilus_drag_default_drop_action):
	Fix a crash in the new drop context menu when Cancel gets selected.

	* libnautilus-extensions/nautilus-drag.h:
	* libnautilus-extensions/nautilus-icon-container.c:
	(start_stretching), (button_release_event), (motion_notify_event),
	(show_context_menu_callback), (handle_icon_button_press):
	* libnautilus-extensions/nautilus-icon-dnd.c:
	(nautilus_icon_container_receive_dropped_icons),
	(nautilus_icon_container_get_drop_action):
	* libnautilus-extensions/nautilus-icon-private.h:
	Fix 1551 - Make drop context menu show up when drag started with
	right click. Turned out to be a bit harder than estimated.
	To do this I made the right-click context menu come up with a slight
	delay - a drag may be started if the mouse is moved before the delay
	expires.
	Renamed and reworked the click/drag state machine a bit.
parent e8e51dd2
2000-07-07 Pavel Cisler <pavel@eazel.com>
* libnautilus-extensions/nautilus-drag.c:
(nautilus_drag_default_drop_action),
(nautilus_drag_drop_action_ask):
Clean fix up action handling - respect suggested actions, handle
actions better if they are different than GDK_ACTION_COPY and GDK_ACTION_MOVE.
* libnautilus-extensions/nautilus-drag.c:
(nautilus_drag_default_drop_action):
Fix a crash in the new drop context menu when Cancel gets selected.
* libnautilus-extensions/nautilus-drag.h:
* libnautilus-extensions/nautilus-icon-container.c:
(start_stretching), (button_release_event), (motion_notify_event),
(show_context_menu_callback), (handle_icon_button_press):
* libnautilus-extensions/nautilus-icon-dnd.c:
(nautilus_icon_container_receive_dropped_icons),
(nautilus_icon_container_get_drop_action):
* libnautilus-extensions/nautilus-icon-private.h:
Fix 1551 - Make drop context menu show up when drag started with
right click. Turned out to be a bit harder than estimated.
To do this I made the right-click context menu come up with a slight
delay - a drag may be started if the mouse is moved before the delay
expires.
Renamed and reworked the click/drag state machine a bit.
2000-07-07 Ali Abdin <aliabdin@aucegypt.edu>
* components/html/ntl-web-browser.c:
......
......@@ -246,12 +246,14 @@ nautilus_drag_can_accept_items (NautilusFile *drop_target_item,
}
void
nautilus_drag_default_drop_action (const char *target_uri_string, const GList *items,
nautilus_drag_default_drop_action (GdkDragContext *context,
const char *target_uri_string, const GList *items,
int *default_action, int *non_default_action)
{
gboolean same_fs;
GnomeVFSURI *target_uri;
GnomeVFSURI *dropped_uri;
GdkDragAction actions;
if (target_uri_string == NULL) {
*default_action = 0;
......@@ -259,6 +261,17 @@ nautilus_drag_default_drop_action (const char *target_uri_string, const GList *i
return;
}
actions = context->actions & (GDK_ACTION_MOVE | GDK_ACTION_COPY);
if (actions != (GDK_ACTION_MOVE | GDK_ACTION_COPY)) {
/* We can't pick between copy and move, just
* go with the suggested action.
*/
*default_action = context->suggested_action;
*non_default_action = context->suggested_action;
return;
}
target_uri = gnome_vfs_uri_new (target_uri_string);
/* Compare the first dropped uri with the target uri for same fs match. */
......@@ -401,7 +414,7 @@ nautilus_drag_drop_action_ask (GdkDragAction actions)
break;
default:
action = -1;
action = 0;
}
gtk_widget_destroy (menu);
......
......@@ -102,7 +102,8 @@ gboolean nautilus_drag_can_accept_item (NautilusFile *drop_target_item,
const char *item_uri);
gboolean nautilus_drag_can_accept_items (NautilusFile *drop_target_item,
const GList *items);
void nautilus_drag_default_drop_action (const char *target_uri,
void nautilus_drag_default_drop_action (GdkDragContext *context,
const char *target_uri,
const GList *items,
int *default_action,
int *non_default_action);
......
......@@ -56,6 +56,8 @@
*/
#define KEYBOARD_ICON_REVEAL_TIMEOUT 300
#define CONTEXT_MENU_TIMEOUT_INTERVAL 500
/* Maximum amount of milliseconds the mouse button is allowed to stay down
* and still be considered a click.
*/
......@@ -1828,7 +1830,7 @@ start_stretching (NautilusIconContainer *container)
}
/* Set up the dragging. */
details->drag_action = DRAG_ACTION_STRETCH;
details->drag_state = DRAG_STATE_STRETCH;
gnome_canvas_w2c (GNOME_CANVAS (container),
details->drag_x,
details->drag_y,
......@@ -1921,20 +1923,27 @@ button_release_event (GtkWidget *widget,
if (event->button == details->drag_button) {
details->drag_button = 0;
switch (details->drag_action) {
case DRAG_ACTION_MOVE_OR_COPY:
switch (details->drag_state) {
case DRAG_STATE_MOVE_OR_COPY:
case DRAG_STATE_MOVE_COPY_OR_MENU:
if (!details->drag_started) {
nautilus_icon_container_did_not_drag (container, event);
} else {
nautilus_icon_dnd_end_drag (container);
}
break;
case DRAG_ACTION_STRETCH:
case DRAG_STATE_STRETCH:
end_stretching (container, event->x, event->y);
break;
default:
break;
}
details->drag_icon = NULL;
if (details->drag_state == DRAG_STATE_MOVE_COPY_OR_MENU) {
gtk_timeout_remove (details->context_menu_timeout_id);
}
details->drag_state = DRAG_STATE_INITIAL;
return TRUE;
}
......@@ -1953,8 +1962,15 @@ motion_notify_event (GtkWidget *widget,
details = container->details;
if (details->drag_button != 0) {
switch (details->drag_action) {
case DRAG_ACTION_MOVE_OR_COPY:
switch (details->drag_state) {
case DRAG_STATE_MOVE_COPY_OR_MENU:
if (details->drag_started) {
break;
}
gtk_timeout_remove (details->context_menu_timeout_id);
/* fall through */
case DRAG_STATE_MOVE_OR_COPY:
if (details->drag_started) {
break;
}
......@@ -1975,17 +1991,22 @@ motion_notify_event (GtkWidget *widget,
motion->y = details->drag_y;
nautilus_icon_dnd_begin_drag (container,
GDK_ACTION_MOVE
| GDK_ACTION_COPY
| GDK_ACTION_LINK
| GDK_ACTION_ASK,
details->drag_button,
motion);
details->drag_state == DRAG_STATE_MOVE_OR_COPY
? (GDK_ACTION_MOVE
| GDK_ACTION_COPY
| GDK_ACTION_LINK
| GDK_ACTION_ASK)
: GDK_ACTION_ASK,
details->drag_button,
motion);
details->drag_state = DRAG_STATE_MOVE_OR_COPY;
}
break;
case DRAG_ACTION_STRETCH:
case DRAG_STATE_STRETCH:
continue_stretching (container, motion->x, motion->y);
break;
default:
break;
}
}
......@@ -2420,6 +2441,33 @@ nautilus_icon_container_initialize (NautilusIconContainer *container)
container->details->type_select_state = NULL;
}
static gboolean
show_context_menu_callback (void *cast_to_container)
{
NautilusIconContainer *container;
container = (NautilusIconContainer *)cast_to_container;
g_assert (NAUTILUS_IS_ICON_CONTAINER (container));
if (container->details->drag_state != DRAG_STATE_MOVE_COPY_OR_MENU) {
/* button was released */
return TRUE;
}
container->details->drag_state = DRAG_STATE_INITIAL;
gtk_timeout_remove (container->details->context_menu_timeout_id);
/* Context menu applies to all selected items. The only
* odd case is if this click deselected the icon under
* the mouse, but at least the behavior is consistent.
*/
gtk_signal_emit (GTK_OBJECT (container),
signals[CONTEXT_CLICK_SELECTION]);
return TRUE;
}
/* NautilusIcon event handling. */
/* Conceptually, pressing button 1 together with CTRL or SHIFT toggles
......@@ -2430,6 +2478,7 @@ nautilus_icon_container_initialize (NautilusIconContainer *container)
* selected, because the user might select multiple icons and drag all
* of them by doing a simple click-drag.
*/
static gboolean
handle_icon_button_press (NautilusIconContainer *container,
NautilusIcon *icon,
......@@ -2444,12 +2493,14 @@ handle_icon_button_press (NautilusIconContainer *container,
details = container->details;
if (event->button == DRAG_BUTTON) {
if (event->button == DRAG_BUTTON
|| event->button == CONTEXTUAL_MENU_BUTTON) {
details->drag_button = event->button;
details->drag_icon = icon;
details->drag_x = event->x;
details->drag_y = event->y;
details->drag_action = DRAG_ACTION_MOVE_OR_COPY;
details->drag_state = event->button == DRAG_BUTTON
? DRAG_STATE_MOVE_OR_COPY : DRAG_STATE_MOVE_COPY_OR_MENU;
details->drag_started = FALSE;
/* Check to see if this is a click on the stretch handles.
......@@ -2460,6 +2511,15 @@ handle_icon_button_press (NautilusIconContainer *container,
return TRUE;
}
}
if (event->button == CONTEXTUAL_MENU_BUTTON) {
/* after a timeout we will decide if this is a
* context menu click or a drag start
*/
details->context_menu_timeout_id = gtk_timeout_add (
CONTEXT_MENU_TIMEOUT_INTERVAL,
show_context_menu_callback, container);
}
}
/* Modify the selection as appropriate. Selection is modified
......@@ -2476,24 +2536,7 @@ handle_icon_button_press (NautilusIconContainer *container,
signals[SELECTION_CHANGED]);
}
if (event->button == CONTEXTUAL_MENU_BUTTON) {
/* Note: this means you cannot drag with right click.
* If we decide we want right drags, we will have to
* set up a timeout and emit this signal if the
* timeout expires without movement.
*/
details->drag_button = 0;
details->drag_icon = NULL;
/* Context menu applies to all selected items. The only
* odd case is if this click deselected the icon under
* the mouse, but at least the behavior is consistent.
*/
gtk_signal_emit (GTK_OBJECT (container),
signals[CONTEXT_CLICK_SELECTION]);
} else if (event->type == GDK_2BUTTON_PRESS) {
if (event->type == GDK_2BUTTON_PRESS) {
/* Double clicking does not trigger a D&D action. */
details->drag_button = 0;
details->drag_icon = NULL;
......
......@@ -701,7 +701,7 @@ nautilus_icon_container_receive_dropped_icons (NautilusIconContainer *container,
(GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_LINK);
}
if (context->action >= 0) {
if (context->action > 0) {
gnome_canvas_window_to_world (GNOME_CANVAS (container),
x, y, &world_x, &world_y);
......@@ -755,7 +755,7 @@ nautilus_icon_container_get_drop_action (NautilusIconContainer *container,
*non_default_action = 0;
return;
}
nautilus_drag_default_drop_action (drop_target,
nautilus_drag_default_drop_action (context, drop_target,
container->details->dnd_info->drag_info.selection_list,
default_action, non_default_action);
g_free (drop_target);
......@@ -764,8 +764,8 @@ nautilus_icon_container_get_drop_action (NautilusIconContainer *container,
case NAUTILUS_ICON_DND_COLOR:
case NAUTILUS_ICON_DND_BGIMAGE:
case NAUTILUS_ICON_DND_KEYWORD:
*default_action = GDK_ACTION_MOVE;
*default_action = GDK_ACTION_MOVE;
*default_action = context->suggested_action;
*default_action = context->suggested_action;
break;
default:
......
......@@ -54,7 +54,6 @@ typedef struct {
nautilus_boolean_bit was_selected_before_rubberband : 1;
} NautilusIcon;
/* Private NautilusIconContainer members. */
......@@ -72,9 +71,11 @@ typedef struct {
} NautilusIconRubberbandInfo;
typedef enum {
DRAG_ACTION_MOVE_OR_COPY,
DRAG_ACTION_STRETCH
} DragAction;
DRAG_STATE_INITIAL,
DRAG_STATE_MOVE_OR_COPY,
DRAG_STATE_MOVE_COPY_OR_MENU,
DRAG_STATE_STRETCH
} DragState;
typedef struct {
/* Pointer position in canvas coordinates. */
......@@ -127,9 +128,10 @@ struct NautilusIconContainerDetails {
guint drag_button;
NautilusIcon *drag_icon;
int drag_x, drag_y;
DragAction drag_action;
DragState drag_state;
gboolean drag_started;
StretchState stretch_start;
int context_menu_timeout_id;
/* Renaming Details */
gboolean renaming;
......
......@@ -246,12 +246,14 @@ nautilus_drag_can_accept_items (NautilusFile *drop_target_item,
}
void
nautilus_drag_default_drop_action (const char *target_uri_string, const GList *items,
nautilus_drag_default_drop_action (GdkDragContext *context,
const char *target_uri_string, const GList *items,
int *default_action, int *non_default_action)
{
gboolean same_fs;
GnomeVFSURI *target_uri;
GnomeVFSURI *dropped_uri;
GdkDragAction actions;
if (target_uri_string == NULL) {
*default_action = 0;
......@@ -259,6 +261,17 @@ nautilus_drag_default_drop_action (const char *target_uri_string, const GList *i
return;
}
actions = context->actions & (GDK_ACTION_MOVE | GDK_ACTION_COPY);
if (actions != (GDK_ACTION_MOVE | GDK_ACTION_COPY)) {
/* We can't pick between copy and move, just
* go with the suggested action.
*/
*default_action = context->suggested_action;
*non_default_action = context->suggested_action;
return;
}
target_uri = gnome_vfs_uri_new (target_uri_string);
/* Compare the first dropped uri with the target uri for same fs match. */
......@@ -401,7 +414,7 @@ nautilus_drag_drop_action_ask (GdkDragAction actions)
break;
default:
action = -1;
action = 0;
}
gtk_widget_destroy (menu);
......
......@@ -102,7 +102,8 @@ gboolean nautilus_drag_can_accept_item (NautilusFile *drop_target_item,
const char *item_uri);
gboolean nautilus_drag_can_accept_items (NautilusFile *drop_target_item,
const GList *items);
void nautilus_drag_default_drop_action (const char *target_uri,
void nautilus_drag_default_drop_action (GdkDragContext *context,
const char *target_uri,
const GList *items,
int *default_action,
int *non_default_action);
......
......@@ -56,6 +56,8 @@
*/
#define KEYBOARD_ICON_REVEAL_TIMEOUT 300
#define CONTEXT_MENU_TIMEOUT_INTERVAL 500
/* Maximum amount of milliseconds the mouse button is allowed to stay down
* and still be considered a click.
*/
......@@ -1828,7 +1830,7 @@ start_stretching (NautilusIconContainer *container)
}
/* Set up the dragging. */
details->drag_action = DRAG_ACTION_STRETCH;
details->drag_state = DRAG_STATE_STRETCH;
gnome_canvas_w2c (GNOME_CANVAS (container),
details->drag_x,
details->drag_y,
......@@ -1921,20 +1923,27 @@ button_release_event (GtkWidget *widget,
if (event->button == details->drag_button) {
details->drag_button = 0;
switch (details->drag_action) {
case DRAG_ACTION_MOVE_OR_COPY:
switch (details->drag_state) {
case DRAG_STATE_MOVE_OR_COPY:
case DRAG_STATE_MOVE_COPY_OR_MENU:
if (!details->drag_started) {
nautilus_icon_container_did_not_drag (container, event);
} else {
nautilus_icon_dnd_end_drag (container);
}
break;
case DRAG_ACTION_STRETCH:
case DRAG_STATE_STRETCH:
end_stretching (container, event->x, event->y);
break;
default:
break;
}
details->drag_icon = NULL;
if (details->drag_state == DRAG_STATE_MOVE_COPY_OR_MENU) {
gtk_timeout_remove (details->context_menu_timeout_id);
}
details->drag_state = DRAG_STATE_INITIAL;
return TRUE;
}
......@@ -1953,8 +1962,15 @@ motion_notify_event (GtkWidget *widget,
details = container->details;
if (details->drag_button != 0) {
switch (details->drag_action) {
case DRAG_ACTION_MOVE_OR_COPY:
switch (details->drag_state) {
case DRAG_STATE_MOVE_COPY_OR_MENU:
if (details->drag_started) {
break;
}
gtk_timeout_remove (details->context_menu_timeout_id);
/* fall through */
case DRAG_STATE_MOVE_OR_COPY:
if (details->drag_started) {
break;
}
......@@ -1975,17 +1991,22 @@ motion_notify_event (GtkWidget *widget,
motion->y = details->drag_y;
nautilus_icon_dnd_begin_drag (container,
GDK_ACTION_MOVE
| GDK_ACTION_COPY
| GDK_ACTION_LINK
| GDK_ACTION_ASK,
details->drag_button,
motion);
details->drag_state == DRAG_STATE_MOVE_OR_COPY
? (GDK_ACTION_MOVE
| GDK_ACTION_COPY
| GDK_ACTION_LINK
| GDK_ACTION_ASK)
: GDK_ACTION_ASK,
details->drag_button,
motion);
details->drag_state = DRAG_STATE_MOVE_OR_COPY;
}
break;
case DRAG_ACTION_STRETCH:
case DRAG_STATE_STRETCH:
continue_stretching (container, motion->x, motion->y);
break;
default:
break;
}
}
......@@ -2420,6 +2441,33 @@ nautilus_icon_container_initialize (NautilusIconContainer *container)
container->details->type_select_state = NULL;
}
static gboolean
show_context_menu_callback (void *cast_to_container)
{
NautilusIconContainer *container;
container = (NautilusIconContainer *)cast_to_container;
g_assert (NAUTILUS_IS_ICON_CONTAINER (container));
if (container->details->drag_state != DRAG_STATE_MOVE_COPY_OR_MENU) {
/* button was released */
return TRUE;
}
container->details->drag_state = DRAG_STATE_INITIAL;
gtk_timeout_remove (container->details->context_menu_timeout_id);
/* Context menu applies to all selected items. The only
* odd case is if this click deselected the icon under
* the mouse, but at least the behavior is consistent.
*/
gtk_signal_emit (GTK_OBJECT (container),
signals[CONTEXT_CLICK_SELECTION]);
return TRUE;
}
/* NautilusIcon event handling. */
/* Conceptually, pressing button 1 together with CTRL or SHIFT toggles
......@@ -2430,6 +2478,7 @@ nautilus_icon_container_initialize (NautilusIconContainer *container)
* selected, because the user might select multiple icons and drag all
* of them by doing a simple click-drag.
*/
static gboolean
handle_icon_button_press (NautilusIconContainer *container,
NautilusIcon *icon,
......@@ -2444,12 +2493,14 @@ handle_icon_button_press (NautilusIconContainer *container,
details = container->details;
if (event->button == DRAG_BUTTON) {
if (event->button == DRAG_BUTTON
|| event->button == CONTEXTUAL_MENU_BUTTON) {
details->drag_button = event->button;
details->drag_icon = icon;
details->drag_x = event->x;
details->drag_y = event->y;
details->drag_action = DRAG_ACTION_MOVE_OR_COPY;
details->drag_state = event->button == DRAG_BUTTON
? DRAG_STATE_MOVE_OR_COPY : DRAG_STATE_MOVE_COPY_OR_MENU;
details->drag_started = FALSE;
/* Check to see if this is a click on the stretch handles.
......@@ -2460,6 +2511,15 @@ handle_icon_button_press (NautilusIconContainer *container,
return TRUE;
}
}
if (event->button == CONTEXTUAL_MENU_BUTTON) {
/* after a timeout we will decide if this is a
* context menu click or a drag start
*/
details->context_menu_timeout_id = gtk_timeout_add (
CONTEXT_MENU_TIMEOUT_INTERVAL,
show_context_menu_callback, container);
}
}
/* Modify the selection as appropriate. Selection is modified
......@@ -2476,24 +2536,7 @@ handle_icon_button_press (NautilusIconContainer *container,
signals[SELECTION_CHANGED]);
}
if (event->button == CONTEXTUAL_MENU_BUTTON) {
/* Note: this means you cannot drag with right click.
* If we decide we want right drags, we will have to
* set up a timeout and emit this signal if the
* timeout expires without movement.
*/
details->drag_button = 0;
details->drag_icon = NULL;
/* Context menu applies to all selected items. The only
* odd case is if this click deselected the icon under
* the mouse, but at least the behavior is consistent.
*/
gtk_signal_emit (GTK_OBJECT (container),
signals[CONTEXT_CLICK_SELECTION]);
} else if (event->type == GDK_2BUTTON_PRESS) {
if (event->type == GDK_2BUTTON_PRESS) {
/* Double clicking does not trigger a D&D action. */
details->drag_button = 0;
details->drag_icon = NULL;
......
<
......@@ -701,7 +701,7 @@ nautilus_icon_container_receive_dropped_icons (NautilusIconContainer *container,
(GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_LINK);
}
if (context->action >= 0) {
if (context->action > 0) {
gnome_canvas_window_to_world (GNOME_CANVAS (container),
x, y, &world_x, &world_y);
......@@ -755,7 +755,7 @@ nautilus_icon_container_get_drop_action (NautilusIconContainer *container,
*non_default_action = 0;
return;
}
nautilus_drag_default_drop_action (drop_target,
nautilus_drag_default_drop_action (context, drop_target,
container->details->dnd_info->drag_info.selection_list,
default_action, non_default_action);
g_free (drop_target);
......@@ -764,8 +764,8 @@ nautilus_icon_container_get_drop_action (NautilusIconContainer *container,
case NAUTILUS_ICON_DND_COLOR:
case NAUTILUS_ICON_DND_BGIMAGE:
case NAUTILUS_ICON_DND_KEYWORD:
*default_action = GDK_ACTION_MOVE;
*default_action = GDK_ACTION_MOVE;
*default_action = context->suggested_action;