Back to index

lightning-sunbird  0.9+nobinonly
nsClipboard.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is the Mozilla OS/2 libraries.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * John Fairhurst, <john_fairhurst@iname.com>.
00020  * Portions created by the Initial Developer are Copyright (C) 1999
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   2000/08/04     Henry Sobotka <sobotka@axess.com>  Update from M7
00025  *   2000/10/02     IBM Corp.                          Sync-up to M18 level
00026  *
00027  * Alternatively, the contents of this file may be used under the terms of
00028  * either the GNU General Public License Version 2 or later (the "GPL"), or
00029  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00030  * in which case the provisions of the GPL or the LGPL are applicable instead
00031  * of those above. If you wish to allow use of your version of this file only
00032  * under the terms of either the GPL or the LGPL, and not to allow others to
00033  * use your version of this file under the terms of the MPL, indicate your
00034  * decision by deleting the provisions above and replace them with the notice
00035  * and other provisions required by the GPL or the LGPL. If you do not delete
00036  * the provisions above, a recipient may use your version of this file under
00037  * the terms of any one of the MPL, the GPL or the LGPL.
00038  *
00039  * ***** END LICENSE BLOCK ***** */
00040 
00041 #include "nsClipboard.h"
00042 #include "nsXPCOM.h"
00043 #include "nsISupportsPrimitives.h"
00044 #include "nsCOMPtr.h"
00045 #include "nsPrimitiveHelpers.h"
00046 #include "nsXPIDLString.h"
00047 #include "prmem.h"
00048 #include "nsIObserverService.h"
00049 #include "nsIServiceManager.h"
00050 
00051 #include "nsOS2Uni.h"
00052 
00053 #include <unidef.h>     // for UniStrlen
00054 
00055 inline ULONG RegisterClipboardFormat(PCSZ pcszFormat)
00056 {
00057   ATOM atom = WinFindAtom(WinQuerySystemAtomTable(), pcszFormat);
00058   if (!atom) {
00059     atom = WinAddAtom(WinQuerySystemAtomTable(), pcszFormat); 
00060   }
00061   return atom;
00062 }
00063 
00064 nsClipboard::nsClipboard() : nsBaseClipboard()
00065 {
00066   RegisterClipboardFormat(kTextMime);
00067   RegisterClipboardFormat(kUnicodeMime);
00068   RegisterClipboardFormat(kHTMLMime);
00069   RegisterClipboardFormat(kAOLMailMime);
00070   RegisterClipboardFormat(kPNGImageMime);
00071   RegisterClipboardFormat(kJPEGImageMime);
00072   RegisterClipboardFormat(kGIFImageMime);
00073   RegisterClipboardFormat(kFileMime);
00074   RegisterClipboardFormat(kURLMime);
00075   RegisterClipboardFormat(kNativeImageMime);
00076   RegisterClipboardFormat(kNativeHTMLMime);
00077 
00078   // Register for a shutdown notification so that we can flush data
00079   // to the OS clipboard.
00080   nsCOMPtr<nsIObserverService> observerService =
00081     do_GetService("@mozilla.org/observer-service;1");
00082   if (observerService)
00083     observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_FALSE);
00084 }
00085 
00086 nsClipboard::~nsClipboard()
00087 {}
00088 
00089 NS_IMPL_ISUPPORTS_INHERITED1(nsClipboard, nsBaseClipboard, nsIObserver)
00090 
00091 nsresult nsClipboard::SetNativeClipboardData(PRInt32 aWhichClipboard)
00092 {
00093   if (aWhichClipboard != kGlobalClipboard)
00094     return NS_ERROR_FAILURE;
00095 
00096   return DoClipboardAction(Write);
00097 }
00098 
00099 nsresult nsClipboard::GetNativeClipboardData(nsITransferable *aTransferable, PRInt32 aWhichClipboard)
00100 {
00101   // make sure we have a good transferable
00102   if (!aTransferable || aWhichClipboard != kGlobalClipboard)
00103     return NS_ERROR_FAILURE;
00104 
00105   nsITransferable *tmp = mTransferable;
00106   mTransferable = aTransferable;
00107   nsresult rc = DoClipboardAction(Read);
00108   mTransferable = tmp;
00109   return rc;
00110 }
00111 
00112 // Get some data from the clipboard
00113 PRBool nsClipboard::GetClipboardData(const char *aFlavor)
00114 {
00115   ULONG ulFormatID = GetFormatID( aFlavor );
00116   
00117   PRBool found = GetClipboardDataByID( ulFormatID, aFlavor );
00118 
00119   if (!found) 
00120   {
00121     if (!strcmp( aFlavor, kUnicodeMime ))
00122     {
00123       found = GetClipboardDataByID( CF_TEXT, aFlavor );
00124     }
00125     else if (strstr( aFlavor, "image/" ))
00126     {
00127       found = GetClipboardDataByID( CF_BITMAP, aFlavor );
00128     }
00129   }
00130 
00131   return found;
00132 }
00133 
00134 PRBool nsClipboard::GetClipboardDataByID(ULONG ulFormatID, const char *aFlavor)
00135 {
00136   PVOID pDataMem;
00137   PRUint32 NumOfBytes;
00138   PRBool TempBufAllocated = PR_FALSE;
00139 
00140   PVOID pClipboardData = NS_REINTERPRET_CAST(PVOID, WinQueryClipbrdData( 0, ulFormatID ));
00141 
00142   if (!pClipboardData) 
00143     return PR_FALSE;
00144 
00145   if (strstr( aFlavor, "text/" ))  // All text/.. flavors are null-terminated
00146   {
00147     pDataMem = pClipboardData;
00148 
00149     if (ulFormatID == CF_TEXT)     // CF_TEXT is one byte character set
00150     {
00151       PRUint32 NumOfChars = strlen( NS_STATIC_CAST (char*, pDataMem) );
00152       NumOfBytes = NumOfChars;
00153 
00154       if (!strcmp( aFlavor, kUnicodeMime ))  // Asked for unicode, but only plain text available.  Convert it!
00155       {
00156         nsAutoChar16Buffer buffer;
00157         PRInt32 bufLength;
00158         MultiByteToWideChar(0, NS_STATIC_CAST(char*, pDataMem), NumOfChars,
00159                             buffer, bufLength);
00160         pDataMem = ToNewUnicode(nsDependentString(buffer.get()));
00161         TempBufAllocated = PR_TRUE;
00162         NumOfBytes = bufLength * sizeof(UniChar);
00163       }
00164 
00165     }
00166     else                           // All other text/.. flavors are in unicode
00167     {
00168       PRUint32 NumOfChars = UniStrlen( NS_STATIC_CAST(UniChar*, pDataMem) );
00169       NumOfBytes = NumOfChars * sizeof(UniChar);
00170       PVOID pTempBuf = nsMemory::Alloc(NumOfBytes);
00171       memcpy(pTempBuf, pDataMem, NumOfBytes);
00172       pDataMem = pTempBuf;
00173       TempBufAllocated = PR_TRUE;
00174     }
00175 
00176     // DOM wants LF only, so convert from CRLF
00177     nsLinebreakHelpers::ConvertPlatformToDOMLinebreaks( aFlavor, &pDataMem,   // pDataMem could be reallocated !!
00178                                                         NS_REINTERPRET_CAST(PRInt32*, &NumOfBytes) );  // yuck
00179 
00180   }
00181   else                             // Assume rest of flavors are binary data
00182   {
00183     if (ulFormatID == CF_BITMAP)
00184     {
00185       if (!strcmp( aFlavor, kJPEGImageMime ))
00186       {
00187         // OS2TODO  Convert bitmap to jpg
00188 #ifdef DEBUG
00189         printf( "nsClipboard:: No JPG found on clipboard; need to convert BMP\n");
00190 #endif
00191       }
00192       else if (!strcmp( aFlavor, kGIFImageMime ))
00193       {
00194         // OS2TODO  Convert bitmap to gif
00195 #ifdef DEBUG
00196         printf( "nsClipboard:: No GIF found on clipboard; need to convert BMP\n");
00197 #endif
00198       }
00199       else if (!strcmp( aFlavor, kPNGImageMime ))
00200       {
00201         // OS2TODO  Convert bitmap to png
00202 #ifdef DEBUG
00203         printf( "nsClipboard:: No PNG found on clipboard; need to convert BMP\n");
00204 #endif
00205       }
00206     }
00207     else
00208     {
00209       pDataMem = NS_STATIC_CAST(PBYTE, pClipboardData) + sizeof(PRUint32);
00210       NumOfBytes = *(NS_STATIC_CAST(PRUint32*, pClipboardData));
00211     }
00212   }
00213 
00214   nsCOMPtr<nsISupports> genericDataWrapper;
00215   nsPrimitiveHelpers::CreatePrimitiveForData( aFlavor, pDataMem, NumOfBytes, getter_AddRefs(genericDataWrapper) );
00216   nsresult errCode = mTransferable->SetTransferData( aFlavor, genericDataWrapper, NumOfBytes );
00217 #ifdef DEBUG
00218   if (errCode != NS_OK)
00219     printf( "nsClipboard:: Error setting data into transferable\n" );
00220 #endif
00221 
00222   if (TempBufAllocated)
00223     nsMemory::Free(pDataMem);
00224 
00225   return PR_TRUE;
00226 }
00227 
00228 
00229 // Set some data onto the clipboard
00230 void nsClipboard::SetClipboardData(const char *aFlavor)
00231 {
00232   void *pMozData = nsnull;
00233   PRUint32 NumOfBytes = 0;
00234 
00235   // Get the data from the transferable
00236   nsCOMPtr<nsISupports> genericDataWrapper;
00237   nsresult errCode = mTransferable->GetTransferData( aFlavor, getter_AddRefs(genericDataWrapper), &NumOfBytes );
00238 #ifdef DEBUG
00239   if (NS_FAILED(errCode)) printf( "nsClipboard:: Error getting data from transferable\n" );
00240 #endif
00241   if (NumOfBytes == 0) return;
00242   nsPrimitiveHelpers::CreateDataFromPrimitive( aFlavor, genericDataWrapper, &pMozData, NumOfBytes );
00243 
00244   /* If creating the data failed, just return */
00245   if (!pMozData) {
00246     return;
00247   }
00248 
00249   ULONG ulFormatID = GetFormatID( aFlavor );
00250 
00251   if (strstr( aFlavor, "text/" ))  // All text/.. flavors are null-terminated
00252   {
00253     if (ulFormatID == CF_TEXT)     // CF_TEXT is one byte character set
00254     {
00255       char* pByteMem = nsnull;
00256 
00257       if (DosAllocSharedMem( NS_REINTERPRET_CAST(PPVOID, &pByteMem), nsnull, NumOfBytes + sizeof(char), 
00258                              PAG_WRITE | PAG_COMMIT | OBJ_GIVEABLE ) == NO_ERROR)
00259       {
00260         memcpy( pByteMem, pMozData, NumOfBytes );       // Copy text string
00261         pByteMem[NumOfBytes] = '\0';                    // Append terminator
00262 
00263         // Don't copy text larger than 64K to the clipboard
00264         if (strlen(pByteMem) <= 0xFFFF) {
00265           WinSetClipbrdData( 0, NS_REINTERPRET_CAST(ULONG, pByteMem), ulFormatID, CFI_POINTER );
00266         } else {
00267           WinAlarm(HWND_DESKTOP, WA_ERROR);
00268         }
00269       }
00270     }
00271     else                           // All other text/.. flavors are in unicode
00272     {
00273       UniChar* pUnicodeMem = nsnull;
00274       PRUint32 NumOfChars = NumOfBytes / sizeof(UniChar);
00275    
00276       if (DosAllocSharedMem( NS_REINTERPRET_CAST(PPVOID, &pUnicodeMem), nsnull, NumOfBytes + sizeof(UniChar), 
00277                              PAG_WRITE | PAG_COMMIT | OBJ_GIVEABLE ) == NO_ERROR) 
00278       {
00279         memcpy( pUnicodeMem, pMozData, NumOfBytes );    // Copy text string
00280         pUnicodeMem[NumOfChars] = L'\0';                // Append terminator
00281 
00282         WinSetClipbrdData( 0, NS_REINTERPRET_CAST(ULONG, pUnicodeMem), ulFormatID, CFI_POINTER );
00283       }
00284 
00285       // If the flavor is unicode, we also put it on the clipboard as CF_TEXT
00286       // after conversion to locale charset.
00287 
00288       if (!strcmp( aFlavor, kUnicodeMime ))
00289       {
00290         char* pByteMem = nsnull;
00291 
00292         if (DosAllocSharedMem(NS_REINTERPRET_CAST(PPVOID, &pByteMem), nsnull,
00293                               NumOfBytes + 1, 
00294                               PAG_WRITE | PAG_COMMIT | OBJ_GIVEABLE ) == NO_ERROR) 
00295         {
00296           PRUnichar* uchtemp = (PRUnichar*)pMozData;
00297           for (PRUint32 i=0;i<NumOfChars;i++) {
00298             switch (uchtemp[i]) {
00299               case 0x2018:
00300               case 0x2019:
00301                 uchtemp[i] = 0x0027;
00302                 break;
00303               case 0x201C:
00304               case 0x201D:
00305                 uchtemp[i] = 0x0022;
00306                 break;
00307               case 0x2014:
00308                 uchtemp[i] = 0x002D;
00309                 break;
00310             }
00311           }
00312 
00313           nsAutoCharBuffer buffer;
00314           PRInt32 bufLength;
00315           WideCharToMultiByte(0, NS_STATIC_CAST(PRUnichar*, pMozData),
00316                               NumOfBytes, buffer, bufLength);
00317           memcpy(pByteMem, buffer.get(), NumOfBytes);
00318           // Don't copy text larger than 64K to the clipboard
00319           if (strlen(pByteMem) <= 0xFFFF) {
00320             WinSetClipbrdData(0, NS_REINTERPRET_CAST(ULONG, pByteMem), CF_TEXT,
00321                               CFI_POINTER);
00322           } else {
00323             WinAlarm(HWND_DESKTOP, WA_ERROR);
00324           }
00325         }
00326       }
00327     }
00328   }
00329   else                             // Assume rest of flavors are binary data
00330   {
00331     PBYTE pBinaryMem = nsnull;
00332 
00333     if (DosAllocSharedMem( NS_REINTERPRET_CAST(PPVOID, &pBinaryMem), nsnull, NumOfBytes + sizeof(PRUint32), 
00334                            PAG_WRITE | PAG_COMMIT | OBJ_GIVEABLE ) == NO_ERROR) 
00335     {
00336       *(NS_REINTERPRET_CAST(PRUint32*, pBinaryMem)) = NumOfBytes;          // First DWORD contains data length
00337       memcpy( pBinaryMem + sizeof(PRUint32), pMozData, NumOfBytes );  // Copy binary data
00338 
00339       WinSetClipbrdData( 0, NS_REINTERPRET_CAST(ULONG, pBinaryMem), ulFormatID, CFI_POINTER );
00340     }
00341 
00342     // If the flavor is image, we also put it on clipboard as CF_BITMAP
00343     // after conversion to OS2 bitmap
00344 
00345     if (strstr (aFlavor, "image/"))
00346     {
00347       //  XXX OS2TODO  Convert jpg, gif, png to bitmap
00348 #ifdef DEBUG
00349       printf( "nsClipboard:: Putting image on clipboard; should also convert to BMP\n" );
00350 #endif
00351     }
00352   }
00353   nsMemory::Free(pMozData);
00354 }
00355 
00356 // Go through the flavors in the transferable and either get or set them
00357 nsresult nsClipboard::DoClipboardAction(ClipboardAction aAction)
00358 {
00359   nsresult rc = NS_ERROR_FAILURE;
00360 
00361   if (WinOpenClipbrd(0/*hab*/)) {
00362 
00363     if (aAction == Write)
00364       WinEmptyClipbrd(0/*hab*/);
00365 
00366     // Get the list of formats the transferable can handle
00367     nsCOMPtr<nsISupportsArray> pFormats;
00368     if(aAction == Read)
00369       rc = mTransferable->FlavorsTransferableCanImport(getter_AddRefs(pFormats));
00370     else
00371       rc = mTransferable->FlavorsTransferableCanExport(getter_AddRefs(pFormats));
00372 
00373     if (NS_FAILED(rc))
00374       return NS_ERROR_FAILURE;
00375 
00376     PRUint32 cFormats = 0;
00377     pFormats->Count(&cFormats);
00378 
00379     for (PRUint32 i = 0; i < cFormats; i++) {
00380 
00381       nsCOMPtr<nsISupports> genericFlavor;
00382       pFormats->GetElementAt(i, getter_AddRefs(genericFlavor));
00383       nsCOMPtr<nsISupportsCString> currentFlavor(do_QueryInterface(genericFlavor));
00384 
00385       if (currentFlavor) {
00386         nsXPIDLCString flavorStr;
00387         currentFlavor->ToString(getter_Copies(flavorStr));
00388 
00389         if (aAction == Read) {
00390           if (GetClipboardData(flavorStr))
00391             break;
00392         }
00393         else
00394           SetClipboardData(flavorStr);
00395       }
00396     }
00397     WinCloseClipbrd(0/*hab*/);
00398     rc = NS_OK;
00399   }
00400   return rc;
00401 }
00402 
00403 // get the format ID for a given mimetype
00404 ULONG nsClipboard::GetFormatID(const char *aMimeStr)
00405 {
00406   if (strcmp(aMimeStr, kTextMime) == 0)
00407     return CF_TEXT;
00408 
00409   return RegisterClipboardFormat(aMimeStr);
00410 }
00411 
00412 // nsIObserver
00413 NS_IMETHODIMP
00414 nsClipboard::Observe(nsISupports *aSubject, const char *aTopic,
00415                      const PRUnichar *aData)
00416 {
00417   // This will be called on shutdown.
00418 
00419   // make sure we have a good transferable
00420   if (!mTransferable)
00421     return NS_ERROR_FAILURE;
00422 
00423   if (WinOpenClipbrd(0/*hab*/)) {
00424     WinEmptyClipbrd(0/*hab*/);
00425 
00426     // get flavor list that includes all flavors that can be written (including ones
00427     // obtained through conversion)
00428     nsCOMPtr<nsISupportsArray> flavorList;
00429     nsresult errCode = mTransferable->FlavorsTransferableCanExport(getter_AddRefs(flavorList));
00430     if (NS_FAILED(errCode))
00431       return NS_ERROR_FAILURE;
00432 
00433     // Walk through flavors and put data on to clipboard
00434     PRUint32 i;
00435     PRUint32 cnt;
00436     flavorList->Count(&cnt);
00437     for (i = 0; i < cnt; i++) {
00438       nsCOMPtr<nsISupports> genericFlavor;
00439       flavorList->GetElementAt(i, getter_AddRefs(genericFlavor));
00440       nsCOMPtr<nsISupportsCString> currentFlavor(do_QueryInterface(genericFlavor));
00441       if (currentFlavor) {
00442         nsXPIDLCString flavorStr;
00443         currentFlavor->ToString(getter_Copies(flavorStr));
00444         SetClipboardData(flavorStr);
00445       }
00446     }
00447     WinCloseClipbrd(0/*hab*/);
00448   }
00449   return NS_OK;
00450 }
00451 
00452 NS_IMETHODIMP nsClipboard::HasDataMatchingFlavors(nsISupportsArray *aFlavorList, PRInt32 aWhichClipboard,
00453                                                   PRBool *_retval)
00454 {
00455   *_retval = PR_FALSE;
00456   if (aWhichClipboard != kGlobalClipboard)
00457     return NS_OK;
00458 
00459   PRUint32 cnt;
00460   aFlavorList->Count(&cnt);
00461   for (PRUint32 i = 0; i < cnt; ++i) {
00462     nsCOMPtr<nsISupports> genericFlavor;
00463     aFlavorList->GetElementAt(i, getter_AddRefs(genericFlavor));
00464     nsCOMPtr<nsISupportsCString> currentFlavor(do_QueryInterface(genericFlavor));
00465     if (currentFlavor) {
00466       nsXPIDLCString flavorStr;
00467       currentFlavor->ToString(getter_Copies(flavorStr));
00468       ULONG fmtInfo = 0;
00469       ULONG format = GetFormatID(flavorStr);
00470 
00471       if (WinQueryClipbrdFmtInfo(0/*hab*/, format, &fmtInfo)) {
00472         *_retval = PR_TRUE;
00473         break;
00474       }
00475 
00476       // if the client asked for unicode and it wasn't present, check if we have CF_TEXT.
00477       if (!strcmp( flavorStr, kUnicodeMime )) {
00478         if (WinQueryClipbrdFmtInfo( 0/*hab*/, CF_TEXT, &fmtInfo )) {
00479           *_retval = PR_TRUE;
00480           break;
00481         }
00482       }
00483 
00484 // OS2TODO - Support for Images
00485       // if the client asked for image/.. and it wasn't present, check if we have CF_BITMAP.
00486       if (strstr (flavorStr, "image/")) {
00487         if (WinQueryClipbrdFmtInfo (0, CF_BITMAP, &fmtInfo)) {
00488 #ifdef DEBUG
00489           printf( "nsClipboard:: Image present on clipboard; need to add BMP conversion!\n" );
00490 #endif
00491 //          *_retval = PR_TRUE;
00492 //          break;
00493         }
00494       }
00495     }
00496   }
00497   return NS_OK;
00498 }