/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "nsIArray.idl"
#include "nsISupports.idl"
#include "nsIDragSession.idl"
#include "nsIContentPolicy.idl"

webidl DragEvent;
webidl Node;
webidl Selection;

interface nsICookieJarSettings;
interface nsIMockDragServiceController;

%{C++
#include "mozilla/EventForwards.h"
#include "nsIWidget.h"

class nsIWidget;

namespace mozilla {
namespace dom {
class BrowserParent;
class DataTransfer;
class RemoteDragStartData;
} // namespace dom
} // namespace mozilla
%}

[ptr] native BrowserParentPtr(mozilla::dom::BrowserParent);
[ptr] native DataTransferPtr(mozilla::dom::DataTransfer);
[ptr] native RemoteDragStartDataPtr(mozilla::dom::RemoteDragStartData);
native EventMessage(mozilla::EventMessage);

[scriptable, uuid(ebd6b3a2-af16-43af-a698-3091a087dd62), builtinclass]
interface nsIDragService : nsISupports
{
  const long DRAGDROP_ACTION_NONE = 0;
  const long DRAGDROP_ACTION_COPY = 1;
  const long DRAGDROP_ACTION_MOVE = 2;
  const long DRAGDROP_ACTION_LINK = 4;
  const long DRAGDROP_ACTION_UNINITIALIZED = 64;

  /**
   * Starts a modal drag session using an image. The first four arguments are
   * the same as invokeDragSession.
   *
   * Note: This method is deprecated for non-native code.
   *
   * A custom image may be specified using the aImage argument. If this is
   * supplied, the aImageX and aImageY arguments specify the offset within
   * the image where the cursor would be positioned. That is, when the image
   * is drawn, it is offset up and left the amount so that the cursor appears
   * at that location within the image.
   *
   * If aImage is null, aImageX and aImageY are not used and the image is instead
   * determined from the source node aDOMNode, and the offset calculated so that
   * the initial location for the image appears in the same screen position as
   * where the element is located. The node must be within a document.
   *
   * Currently, supported images are all DOM nodes. If this is an HTML <image> or
   * <canvas>, the drag image is taken from the image data. If the element is in
   * a document, it will be rendered at its displayed size, othewise, it will be
   * rendered at its real size. For other types of elements, the element is
   * rendered into an offscreen buffer in the same manner as it is currently
   * displayed. The document selection is hidden while drawing.
   *
   * The aDragEvent must be supplied as the current screen coordinates of the
   * event are needed to calculate the image location.
   */
  [noscript, can_run_script]
  void invokeDragSessionWithImage(in Node aDOMNode,
                                  in nsIPrincipal aPrincipal,
                                  in nsIContentSecurityPolicy aCsp,
                                  in nsICookieJarSettings aCookieJarSettings,
                                  in nsIArray aTransferableArray,
                                  in unsigned long aActionType,
                                  in Node aImage,
                                  in long aImageX,
                                  in long aImageY,
                                  in DragEvent aDragEvent,
                                  in DataTransferPtr aDataTransfer);

  /** Start a drag session with the data in aDragStartData from a child process.
   *  Other arguments are the same as invokeDragSessionWithImage.
   */
  [noscript, can_run_script]
  void invokeDragSessionWithRemoteImage(in Node aDOMNode,
                                        in nsIPrincipal aPrincipal,
                                        in nsIContentSecurityPolicy aCsp,
                                        in nsICookieJarSettings aCookieJarSettings,
                                        in nsIArray aTransferableArray,
                                        in unsigned long aActionType,
                                        in RemoteDragStartDataPtr aDragStartData,
                                        in DragEvent aDragEvent,
                                        in DataTransferPtr aDataTransfer);

  /**
   * Start a modal drag session using the selection as the drag image.
   * The aDragEvent must be supplied as the current screen coordinates of the
   * event are needed to calculate the image location.
   *
   * Note: This method is deprecated for non-native code.
   */
  [noscript, can_run_script]
  void invokeDragSessionWithSelection(in Selection aSelection,
                                      in nsIPrincipal aPrincipal,
                                      in nsIContentSecurityPolicy aCsp,
                                      in nsICookieJarSettings aCookieJarSettings,
                                      in nsIArray aTransferableArray,
                                      in unsigned long aActionType,
                                      in DragEvent aDragEvent,
                                      in DataTransferPtr aDataTransfer,
                                      in Node aTargetContent);

  /**
    * In the parent process, returns the current drag session.  In content,
    * returns the current drag session for the widget containing the given
    * window, or the entry global JS context if aWindow is not specified.
    *
    * @param aWidgetProvider Either the nsIWidget that is the source or current
    *                        target of the drag, or an nsIDOMWindowProxy for a
    *                        window that is on the widget.
    */
  nsIDragSession getCurrentSession([optional] in nsISupports aWidgetProvider);

%{ C++
  nsIDragSession* GetCurrentSession(nsIWidget* aWidget) {
  	nsCOMPtr<nsIDragSession> session;
    GetCurrentSession(aWidget, getter_AddRefs(session));
    return session;
  }
%}

  /**
    * Tells the Drag Service to start a drag session. This is called when
    * an external drag occurs.
    *
    * @param aWidgetProvider Either the nsIWidget that will be the target of
    *                        the drag, or an nsIDOMWindowProxy for a
    *                        window that is on that widget.
    * @returns the new (or pre-existing) session
    */
  [notxpcom, nostdcall]
  nsIDragSession startDragSession(in nsISupports aWidgetProvider);

  /**
   * Similar to startDragSession(), automated tests may want to start
   * session for emulating an external drag.  At that time, this should
   * be used instead of startDragSession().
   *
   * @param aWidgetProvider Either the nsIWidget that is the source or current
   *                        target of the drag, or an nsIDOMWindowProxy for a
   *                        window that is on the widget.
   *
   * @param aAllowedEffect Set default drag action which means allowed effects
   *                       in the session and every DnD events are initialized
   *                       with one of specified value.  So, the value can be
   *                       DRAGDROP_ACTION_NONE, or one or more values of
   *                       DRAGDROP_ACTION_(MOVE|COPY|LINK).
   */
  void startDragSessionForTests(in nsISupports aWidgetProvider,
                                in unsigned long aAllowedEffect);

  /**
   * Increase/decrease dragging suppress level by one.
   * If level is greater than one, dragging is disabled.
   */
  [can_run_script]
  void suppress();
  void unsuppress();

  [notxpcom, nostdcall] boolean maybeAddBrowser(in BrowserParentPtr aBP);
  [notxpcom, nostdcall] boolean removeAllBrowsers();

  /**
   * The controller is used to issue events that would normally come from
   * the system (when it is not mocked for testing).  This allows us to test
   * without engaging any native DND behavior.
   *
   * In order for the controller to be effective, the existing nsIDragService
   * needs to be replaced with the one in the controller.  See
   * nsIMockDragServiceController for details.
   */
  nsIMockDragServiceController getMockDragController();

  /**
   * True if this is a mock nsIDragService, created with
   * createMockDragController().
   */
  readonly attribute boolean isMockService;

%{ C++
  bool IsMockService() {
    bool ret = false;
    MOZ_ALWAYS_SUCCEEDS(GetIsMockService(&ret));
    return ret;
  }
%}

  /**
   * If this is true, mSessionIsSynthesizedForTests should not become true.
   * This hack is used to bypass the "old" drag-drop test behavior, which needed
   * special behavior to pass.  The new framework requires the actual browser
   * behavior.  The test for whether we are using the new framework or not can
   * only be done in the main process with nsBaseDragService::IsMockService.
   * Unfortunately, mSessionIsSynthesizedForTests is inherited from
   * synthetic mouse events in content processes (when dragging content) so we
   * set this early in the relevant tests.  Once the old tests are replaced,
   * this can be removed along with mSessionIsSynthesizedForTests.
   */
  [infallible] attribute boolean neverAllowSessionIsSynthesizedForTests;
};


%{ C++

%}
