コード例 #1
0
ファイル: panel.c プロジェクト: JonahAragon/consort-panel
static gboolean
panel_check_drop_forbidden (PanelWidget    *panel,
			    GdkDragContext *context,
			    guint           info,
			    guint           time_)
{
	if (!panel)
		return FALSE;

	if (panel_lockdown_get_panels_locked_down_s ())
		return FALSE;

	if (info == TARGET_ICON_INTERNAL ||
	    info == TARGET_APPLET_INTERNAL) {
		if (gdk_drag_context_get_actions (context) & GDK_ACTION_MOVE)
			gdk_drag_status (context, GDK_ACTION_MOVE, time_);
		else
			gdk_drag_status (context,
					 gdk_drag_context_get_suggested_action (context),
					 time_);

	} else if (gdk_drag_context_get_actions (context) & GDK_ACTION_COPY)
		gdk_drag_status (context, GDK_ACTION_COPY, time_);
	else
		gdk_drag_status (context,
				 gdk_drag_context_get_suggested_action (context),
				 time_);

	return TRUE;

}
コード例 #2
0
ファイル: panel.c プロジェクト: fanpenggogo/mate-panel-new
gboolean
panel_check_dnd_target_data (GtkWidget      *widget,
			     GdkDragContext *context,
			     guint          *ret_info,
			     GdkAtom        *ret_atom)
{
	GList *l;

	g_return_val_if_fail (widget, FALSE);

	if (!PANEL_IS_TOPLEVEL  (widget) &&
	    !BUTTON_IS_WIDGET (widget))
		return FALSE;

	if (!(gdk_drag_context_get_actions (context) & (GDK_ACTION_COPY|GDK_ACTION_MOVE)))
		return FALSE;

	for (l = gdk_drag_context_list_targets (context); l; l = l->next) {
		GdkAtom atom;
		guint   info;

		atom = GDK_POINTER_TO_ATOM (l->data);

		if (gtk_target_list_find (get_target_list (), atom, &info)) {
			if (ret_info)
				*ret_info = info;

			if (ret_atom)
				*ret_atom = atom;
			break;
		}
	}

	return l ? TRUE : FALSE;
}
コード例 #3
0
static gboolean
is_this_drop_ok (GtkWidget      *widget,
		 GdkDragContext *context)
{
	static GdkAtom  text_uri_list = GDK_NONE;
	GList           *l;
	GtkWidget       *source;

	source = gtk_drag_get_source_widget (context);

	if (source == widget)
		return FALSE;

	if (!(gdk_drag_context_get_actions (context) & GDK_ACTION_COPY))
		return FALSE;

	if (!text_uri_list)
		text_uri_list = gdk_atom_intern_static_string ("text/uri-list");

	for (l = gdk_drag_context_list_targets (context); l; l = l->next) {
		if (GDK_POINTER_TO_ATOM (l->data) == text_uri_list)
			break;
	}

	return l ? TRUE : FALSE;
}
コード例 #4
0
ファイル: panel.c プロジェクト: fanpenggogo/mate-panel-new
gboolean
panel_check_drop_forbidden (PanelWidget    *panel,
			    GdkDragContext *context,
			    guint           info,
			    guint           time_)
{
	if (!panel)
		return FALSE;

	if (panel_lockdown_get_locked_down ())
		return FALSE;

	if (info == TARGET_APPLET_INTERNAL) {
		GtkWidget *source_widget;

		source_widget = gtk_drag_get_source_widget (context);

		if (BUTTON_IS_WIDGET (source_widget)) {
			GSList *forb;

			forb = g_object_get_data (G_OBJECT (source_widget),
						  MATE_PANEL_APPLET_FORBIDDEN_PANELS);

			if (g_slist_find (forb, panel))
				return FALSE;
		}
	}

	if (info == TARGET_ICON_INTERNAL ||
	    info == TARGET_APPLET_INTERNAL) {
		if (gdk_drag_context_get_actions (context) & GDK_ACTION_MOVE)
			gdk_drag_status (context, GDK_ACTION_MOVE, time_);
		else
			gdk_drag_status (context,
					 gdk_drag_context_get_suggested_action (context),
					 time_);

	} else if (gdk_drag_context_get_actions (context) & GDK_ACTION_COPY)
		gdk_drag_status (context, GDK_ACTION_COPY, time_);
	else
		gdk_drag_status (context,
				 gdk_drag_context_get_suggested_action (context),
				 time_);

	return TRUE;

}
コード例 #5
0
ファイル: dnd.cpp プロジェクト: 0ryuO/dolphin-avsync
wxDragResult wxDropTarget::GTKFigureOutSuggestedAction()
{
    if (!m_dragContext)
        return wxDragError;

    // GTK+ always supposes that we want to copy the data by default while we
    // might want to move it, so examine not only suggested_action - which is
    // only good if we don't have our own preferences - but also the actions
    // field
    wxDragResult suggested_action = wxDragNone;
    const GdkDragAction actions = gdk_drag_context_get_actions(m_dragContext);
    if (GetDefaultAction() == wxDragNone)
    {
        // use default action set by wxDropSource::DoDragDrop()
        if ( (gs_flagsForDrag & wxDrag_DefaultMove) == wxDrag_DefaultMove &&
            (actions & GDK_ACTION_MOVE))
        {
            // move is requested by the program and allowed by GTK+ - do it, even
            // though suggested_action may be currently wxDragCopy
            suggested_action = wxDragMove;
        }
        else // use whatever GTK+ says we should
        {
            suggested_action = ConvertFromGTK(gdk_drag_context_get_suggested_action(m_dragContext));

#if 0
            // RR: I don't understand the code below: if the drag comes from
            //     a different app, the gs_flagsForDrag is invalid; if it
            //     comes from the same wx app, then GTK+ hopefully won't
            //     suggest something we didn't allow in the frist place
            //     in DoDrop()
            if ( (suggested_action == wxDragMove) && !(gs_flagsForDrag & wxDrag_AllowMove) )
            {
                // we're requested to move but we can't
                suggested_action = wxDragCopy;
            }
#endif
        }
    }
    else if (GetDefaultAction() == wxDragMove &&
            (actions & GDK_ACTION_MOVE))
    {

        suggested_action = wxDragMove;
    }
    else
    {
        if (actions & GDK_ACTION_COPY)
            suggested_action = wxDragCopy;
        else if (actions & GDK_ACTION_MOVE)
            suggested_action = wxDragMove;
        else if (actions & GDK_ACTION_LINK)
            suggested_action = wxDragLink;
        else
            suggested_action = wxDragNone;
    }

    return suggested_action;
}
コード例 #6
0
GdkDragAction
athena_drag_default_drop_action_for_uri_list (GdkDragContext *context,
						const char *target_uri_string)
{
	if (eel_uri_is_trash (target_uri_string) && (gdk_drag_context_get_actions (context) & GDK_ACTION_MOVE)) {
		/* Only move to Trash */
		return GDK_ACTION_MOVE;
	} else {
		return gdk_drag_context_get_suggested_action (context);
	}
}
コード例 #7
0
GdkDragAction
athena_drag_default_drop_action_for_netscape_url (GdkDragContext *context)
{
	/* Mozilla defaults to copy, but unless thats the
	   only allowed thing (enforced by ctrl) we want to LINK */
	if (gdk_drag_context_get_suggested_action (context) == GDK_ACTION_COPY &&
	    gdk_drag_context_get_actions (context) != GDK_ACTION_COPY) {
		return GDK_ACTION_LINK;
	} else if (gdk_drag_context_get_suggested_action (context) == GDK_ACTION_MOVE) {
		/* Don't support move */
		return GDK_ACTION_COPY;
	}
	
	return gdk_drag_context_get_suggested_action (context);
}
コード例 #8
0
static gboolean
gstyle_color_widget_on_drag_motion (GtkWidget      *widget,
                                    GdkDragContext *context,
                                    gint            x,
                                    gint            y,
                                    guint           time)
{
  GstyleColorWidget *self = (GstyleColorWidget *)widget;
  GstylePaletteWidgetDndLockFlags dnd_lock;
  GdkAtom target;
  GdkDragAction drag_action;

  g_assert (GSTYLE_IS_COLOR_WIDGET (self));
  g_assert (GDK_IS_DRAG_CONTEXT (context));

  target = gtk_drag_dest_find_target (widget, context, NULL);
  dnd_lock = get_palette_widget_dnd_lock (self);
  if ((dnd_lock & GSTYLE_PALETTE_WIDGET_DND_LOCK_FLAGS_DRAG) != 0)
    {
      gdk_drag_status (context, 0, time);
      return FALSE;
    }

  if ((target == gdk_atom_intern_static_string ("GSTYLE_COLOR_WIDGET") ||
       target == gdk_atom_intern_static_string ("application/x-color") ||
       gtk_targets_include_text (&target, 1)) &&
      (dnd_lock & GSTYLE_PALETTE_WIDGET_DND_LOCK_FLAGS_DROP) == 0 &&
      is_in_drop_zone (self, x, y))
    {
      gtk_drag_highlight (widget);

      drag_action = gdk_drag_context_get_actions (context);
      if ((drag_action | GDK_ACTION_COPY) != 0)
        {
          gdk_drag_status (context, GDK_ACTION_COPY, time);
          return TRUE;
        }
    }

  gdk_drag_status (context, 0, time);
  return FALSE;
}
コード例 #9
0
static void dispatchEvent(GdkEvent* event)
{
    webkit_web_frame_layout(mainFrame);
    WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
    if (!view) {
        gdk_event_free(event);
        return;
    }

    gtk_main_do_event(event);

    if (!currentDragSourceContext) {
        gdk_event_free(event);
        return;
    }

    if (event->type == GDK_MOTION_NOTIFY) {
        // WebKit has called gtk_drag_start(), but because the main loop isn't
        // running GDK internals don't know that the drag has started yet. Pump
        // the main loop a little bit so that GDK is in the correct state.
        while (gtk_events_pending())
            gtk_main_iteration();

        // Simulate a drag motion on the top-level GDK window.
        GtkWidget* parentWidget = gtk_widget_get_parent(GTK_WIDGET(view));
        GdkWindow* parentWidgetWindow = gtk_widget_get_window(parentWidget);
        gdk_drag_motion(currentDragSourceContext, parentWidgetWindow, GDK_DRAG_PROTO_XDND,
            event->motion.x_root, event->motion.y_root,
            gdk_drag_context_get_selected_action(currentDragSourceContext),
            gdk_drag_context_get_actions(currentDragSourceContext),
            GDK_CURRENT_TIME);

    } else if (currentDragSourceContext && event->type == GDK_BUTTON_RELEASE) {
        // We've released the mouse button, we should just be able to spin the
        // event loop here and have GTK+ send the appropriate notifications for
        // the end of the drag.
        while (gtk_events_pending())
            gtk_main_iteration();
    }

    gdk_event_free(event);
}
コード例 #10
0
ファイル: callbacks.c プロジェクト: linuxmint/pix
static void
gth_file_list_drag_data_received (GtkWidget        *file_view,
				  GdkDragContext   *context,
				  int               x,
				  int               y,
				  GtkSelectionData *selection_data,
				  guint             info,
				  guint             time,
				  gpointer          user_data)
{
	GthBrowser     *browser = user_data;
	gboolean        success = FALSE;
	char          **uris;
	GList          *selected_files;
	GdkDragAction   action;

	g_signal_stop_emission_by_name (file_view, "drag-data-received");

	action = gdk_drag_context_get_suggested_action (context);
	if (action == GDK_ACTION_COPY || action == GDK_ACTION_MOVE) {
		success = TRUE;
	}

	if (action == GDK_ACTION_ASK) {
		GdkDragAction actions =
			_gtk_menu_ask_drag_drop_action (file_view,
							gdk_drag_context_get_actions (context),
							time);
		gdk_drag_status (context, actions, time);
		success = gdk_drag_context_get_selected_action (context) != 0;
	}

	if (gtk_selection_data_get_data_type (selection_data) == XDND_ACTION_DIRECT_SAVE_ATOM) {
		const guchar *data;
		int           format;
		int           length;

		data = gtk_selection_data_get_data (selection_data);
		format = gtk_selection_data_get_format (selection_data);
		length = gtk_selection_data_get_length (selection_data);

		if ((format == 8) && (length == 1) && (data[0] == 'S')) {
			success = TRUE;
		}
		else {
			gdk_property_change (gdk_drag_context_get_dest_window (context),
					     XDND_ACTION_DIRECT_SAVE_ATOM,
					     TEXT_PLAIN_ATOM,
					     8,
					     GDK_PROP_MODE_REPLACE,
					     (const guchar *) "",
					     0);
			success = FALSE;
		}

		gtk_drag_finish (context, success, FALSE, time);
		return;
	}

	gtk_drag_finish (context, success, FALSE, time);
	if (! success)
		return;

	uris = gtk_selection_data_get_uris (selection_data);
	selected_files = _g_file_list_new_from_uriv (uris);
	if (selected_files != NULL) {
		if (gtk_drag_get_source_widget (context) == file_view) {
			GList       *file_data_list;
			GList       *visible_files;
			BrowserData *data;
			GthTask     *task;

			file_data_list = gth_file_store_get_visibles (gth_browser_get_file_store (browser));
			visible_files = gth_file_data_list_to_file_list (file_data_list);

			data = g_object_get_data (G_OBJECT (browser), BROWSER_DATA_KEY);
			task = gth_reorder_task_new (gth_browser_get_location_source (browser),
						     gth_browser_get_location_data (browser),
						     visible_files,
						     selected_files,
						     data->drop_pos);
			gth_browser_exec_task (browser, task, FALSE);

			g_object_unref (task);
			_g_object_list_unref (visible_files);
			_g_object_list_unref (file_data_list);
		}
		else {
			GthFileSource *file_source;
			gboolean       cancel = FALSE;
			gboolean       move;

			file_source = gth_browser_get_location_source (browser);
			move = gdk_drag_context_get_selected_action (context) == GDK_ACTION_MOVE;
			if (move && ! gth_file_source_can_cut (file_source, (GFile *) selected_files->data)) {
				GtkWidget *dialog;
				int        response;

				dialog = _gtk_message_dialog_new (GTK_WINDOW (browser),
								  GTK_DIALOG_MODAL,
								  GTK_STOCK_DIALOG_QUESTION,
								  _("Could not move the files"),
								  _("Files cannot be moved to the current location, as alternative you can choose to copy them."),
								  GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
								  GTK_STOCK_COPY, GTK_RESPONSE_OK,
								  NULL);
				response = gtk_dialog_run (GTK_DIALOG (dialog));
				gtk_widget_destroy (dialog);

				if (response == GTK_RESPONSE_CANCEL)
					cancel = TRUE;

				move = FALSE;
			}

			if (! cancel) {
				GthFileSource *location_source;
				BrowserData   *data;
				GthTask       *task;

				location_source = gth_main_get_file_source (gth_browser_get_location (browser));
				data = g_object_get_data (G_OBJECT (browser), BROWSER_DATA_KEY);
				task = gth_copy_task_new (location_source,
							  gth_browser_get_location_data (browser),
							  move,
							  selected_files,
							  data->drop_pos);
				gth_browser_exec_task (browser, task, FALSE);

				g_object_unref (task);
				g_object_unref (location_source);
			}
		}
	}

	_g_object_list_unref (selected_files);
	g_strfreev (uris);
}
コード例 #11
0
ファイル: DragAndDropHandler.cpp プロジェクト: sinoory/webv8
bool DragAndDropHandler::drop(GdkDragContext* context, const IntPoint& position, unsigned time)
{
    DroppingContext* droppingContext = m_droppingContexts.get(context);
    if (!droppingContext)
        return false;

    droppingContext->dropHappened = true;

    DataObjectGtk* dataObject = droppingContext->dataObject.get();
    if (!dataObject)
        return false;

    DragData dragData(dataObject, position, convertWidgetPointToScreenPoint(m_page.viewWidget(), position), gdkDragActionToDragOperation(gdk_drag_context_get_actions(context)));
    SandboxExtension::Handle handle;
    SandboxExtension::HandleArray sandboxExtensionForUpload;
    m_page.performDragOperation(dragData, String(), handle, sandboxExtensionForUpload);
    gtk_drag_finish(context, TRUE, FALSE, time);
    return true;
}
コード例 #12
0
ファイル: DragAndDropHandler.cpp プロジェクト: sinoory/webv8
void DragAndDropHandler::dragMotion(GdkDragContext* context, const IntPoint& position, unsigned time)
{
    DataObjectGtk* dataObject = requestDragData(context, position, time);
    if (!dataObject)
        return;

    DragData dragData(dataObject, position, convertWidgetPointToScreenPoint(m_page.viewWidget(), position), gdkDragActionToDragOperation(gdk_drag_context_get_actions(context)));
    m_page.dragUpdated(dragData);
    DragOperation operation = m_page.currentDragOperation();
    gdk_drag_status(context, dragOperationToSingleGdkDragAction(operation), time);
}
コード例 #13
0
ファイル: DragAndDropHandler.cpp プロジェクト: sinoory/webv8
void DragAndDropHandler::dragEntered(GdkDragContext* context, GtkSelectionData* selectionData, unsigned info, unsigned time)
{
    IntPoint position;
    DataObjectGtk* dataObject = dataObjectForDropData(context, selectionData, info, position);
    if (!dataObject)
        return;

    DragData dragData(dataObject, position, convertWidgetPointToScreenPoint(m_page.viewWidget(), position), gdkDragActionToDragOperation(gdk_drag_context_get_actions(context)));
    m_page.resetCurrentDragInformation();
    m_page.dragEntered(dragData);
    DragOperation operation = m_page.currentDragOperation();
    gdk_drag_status(context, dragOperationToSingleGdkDragAction(operation), time);
}
コード例 #14
0
ファイル: dnd.cpp プロジェクト: 0ryuO/dolphin-avsync
static gboolean target_drag_motion( GtkWidget *WXUNUSED(widget),
                                    GdkDragContext *context,
                                    gint x,
                                    gint y,
                                    guint time,
                                    wxDropTarget *drop_target )
{
    /* Owen Taylor: "if the coordinates not in a drop zone,
       return FALSE, otherwise call gtk_drag_status() and
       return TRUE" */

#if 0
    wxPrintf( "motion\n" );
    GList *tmp_list;
    for (tmp_list = context->targets; tmp_list; tmp_list = tmp_list->next)
    {
        wxString atom = wxString::FromAscii( gdk_atom_name (GDK_POINTER_TO_ATOM (tmp_list->data)) );
        wxPrintf( "Atom: %s\n", atom );
    }
#endif

    // Inform the wxDropTarget about the current GdkDragContext.
    // This is only valid for the duration of this call.
    drop_target->GTKSetDragContext( context );

    // Does the source actually accept the data type?
    if (drop_target->GTKGetMatchingPair() == (GdkAtom) 0)
    {
        drop_target->GTKSetDragContext( NULL );
        return FALSE;
    }

    wxDragResult suggested_action = drop_target->GTKFigureOutSuggestedAction();

    wxDragResult result = wxDragNone;

    if (drop_target->m_firstMotion)
    {
        // the first "drag_motion" event substitutes a "drag_enter" event
        result = drop_target->OnEnter( x, y, suggested_action );
    }
    else
    {
        // give program a chance to react (i.e. to say no by returning FALSE)
        result = drop_target->OnDragOver( x, y, suggested_action );
    }

    GdkDragAction result_action = GDK_ACTION_DEFAULT;
    if (result == wxDragCopy)
        result_action = GDK_ACTION_COPY;
    else if (result == wxDragLink)
        result_action = GDK_ACTION_LINK;
    else
        result_action = GDK_ACTION_MOVE;

    // is result action actually supported
    bool ret = (result_action != GDK_ACTION_DEFAULT) &&
               (gdk_drag_context_get_actions(context) & result_action);

    if (ret)
        gdk_drag_status( context, result_action, time );

    // after this, invalidate the drop_target's GdkDragContext
    drop_target->GTKSetDragContext( NULL );

    // this has to be done because GDK has no "drag_enter" event
    drop_target->m_firstMotion = false;

    return ret;
}
コード例 #15
0
void
athena_drag_default_drop_action_for_icons (GdkDragContext *context,
					     const char *target_uri_string, const GList *items,
					     int *action)
{
	gboolean same_fs;
	gboolean target_is_source_parent;
	gboolean source_deletable;
	const char *dropped_uri;
	GFile *target, *dropped, *dropped_directory;
	GdkDragAction actions;
	AthenaFile *dropped_file, *target_file;

	if (target_uri_string == NULL) {
		*action = 0;
		return;
	}

	actions = gdk_drag_context_get_actions (context) & (GDK_ACTION_MOVE | GDK_ACTION_COPY);
	if (actions == 0) {
		 /* We can't use copy or move, just go with the suggested action. */
		*action = gdk_drag_context_get_suggested_action (context);
		return;
	}

	if (gdk_drag_context_get_suggested_action (context) == GDK_ACTION_ASK) {
		/* Don't override ask */
		*action = gdk_drag_context_get_suggested_action (context);
		return;
	}
	
	dropped_uri = ((AthenaDragSelectionItem *)items->data)->uri;
	dropped_file = athena_file_get_existing_by_uri (dropped_uri);
	target_file = athena_file_get_existing_by_uri (target_uri_string);
	
	/*
	 * Check for trash URI.  We do a find_directory for any Trash directory.
	 * Passing 0 permissions as gnome-vfs would override the permissions
	 * passed with 700 while creating .Trash directory
	 */
	if (eel_uri_is_trash (target_uri_string)) {
		/* Only move to Trash */
		if (actions & GDK_ACTION_MOVE) {
			*action = GDK_ACTION_MOVE;
		}

		athena_file_unref (dropped_file);
		athena_file_unref (target_file);
		return;

	} else if (dropped_file != NULL && athena_file_is_launcher (dropped_file)) {
		if (actions & GDK_ACTION_MOVE) {
			*action = GDK_ACTION_MOVE;
		}
		athena_file_unref (dropped_file);
		athena_file_unref (target_file);
		return;
	} else if (eel_uri_is_desktop (target_uri_string)) {
		target = athena_get_desktop_location ();

		athena_file_unref (target_file);
		target_file = athena_file_get (target);

		if (eel_uri_is_desktop (dropped_uri)) {
			/* Only move to Desktop icons */
			if (actions & GDK_ACTION_MOVE) {
				*action = GDK_ACTION_MOVE;
			}
			
			g_object_unref (target);
			athena_file_unref (dropped_file);
			athena_file_unref (target_file);
			return;
		}
	} else if (target_file != NULL && athena_file_is_archive (target_file)) {
		*action = GDK_ACTION_COPY;

		athena_file_unref (dropped_file);
		athena_file_unref (target_file);
		return;
	} else {
		target = g_file_new_for_uri (target_uri_string);
	}

	same_fs = check_same_fs (target_file, dropped_file);

	athena_file_unref (dropped_file);
	athena_file_unref (target_file);
	
	/* Compare the first dropped uri with the target uri for same fs match. */
	dropped = g_file_new_for_uri (dropped_uri);
	dropped_directory = g_file_get_parent (dropped);
	target_is_source_parent = FALSE;
	if (dropped_directory != NULL) {
		/* If the dropped file is already in the same directory but
		   is in another filesystem we still want to move, not copy
		   as this is then just a move of a mountpoint to another
		   position in the dir */
		target_is_source_parent = g_file_equal (dropped_directory, target);
		g_object_unref (dropped_directory);
	}
	source_deletable = source_is_deletable (dropped);

	if ((same_fs && source_deletable) || target_is_source_parent ||
	    g_file_has_uri_scheme (dropped, "trash")) {
		if (actions & GDK_ACTION_MOVE) {
			*action = GDK_ACTION_MOVE;
		} else {
			*action = gdk_drag_context_get_suggested_action (context);
		}
	} else {
		if (actions & GDK_ACTION_COPY) {
			*action = GDK_ACTION_COPY;
		} else {
			*action = gdk_drag_context_get_suggested_action (context);
		}
	}

	g_object_unref (target);
	g_object_unref (dropped);
	
}
コード例 #16
0
gboolean on_dir_tree_view_drag_motion ( GtkWidget *widget,
                                      GdkDragContext *drag_context,
                                      gint x,
                                      gint y,
                                      guint time,
                                      PtkFileBrowser* file_browser )  //MOD added
{
    GdkDragAction suggested_action;
    GdkAtom target;
    GtkTargetList* target_list;

    target_list = gtk_target_list_new( drag_targets, G_N_ELEMENTS(drag_targets) );
    target = gtk_drag_dest_find_target( widget, drag_context, target_list );
    gtk_target_list_unref( target_list );

    if (target == GDK_NONE)
        gdk_drag_status( drag_context, 0, time);
    else
    {
        // Need to set suggested_action because default handler assumes copy
        /* Only 'move' is available. The user force move action by pressing Shift key */
        if( (gdk_drag_context_get_actions ( drag_context ) & GDK_ACTION_ALL) == GDK_ACTION_MOVE )
            suggested_action = GDK_ACTION_MOVE;
        /* Only 'copy' is available. The user force copy action by pressing Ctrl key */
        else if( (gdk_drag_context_get_actions ( drag_context ) & GDK_ACTION_ALL) == GDK_ACTION_COPY )
            suggested_action = GDK_ACTION_COPY;
        /* Only 'link' is available. The user force link action by pressing Shift+Ctrl key */
        else if( (gdk_drag_context_get_actions ( drag_context ) & GDK_ACTION_ALL) == GDK_ACTION_LINK )
            suggested_action = GDK_ACTION_LINK;
        /* Several different actions are available. We have to figure out a good default action. */
        else
        {
            int drag_action = xset_get_int( "drag_action", "x" );
            if ( drag_action == 1 )
                suggested_action = GDK_ACTION_COPY;
            else if ( drag_action == 2 )
                suggested_action = GDK_ACTION_MOVE;
            else if ( drag_action == 3 )
                suggested_action = GDK_ACTION_LINK;
            else
            {
                // automatic
                file_browser->pending_drag_status_tree = 1;
                gtk_drag_get_data (widget, drag_context, target, time);
                suggested_action = gdk_drag_context_get_selected_action( drag_context );
            }
        }
#if GTK_CHECK_VERSION (3, 0, 0)
        /* hack to be able to call the default handler with the correct suggested_action */
        struct _GdkDragContext {
          GObject parent_instance;

          /*< private >*/
          GdkDragProtocol protocol;
#if GTK_CHECK_VERSION (3, 22, 0)
          /* 1.0.6 per Teklad: _GdkDragContext appears to change between
           * different versions of GTK3 which causes the crash. It appears they
           * added/removed some variables from that struct.
           * https://github.com/IgnorantGuru/spacefm/issues/670 */
          GdkDisplay *display;
#endif
          gboolean is_source;
          GdkWindow *source_window;
          GdkWindow *dest_window;

          GList *targets;
          GdkDragAction actions;
          GdkDragAction suggested_action;
          GdkDragAction action;

          guint32 start_time;

          GdkDevice *device;
#if GTK_CHECK_VERSION (3, 22, 0)
          /* 1.0.6 per Teklad: _GdkDragContext appears to change between
           * different versions of GTK3 which causes the crash. It appears they
           * added/removed some variables from that struct.
           * https://github.com/IgnorantGuru/spacefm/issues/670 */
          guint drop_done : 1; /* Whether gdk_drag_drop_done() was performed */
#endif
        };
        ((struct _GdkDragContext *)drag_context)->suggested_action = suggested_action;
#else
        drag_context->suggested_action = suggested_action; // needed for default handler
#endif
        gdk_drag_status( drag_context, suggested_action, gtk_get_current_event_time() );
    }
    return FALSE;
}