Mozilla/mozilla/widget/src/xlib/nsDragService.cpp

297 lines
9.3 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim:ts=2:et:sw=2
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Christopher Blizzard
* <blizzard@mozilla.org>. Portions created by Christopher Blizzard
* are Copyright (C) 1998 Christopher Blizzard. All Rights Reserved.
*
* Contributor(s):
* Christopher Blizzard <blizzard@mozilla.org>
* Peter Hartshorn <peter@igelaus.com.au>
*/
#include "nsAppShell.h"
#include "nsDragService.h"
#include "nsWidgetsCID.h"
#include "nsIWidget.h"
#include "nsIServiceManager.h"
#include "nsVoidArray.h"
#include "nsXPIDLString.h"
#include "nsISupportsPrimitives.h"
#include "nsPrimitiveHelpers.h"
#include "nsString.h"
#include <X11/extensions/shape.h>
#include "xlibrgb.h"
/* drag bitmaps */
static const unsigned char drag_bitmap[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00,
0x00, 0xc0, 0x02, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00, 0x38, 0x04, 0x00,
0x00, 0x0e, 0x0c, 0x00, 0x80, 0x03, 0x08, 0x00, 0xe0, 0x00, 0x18, 0x00,
0xb0, 0x00, 0x30, 0x00, 0x20, 0x01, 0x60, 0x00, 0x20, 0x02, 0xc0, 0x00,
0x20, 0x04, 0x80, 0x00, 0x20, 0x02, 0x80, 0x01, 0x20, 0x01, 0x00, 0x03,
0xa0, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0x0c, 0x60, 0x00, 0x00, 0x08,
0x20, 0x00, 0x00, 0x0c, 0x60, 0x00, 0x00, 0x03, 0x40, 0x00, 0x80, 0x01,
0xc0, 0x00, 0xe0, 0x00, 0x80, 0x00, 0x30, 0x00, 0x80, 0x01, 0x0c, 0x00,
0x00, 0x01, 0x06, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x82, 0x01, 0x00,
0x00, 0x64, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
static const unsigned char drag_mask[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00,
0x00, 0xc0, 0x03, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xf8, 0x07, 0x00,
0x00, 0xfe, 0x0f, 0x00, 0x80, 0xff, 0x0f, 0x00, 0xe0, 0xff, 0x1f, 0x00,
0xf0, 0xff, 0x3f, 0x00, 0xe0, 0xff, 0x7f, 0x00, 0xe0, 0xff, 0xff, 0x00,
0xe0, 0xff, 0xff, 0x00, 0xe0, 0xff, 0xff, 0x01, 0xe0, 0xff, 0xff, 0x03,
0xe0, 0xff, 0xff, 0x07, 0xe0, 0xff, 0xff, 0x0f, 0xe0, 0xff, 0xff, 0x0f,
0xe0, 0xff, 0xff, 0x0f, 0xe0, 0xff, 0xff, 0x03, 0xc0, 0xff, 0xff, 0x01,
0xc0, 0xff, 0xff, 0x00, 0x80, 0xff, 0x3f, 0x00, 0x80, 0xff, 0x0f, 0x00,
0x00, 0xff, 0x07, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0xfe, 0x01, 0x00,
0x00, 0x7c, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
NS_IMPL_ADDREF_INHERITED(nsDragService, nsBaseDragService)
NS_IMPL_RELEASE_INHERITED(nsDragService, nsBaseDragService)
NS_IMPL_QUERY_INTERFACE3(nsDragService, nsIDragService, nsIDragSession, nsIDragSessionXlib)
nsWidget *nsDragService::sWidget = nsnull;
Window nsDragService::sWindow;
XlibRgbHandle *nsDragService::sXlibRgbHandle;
Display *nsDragService::sDisplay;
PRBool nsDragService::mDragging = PR_FALSE;
nsDragService::nsDragService()
{
sXlibRgbHandle = nsAppShell::GetXlibRgbHandle();
sDisplay = xxlib_rgb_get_display(sXlibRgbHandle);
mCanDrop = PR_FALSE;
sWindow = None;
}
nsDragService::~nsDragService()
{
}
// nsIDragService
NS_IMETHODIMP nsDragService::InvokeDragSession (nsIDOMNode *aDOMNode,
nsISupportsArray *aArrayTransferables,
nsIScriptableRegion *aRegion,
PRUint32 aActionType)
{
nsBaseDragService::InvokeDragSession(aDOMNode, aArrayTransferables,
aRegion, aActionType);
/* no data - no dnd */
if (!aArrayTransferables)
return NS_ERROR_INVALID_ARG;
nsresult rv;
PRUint32 numItemsToDrag = 0;
mSourceDataItems = aArrayTransferables;
rv = mSourceDataItems->Count(&numItemsToDrag);
if (!numItemsToDrag)
return NS_ERROR_FAILURE;
mDragging = PR_TRUE;
CreateDragCursor(aActionType);
return NS_OK;
}
NS_IMETHODIMP nsDragService::StartDragSession()
{
mDragging = PR_TRUE;
return nsBaseDragService::StartDragSession();
}
NS_IMETHODIMP nsDragService::EndDragSession()
{
if (sWindow) {
XDestroyWindow(sDisplay, sWindow);
sWindow = 0;
}
mDragging = PR_FALSE;
return nsBaseDragService::EndDragSession();
}
// nsIDragSession
// For some reason we need this, but GTK does not. Hmmm...
NS_IMETHODIMP nsDragService::GetCurrentSession(nsIDragSession **aSession)
{
if (!aSession)
return NS_ERROR_FAILURE;
if (!mDragging) {
*aSession = nsnull;
return NS_OK;
}
*aSession = (nsIDragSession *)this;
NS_ADDREF(*aSession);
return NS_OK;
}
NS_IMETHODIMP nsDragService::SetCanDrop(PRBool aCanDrop)
{
mCanDrop = aCanDrop;
return NS_OK;
}
NS_IMETHODIMP nsDragService::GetCanDrop(PRBool *aCanDrop)
{
*aCanDrop = mCanDrop;
return NS_OK;
}
NS_IMETHODIMP nsDragService::GetNumDropItems(PRUint32 *aNumItems)
{
mSourceDataItems->Count(aNumItems);
return NS_OK;
}
NS_IMETHODIMP nsDragService::GetData(nsITransferable *aTransferable, PRUint32 anItemIndex)
{
if (!aTransferable)
return NS_ERROR_INVALID_ARG;
nsresult rv = NS_ERROR_FAILURE;
nsCOMPtr <nsISupportsArray> flavorList;
rv = aTransferable->FlavorsTransferableCanImport(getter_AddRefs(flavorList));
if (NS_FAILED(rv))
return rv;
PRUint32 cnt, i;
flavorList->Count (&cnt);
for (i = 0; i < cnt; ++i) {
nsCAutoString foundFlavor;
nsCOMPtr <nsISupports> genericWrapper;
flavorList->GetElementAt(i, getter_AddRefs(genericWrapper));
nsCOMPtr <nsISupportsString> currentFlavor;
currentFlavor = do_QueryInterface(genericWrapper);
if (currentFlavor) {
nsXPIDLCString flavorStr;
currentFlavor->ToString(getter_Copies(flavorStr));
foundFlavor = nsCAutoString(flavorStr);
#if 0
g_print("Looking for data in type %s\n",
NS_STATIC_CAST(const char*, flavorStr));
#endif
/* set the data */
nsCOMPtr <nsISupports> genItem;
mSourceDataItems->GetElementAt(anItemIndex, getter_AddRefs(genItem));
nsCOMPtr <nsITransferable> item(do_QueryInterface(genItem));
nsCOMPtr <nsISupports> data;
PRUint32 dataLen = 0;
item->GetTransferData(foundFlavor, getter_AddRefs(data), &dataLen);
aTransferable->SetTransferData(foundFlavor, data, dataLen);
}
}
EndDragSession();
return NS_OK;
}
NS_IMETHODIMP nsDragService::IsDataFlavorSupported(const char *aDataFlavor, PRBool *_retval)
{
/* XXX Please implement this - for now - support all flavors */
*_retval = PR_TRUE;
return NS_OK;
}
// nsIDragSessionXlib
NS_IMETHODIMP nsDragService::IsDragging(PRBool *result) {
*result = mDragging;
return NS_OK;
}
NS_IMETHODIMP nsDragService::UpdatePosition(PRInt32 x, PRInt32 y)
{
if (sWindow) {
Window aRoot, aChild;
int cx, cy;
unsigned int mask;
XQueryPointer(sDisplay, sWindow, &aRoot, &aChild, &x, &y, &cx, &cy, &mask);
XMoveWindow(sDisplay, sWindow, x, y);
}
return NS_OK;
}
void nsDragService::CreateDragCursor(PRUint32 aActionType)
{
if (sWindow == None) {
Pixmap aPixmap;
Pixmap aShapeMask;
XSetWindowAttributes wattr;
unsigned long wattr_mask;
XWMHints wmHints;
int depth;
Screen *screen = xxlib_rgb_get_screen(sXlibRgbHandle);
int screennum = XScreenNumberOfScreen(screen);
wattr.override_redirect = True;
wattr.background_pixel = XWhitePixel(sDisplay, screennum);
wattr.border_pixel = XBlackPixel(sDisplay, screennum);
wattr.colormap = xxlib_rgb_get_cmap(sXlibRgbHandle);
wattr_mask = CWOverrideRedirect | CWBorderPixel | CWBackPixel;
if (wattr.colormap)
wattr_mask |= CWColormap;
depth = xxlib_rgb_get_depth(sXlibRgbHandle);
/* make a window off-screen at -64, -64 */
sWindow = XCreateWindow(sDisplay, XRootWindowOfScreen(screen),
-64, -64, 32, 32, 0, depth,
InputOutput, xxlib_rgb_get_visual(sXlibRgbHandle),
wattr_mask, &wattr);
aPixmap = XCreatePixmapFromBitmapData(sDisplay, sWindow,
(char *)drag_bitmap,
32, 32, 0x0, 0xffffffff, depth);
aShapeMask = XCreatePixmapFromBitmapData(sDisplay, sWindow,
(char *)drag_mask,
32, 32, 0xffffffff, 0x0, 1);
wmHints.flags = StateHint;
wmHints.initial_state = NormalState;
XSetWMProperties(sDisplay, sWindow, NULL, NULL, NULL, 0, NULL,
&wmHints, NULL);
XSetTransientForHint(sDisplay, sWindow, sWindow);
XShapeCombineMask(sDisplay, sWindow, ShapeClip, 0, 0,
aShapeMask, ShapeSet);
XShapeCombineMask(sDisplay, sWindow, ShapeBounding, 0, 0,
aShapeMask, ShapeSet);
XSetWindowBackgroundPixmap(sDisplay, sWindow, aPixmap);
XMapWindow(sDisplay, sWindow);
}
}