Back to index

lightning-sunbird  0.9+nobinonly
nsDragService.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
00002  * vim:ts=2:et:sw=2
00003  *
00004  * ***** BEGIN LICENSE BLOCK *****
00005  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00006  *
00007  * The contents of this file are subject to the Mozilla Public License Version
00008  * 1.1 (the "License"); you may not use this file except in compliance with
00009  * the License. You may obtain a copy of the License at
00010  * http://www.mozilla.org/MPL/
00011  *
00012  * Software distributed under the License is distributed on an "AS IS" basis,
00013  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00014  * for the specific language governing rights and limitations under the
00015  * License.
00016  *
00017  * The Original Code is mozilla.org code.
00018  *
00019  * The Initial Developer of the Original Code is
00020  * Christopher Blizzard <blizzard@mozilla.org>.
00021  * Portions created by the Initial Developer are Copyright (C) 1998
00022  * the Initial Developer. All Rights Reserved.
00023  *
00024  * Contributor(s):
00025  *   Christopher Blizzard <blizzard@mozilla.org>
00026  *   Peter Hartshorn <peter@igelaus.com.au>
00027  *
00028  * Alternatively, the contents of this file may be used under the terms of
00029  * either the GNU General Public License Version 2 or later (the "GPL"), or
00030  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00031  * in which case the provisions of the GPL or the LGPL are applicable instead
00032  * of those above. If you wish to allow use of your version of this file only
00033  * under the terms of either the GPL or the LGPL, and not to allow others to
00034  * use your version of this file under the terms of the MPL, indicate your
00035  * decision by deleting the provisions above and replace them with the notice
00036  * and other provisions required by the GPL or the LGPL. If you do not delete
00037  * the provisions above, a recipient may use your version of this file under
00038  * the terms of any one of the MPL, the GPL or the LGPL.
00039  *
00040  * ***** END LICENSE BLOCK ***** */
00041 
00042 #include "nsAppShell.h"
00043 #include "nsDragService.h"
00044 #include "nsWidgetsCID.h"
00045 #include "nsIWidget.h"
00046 #include "nsIServiceManager.h"
00047 #include "nsXPIDLString.h"
00048 #include "nsXPCOM.h"
00049 #include "nsISupportsPrimitives.h"
00050 #include "nsPrimitiveHelpers.h"
00051 #include "nsString.h"
00052 
00053 #include <X11/extensions/shape.h>
00054 
00055 #include "xlibrgb.h"
00056 
00057 NS_IMPL_ISUPPORTS_INHERITED1(nsDragService,
00058                              nsBaseDragService,
00059                              nsIDragSessionXlib)
00060 
00061 /* drag bitmaps */
00062 static const unsigned char drag_bitmap[] = {
00063    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00,
00064    0x00, 0xc0, 0x02, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00, 0x38, 0x04, 0x00,
00065    0x00, 0x0e, 0x0c, 0x00, 0x80, 0x03, 0x08, 0x00, 0xe0, 0x00, 0x18, 0x00,
00066    0xb0, 0x00, 0x30, 0x00, 0x20, 0x01, 0x60, 0x00, 0x20, 0x02, 0xc0, 0x00,
00067    0x20, 0x04, 0x80, 0x00, 0x20, 0x02, 0x80, 0x01, 0x20, 0x01, 0x00, 0x03,
00068    0xa0, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0x0c, 0x60, 0x00, 0x00, 0x08,
00069    0x20, 0x00, 0x00, 0x0c, 0x60, 0x00, 0x00, 0x03, 0x40, 0x00, 0x80, 0x01,
00070    0xc0, 0x00, 0xe0, 0x00, 0x80, 0x00, 0x30, 0x00, 0x80, 0x01, 0x0c, 0x00,
00071    0x00, 0x01, 0x06, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x82, 0x01, 0x00,
00072    0x00, 0x64, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00,
00073    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
00074 
00075 static const unsigned char drag_mask[] = {
00076    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00,
00077    0x00, 0xc0, 0x03, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xf8, 0x07, 0x00,
00078    0x00, 0xfe, 0x0f, 0x00, 0x80, 0xff, 0x0f, 0x00, 0xe0, 0xff, 0x1f, 0x00,
00079    0xf0, 0xff, 0x3f, 0x00, 0xe0, 0xff, 0x7f, 0x00, 0xe0, 0xff, 0xff, 0x00,
00080    0xe0, 0xff, 0xff, 0x00, 0xe0, 0xff, 0xff, 0x01, 0xe0, 0xff, 0xff, 0x03,
00081    0xe0, 0xff, 0xff, 0x07, 0xe0, 0xff, 0xff, 0x0f, 0xe0, 0xff, 0xff, 0x0f,
00082    0xe0, 0xff, 0xff, 0x0f, 0xe0, 0xff, 0xff, 0x03, 0xc0, 0xff, 0xff, 0x01,
00083    0xc0, 0xff, 0xff, 0x00, 0x80, 0xff, 0x3f, 0x00, 0x80, 0xff, 0x0f, 0x00,
00084    0x00, 0xff, 0x07, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0xfe, 0x01, 0x00,
00085    0x00, 0x7c, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00,
00086    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
00087 
00088 nsWidget *nsDragService::sWidget = nsnull;
00089 Window    nsDragService::sWindow;
00090 XlibRgbHandle *nsDragService::sXlibRgbHandle;
00091 Display  *nsDragService::sDisplay;
00092 PRBool    nsDragService::mDragging = PR_FALSE;
00093 
00094 nsDragService::nsDragService()
00095 {
00096   sXlibRgbHandle = nsAppShell::GetXlibRgbHandle();
00097   sDisplay = xxlib_rgb_get_display(sXlibRgbHandle);
00098   mCanDrop = PR_FALSE;
00099   sWindow = None;
00100 }
00101 
00102 nsDragService::~nsDragService()
00103 {
00104 }
00105 
00106 // nsIDragService
00107 NS_IMETHODIMP nsDragService::InvokeDragSession (nsIDOMNode *aDOMNode,
00108                                                 nsISupportsArray *aArrayTransferables,
00109                                                 nsIScriptableRegion *aRegion,
00110                                                 PRUint32 aActionType)
00111 {
00112   nsresult rv = nsBaseDragService::InvokeDragSession(aDOMNode,
00113                                                      aArrayTransferables,
00114                                                      aRegion, aActionType);
00115   NS_ENSURE_SUCCESS(rv, rv);
00116 
00117   /* no data - no dnd */
00118   if (!aArrayTransferables)
00119     return NS_ERROR_INVALID_ARG;
00120 
00121   PRUint32 numItemsToDrag = 0;
00122 
00123   mSourceDataItems = aArrayTransferables;
00124 
00125   rv = mSourceDataItems->Count(&numItemsToDrag);
00126   if (!numItemsToDrag)
00127     return NS_ERROR_FAILURE;
00128 
00129   mDragging = PR_TRUE;
00130 
00131   CreateDragCursor(aActionType);
00132 
00133   return NS_OK;
00134 }
00135 
00136 NS_IMETHODIMP nsDragService::StartDragSession()
00137 {
00138   mDragging = PR_TRUE;
00139 
00140   return nsBaseDragService::StartDragSession();
00141 }
00142 
00143 NS_IMETHODIMP nsDragService::EndDragSession()
00144 {
00145   if (sWindow) {
00146     XDestroyWindow(sDisplay, sWindow);
00147     sWindow = 0;
00148   }
00149   mDragging = PR_FALSE;
00150 
00151   return nsBaseDragService::EndDragSession();
00152 }
00153 
00154 // nsIDragSession
00155 
00156 // For some reason we need this, but GTK does not. Hmmm...
00157 NS_IMETHODIMP nsDragService::GetCurrentSession(nsIDragSession **aSession)
00158 {
00159   if (!aSession)
00160     return NS_ERROR_FAILURE;
00161 
00162   if (!mDragging || mSuppressLevel) {
00163     *aSession = nsnull;
00164     return NS_OK;
00165   }
00166 
00167   *aSession = (nsIDragSession *)this;
00168   NS_ADDREF(*aSession);
00169   return NS_OK;
00170 }
00171 
00172 NS_IMETHODIMP nsDragService::SetCanDrop(PRBool aCanDrop)
00173 {
00174   mCanDrop = aCanDrop;
00175   return NS_OK;
00176 }
00177 
00178 NS_IMETHODIMP nsDragService::GetCanDrop(PRBool *aCanDrop)
00179 {
00180   *aCanDrop = mCanDrop;
00181   return NS_OK;
00182 }
00183 
00184 NS_IMETHODIMP nsDragService::GetNumDropItems(PRUint32 *aNumItems)
00185 {
00186   mSourceDataItems->Count(aNumItems);
00187   return NS_OK;
00188 }
00189 
00190 NS_IMETHODIMP nsDragService::GetData(nsITransferable *aTransferable, PRUint32 anItemIndex)
00191 {
00192   if (!aTransferable)
00193     return NS_ERROR_INVALID_ARG;
00194 
00195   nsresult rv = NS_ERROR_FAILURE;
00196   nsCOMPtr <nsISupportsArray> flavorList;
00197   rv = aTransferable->FlavorsTransferableCanImport(getter_AddRefs(flavorList));
00198   if (NS_FAILED(rv))
00199     return rv;
00200 
00201   PRUint32 cnt, i;
00202   flavorList->Count (&cnt);
00203 
00204   for (i = 0; i < cnt; ++i) {
00205     nsCAutoString foundFlavor;
00206     nsCOMPtr <nsISupports> genericWrapper;
00207 
00208     flavorList->GetElementAt(i, getter_AddRefs(genericWrapper));
00209     nsCOMPtr <nsISupportsCString> currentFlavor;
00210     currentFlavor = do_QueryInterface(genericWrapper);
00211 
00212     if (currentFlavor) {
00213       nsXPIDLCString flavorStr;
00214       currentFlavor->ToString(getter_Copies(flavorStr));
00215       foundFlavor = nsCAutoString(flavorStr);
00216 
00217 #if 0
00218       g_print("Looking for data in type %s\n",
00219           NS_STATIC_CAST(const char*, flavorStr));
00220 #endif
00221 
00222       /* set the data */
00223       nsCOMPtr <nsISupports> genItem;
00224       mSourceDataItems->GetElementAt(anItemIndex, getter_AddRefs(genItem));
00225       
00226       nsCOMPtr <nsITransferable> item(do_QueryInterface(genItem));
00227       nsCOMPtr <nsISupports> data;
00228       PRUint32 dataLen = 0;
00229 
00230       item->GetTransferData(foundFlavor.get(), getter_AddRefs(data), &dataLen);
00231       aTransferable->SetTransferData(foundFlavor.get(), data, dataLen);
00232     }
00233   }
00234 
00235   EndDragSession();
00236 
00237   return NS_OK;
00238 }
00239 
00240 NS_IMETHODIMP nsDragService::IsDataFlavorSupported(const char *aDataFlavor, PRBool *_retval)
00241 {
00242   /* XXX Please implement this - for now - support all flavors */
00243   *_retval = PR_TRUE;
00244   return NS_OK;
00245 }
00246 
00247 // nsIDragSessionXlib
00248 
00249 NS_IMETHODIMP nsDragService::IsDragging(PRBool *result) {
00250   *result = mDragging;
00251   return NS_OK;
00252 }
00253 
00254 NS_IMETHODIMP nsDragService::UpdatePosition(PRInt32 x, PRInt32 y)
00255 {
00256   if (sWindow) {
00257     Window aRoot, aChild;
00258     int cx, cy;
00259     unsigned int mask;
00260     XQueryPointer(sDisplay, sWindow, &aRoot, &aChild, &x, &y, &cx, &cy, &mask); 
00261     XMoveWindow(sDisplay, sWindow, x, y);
00262   }
00263   return NS_OK;
00264 }
00265 
00266 void nsDragService::CreateDragCursor(PRUint32 aActionType)
00267 {
00268   if (sWindow == None) {
00269     Pixmap aPixmap;
00270     Pixmap aShapeMask;
00271     XSetWindowAttributes wattr;
00272     unsigned long wattr_mask;
00273     XWMHints wmHints;
00274     int depth;
00275     Screen *screen = xxlib_rgb_get_screen(sXlibRgbHandle);
00276     int screennum = XScreenNumberOfScreen(screen);
00277 
00278     wattr.override_redirect = True;
00279     wattr.background_pixel  = XWhitePixel(sDisplay, screennum);
00280     wattr.border_pixel      = XBlackPixel(sDisplay, screennum);
00281     wattr.colormap          = xxlib_rgb_get_cmap(sXlibRgbHandle);
00282     wattr_mask = CWOverrideRedirect | CWBorderPixel | CWBackPixel;
00283     if (wattr.colormap)
00284       wattr_mask |= CWColormap;
00285     
00286     depth = xxlib_rgb_get_depth(sXlibRgbHandle);
00287     
00288     /* make a window off-screen at -64, -64 */
00289     sWindow = XCreateWindow(sDisplay, XRootWindowOfScreen(screen),
00290                             -64, -64, 32, 32, 0, depth,
00291                             InputOutput, xxlib_rgb_get_visual(sXlibRgbHandle),
00292                             wattr_mask, &wattr);
00293     
00294     aPixmap = XCreatePixmapFromBitmapData(sDisplay, sWindow,
00295                                           (char *)drag_bitmap,
00296                                           32, 32, 0x0, 0xffffffff, depth);
00297 
00298     aShapeMask = XCreatePixmapFromBitmapData(sDisplay, sWindow,
00299                                              (char *)drag_mask,
00300                                              32, 32, 0xffffffff, 0x0, 1);
00301 
00302     wmHints.flags = StateHint;
00303     wmHints.initial_state = NormalState;
00304     XSetWMProperties(sDisplay, sWindow, nsnull, nsnull, nsnull, 0, nsnull,
00305                      &wmHints, nsnull);
00306     XSetTransientForHint(sDisplay, sWindow, sWindow);
00307     XShapeCombineMask(sDisplay, sWindow, ShapeClip, 0, 0, 
00308                       aShapeMask, ShapeSet);
00309     XShapeCombineMask(sDisplay, sWindow, ShapeBounding, 0, 0,
00310                       aShapeMask, ShapeSet);
00311     XSetWindowBackgroundPixmap(sDisplay, sWindow, aPixmap);
00312     XMapWindow(sDisplay, sWindow);
00313   }
00314 }