/* -*- 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 * . Portions created by Christopher Blizzard * are Copyright (C) 1998 Christopher Blizzard. All Rights Reserved. * * Contributor(s): * Christopher Blizzard * Peter Hartshorn */ #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 #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 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 genericWrapper; flavorList->GetElementAt(i, getter_AddRefs(genericWrapper)); nsCOMPtr 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 genItem; mSourceDataItems->GetElementAt(anItemIndex, getter_AddRefs(genItem)); nsCOMPtr item(do_QueryInterface(genItem)); nsCOMPtr 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); } }