widget r=darin sr=darin a=asa git-svn-id: svn://10.0.0.236/trunk@175469 18797224-902f-48f8-a5cc-f745e15eee43
314 lines
10 KiB
C++
314 lines
10 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
* vim:ts=2:et:sw=2
|
|
*
|
|
* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
*
|
|
* 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 the Initial Developer are Copyright (C) 1998
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
* Christopher Blizzard <blizzard@mozilla.org>
|
|
* Peter Hartshorn <peter@igelaus.com.au>
|
|
*
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
* the provisions above, a recipient may use your version of this file under
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
*
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
#include "nsAppShell.h"
|
|
#include "nsDragService.h"
|
|
#include "nsWidgetsCID.h"
|
|
#include "nsIWidget.h"
|
|
#include "nsIServiceManager.h"
|
|
#include "nsXPIDLString.h"
|
|
#include "nsXPCOM.h"
|
|
#include "nsISupportsPrimitives.h"
|
|
#include "nsPrimitiveHelpers.h"
|
|
#include "nsString.h"
|
|
|
|
#include <X11/extensions/shape.h>
|
|
|
|
#include "xlibrgb.h"
|
|
|
|
NS_IMPL_ISUPPORTS_INHERITED1(nsDragService,
|
|
nsBaseDragService,
|
|
nsIDragSessionXlib)
|
|
|
|
/* 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 };
|
|
|
|
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 <nsISupportsCString> 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.get(), getter_AddRefs(data), &dataLen);
|
|
aTransferable->SetTransferData(foundFlavor.get(), 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, nsnull, nsnull, nsnull, 0, nsnull,
|
|
&wmHints, nsnull);
|
|
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);
|
|
}
|
|
}
|