Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / widget / src / photon / nsClipboard.cpp
blob1a6a291c3be22b002839e4ee73049f15a1d4b9ab
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
3 * ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
16 * The Original Code is mozilla.org code.
18 * The Initial Developer of the Original Code is
19 * Netscape Communications Corporation.
20 * Portions created by the Initial Developer are Copyright (C) 1999-2000
21 * the Initial Developer. All Rights Reserved.
23 * Contributor(s):
24 * Stuart Parmenter <pavlov@netscape.com>
25 * Mike Pinkerton <pinkerton@netscape.com>
26 * Dan Rosen <dr@netscape.com>
28 * Alternatively, the contents of this file may be used under the terms of
29 * either the GNU General Public License Version 2 or later (the "GPL"), or
30 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
31 * in which case the provisions of the GPL or the LGPL are applicable instead
32 * of those above. If you wish to allow use of your version of this file only
33 * under the terms of either the GPL or the LGPL, and not to allow others to
34 * use your version of this file under the terms of the MPL, indicate your
35 * decision by deleting the provisions above and replace them with the notice
36 * and other provisions required by the GPL or the LGPL. If you do not delete
37 * the provisions above, a recipient may use your version of this file under
38 * the terms of any one of the MPL, the GPL or the LGPL.
40 * ***** END LICENSE BLOCK ***** */
42 #include "nsClipboard.h"
44 #include <Pt.h>
46 #include "nsCOMPtr.h"
47 #include "nsCRT.h"
48 #include "nsISupportsArray.h"
49 #include "nsISupportsPrimitives.h"
50 #include "nsReadableUtils.h"
52 #include "nsIComponentManager.h"
53 #include "nsIServiceManager.h"
54 #include "nsWidgetsCID.h"
55 #include "nsXPIDLString.h"
56 #include "nsReadableUtils.h"
57 #include "nsPrimitiveHelpers.h"
59 #include "nsTextFormatter.h"
61 #include "nsIServiceManager.h"
62 #include "nsICharsetConverterManager.h"
64 #include "prtime.h"
65 #include "prthread.h"
67 // unicode conversion
68 #include "nsIPlatformCharset.h"
69 #include "nsICharsetConverterManager.h"
71 //#define DEBUG_CLIPBOARD
74 // Define this to enable the obsolete X cut buffer mechanism
75 // In general, a bad idea (see http://www.jwz.org/doc/x-cut-and-paste.html)
76 // but it might have its uses for backwards compatibility.
78 NS_IMPL_ISUPPORTS1(nsClipboard, nsIClipboard)
80 #define Ph_CLIPBOARD_TYPE_MOZ_BOOKMARK "BOOK"
81 #define Ph_CLIPBOARD_TYPE_IMAGE "IMAG"
82 #define Ph_CLIPBOARD_TYPE_HTML "HTML"
84 //-------------------------------------------------------------------------
86 // nsClipboard constructor
88 //-------------------------------------------------------------------------
89 nsClipboard::nsClipboard()
91 #ifdef DEBUG_CLIPBOARD
92 printf("nsClipboard::nsClipboard()\n");
93 #endif /* DEBUG_CLIPBOARD */
95 mIgnoreEmptyNotification = PR_FALSE;
96 mGlobalTransferable = nsnull;
97 mSelectionTransferable = nsnull;
98 mGlobalOwner = nsnull;
99 mSelectionOwner = nsnull;
100 mInputGroup = 1;
103 //-------------------------------------------------------------------------
105 // nsClipboard destructor
107 //-------------------------------------------------------------------------
108 nsClipboard::~nsClipboard()
110 #ifdef DEBUG_CLIPBOARD
111 printf("nsClipboard::~nsClipboard()\n");
112 #endif /* DEBUG_CLIPBOARD */
116 * Sets the transferable object
119 NS_IMETHODIMP nsClipboard::SetData(nsITransferable * aTransferable,
120 nsIClipboardOwner * anOwner,
121 PRInt32 aWhichClipboard)
123 if (aWhichClipboard == kSelectionClipboard)
124 return (NS_ERROR_FAILURE);
126 if ((aTransferable == mGlobalTransferable.get() && anOwner == mGlobalOwner.get() &&
127 aWhichClipboard == kGlobalClipboard ) || (aTransferable == mSelectionTransferable.get() &&
128 anOwner == mSelectionOwner.get() && aWhichClipboard == kSelectionClipboard))
130 return NS_OK;
133 EmptyClipboard(aWhichClipboard);
135 switch (aWhichClipboard)
137 case kSelectionClipboard:
138 mSelectionOwner = anOwner;
139 mSelectionTransferable = aTransferable;
140 break;
141 case kGlobalClipboard:
142 mGlobalOwner = anOwner;
143 mGlobalTransferable = aTransferable;
144 break;
147 return SetNativeClipboardData(aWhichClipboard);
151 * Gets the transferable object
154 NS_IMETHODIMP nsClipboard::GetData(nsITransferable * aTransferable, PRInt32 aWhichClipboard)
156 if (aWhichClipboard == kSelectionClipboard)
157 return (NS_ERROR_FAILURE);
158 if (nsnull != aTransferable)
159 return GetNativeClipboardData(aTransferable, aWhichClipboard);
160 else
162 #ifdef DEBUG_CLIPBOARD
163 printf(" nsClipboard::GetData(), aTransferable is NULL.\n");
164 #endif
167 return NS_ERROR_FAILURE;
175 NS_IMETHODIMP nsClipboard::EmptyClipboard(PRInt32 aWhichClipboard)
177 if (mIgnoreEmptyNotification)
178 return NS_OK;
180 if (aWhichClipboard == kSelectionClipboard)
181 return (NS_ERROR_FAILURE);
183 switch(aWhichClipboard)
185 case kSelectionClipboard:
186 return NS_ERROR_FAILURE;
187 if (mSelectionOwner)
189 mSelectionOwner->LosingOwnership(mSelectionTransferable);
190 mSelectionOwner = nsnull;
192 mSelectionTransferable = nsnull;
193 break;
194 case kGlobalClipboard:
195 if (mGlobalOwner)
197 mGlobalOwner->LosingOwnership(mGlobalTransferable);
198 mGlobalOwner = nsnull;
200 mGlobalTransferable = nsnull;
201 break;
204 return NS_OK;
207 NS_IMETHODIMP nsClipboard::SupportsSelectionClipboard(PRBool *_retval)
209 NS_ENSURE_ARG_POINTER(_retval);
211 *_retval = PR_FALSE; // we support the selection clipboard on unix.
212 return NS_ERROR_FAILURE;
215 //-------------------------------------------------------------------------
216 NS_IMETHODIMP nsClipboard::SetNativeClipboardData(PRInt32 aWhichClipboard)
218 mIgnoreEmptyNotification = PR_TRUE;
219 if (aWhichClipboard == kSelectionClipboard)
220 return (NS_ERROR_FAILURE);
222 #ifdef DEBUG_CLIPBOARD
223 printf(" nsClipboard::SetNativeClipboardData(%i)\n", aWhichClipboard);
224 #endif /* DEBUG_CLIPBOARD */
226 nsCOMPtr<nsITransferable> transferable(GetTransferable(aWhichClipboard));
228 // make sure we have a good transferable
229 if (nsnull == transferable)
231 #ifdef DEBUG_CLIPBOARD
232 printf("nsClipboard::SetNativeClipboardData(): no transferable!\n");
233 #endif
234 return NS_ERROR_FAILURE;
237 // get flavor list that includes all flavors that can be written (including ones
238 // obtained through conversion)
239 nsCOMPtr<nsISupportsArray> flavorList;
240 nsresult errCode = transferable->FlavorsTransferableCanExport ( getter_AddRefs(flavorList) );
241 if ( NS_FAILED(errCode) )
242 return NS_ERROR_FAILURE;
244 PRUint32 cnt, index = 0;
245 flavorList->Count(&cnt);
246 PhClipHeader *cliphdr = (PhClipHeader *) calloc( cnt, sizeof( PhClipHeader ));
247 if( !cliphdr ) return NS_ERROR_FAILURE;
249 for ( PRUint32 k=0; k<cnt; ++k )
251 void *data = nsnull;
252 PRUint32 dataLen;
254 nsCOMPtr<nsISupports> genericFlavor;
255 flavorList->GetElementAt ( k, getter_AddRefs(genericFlavor) );
256 nsCOMPtr<nsISupportsCString> currentFlavor ( do_QueryInterface(genericFlavor) );
257 if ( currentFlavor )
259 nsXPIDLCString flavorStr;
260 currentFlavor->ToString(getter_Copies(flavorStr));
262 nsresult err = GetFormat( flavorStr, cliphdr[index].type );
263 if( err != NS_OK )
264 continue;
266 // Get data out of transferable.
267 nsCOMPtr<nsISupports> genericDataWrapper;
268 transferable->GetTransferData( flavorStr, getter_AddRefs(genericDataWrapper), &dataLen );
269 nsPrimitiveHelpers::CreateDataFromPrimitive ( flavorStr, genericDataWrapper, &data, dataLen );
271 if( !strcmp(cliphdr[index].type, Ph_CLIPBOARD_TYPE_TEXT) ||
272 !strcmp(cliphdr[index].type, Ph_CLIPBOARD_TYPE_HTML) ||
273 !strcmp(cliphdr[index].type, Ph_CLIPBOARD_TYPE_MOZ_BOOKMARK) )
275 PRUnichar* castedUnicode = reinterpret_cast<PRUnichar*>(data);
276 char *utf8String = ToNewUTF8String(nsDependentString(castedUnicode, dataLen/2));
277 nsMemory::Free(reinterpret_cast<char*>(data));
279 if( !strcmp(cliphdr[index].type, Ph_CLIPBOARD_TYPE_TEXT) )
281 /* we have to create a null terminated string, because
282 PhClipboardCopyString does that and some other applications
283 rely on the null terminated thing
285 PRInt32 len = strlen(utf8String);
286 char *temp = ( char * ) nsMemory::Alloc( len + 1 );
287 memcpy( temp, utf8String, len );
288 temp[len] = 0;
289 nsMemory::Free(reinterpret_cast<char*>(utf8String));
291 cliphdr[index].length = len+1;
292 cliphdr[index].data = temp;
294 else {
295 cliphdr[index].length = strlen(utf8String);
296 cliphdr[index].data = utf8String;
299 index++;
303 PhClipboardCopy( mInputGroup, index, cliphdr );
304 for( PRUint32 k=0; k<index; k++)
305 nsMemory::Free(reinterpret_cast<char*>(cliphdr[k].data));
307 free( cliphdr );
309 mIgnoreEmptyNotification = PR_FALSE;
311 return NS_OK;
315 //-------------------------------------------------------------------------
317 // The blocking Paste routine
319 //-------------------------------------------------------------------------
320 NS_IMETHODIMP
321 nsClipboard::GetNativeClipboardData(nsITransferable * aTransferable,
322 PRInt32 aWhichClipboard)
324 if (aWhichClipboard == kSelectionClipboard)
325 return (NS_ERROR_FAILURE);
327 #ifdef DEBUG_CLIPBOARD
328 printf("nsClipboard::GetNativeClipboardData(%i)\n", aWhichClipboard);
329 #endif /* DEBUG_CLIPBOARD */
331 // make sure we have a good transferable
332 if (nsnull == aTransferable)
334 #ifdef DEBUG_CLIPBOARD
335 printf(" GetNativeClipboardData: Transferable is null!\n");
336 #endif
337 return NS_ERROR_FAILURE;
340 // get flavor list that includes all acceptable flavors (including ones obtained through
341 // conversion)
342 nsCOMPtr<nsISupportsArray> flavorList;
343 nsresult errCode = aTransferable->FlavorsTransferableCanImport ( getter_AddRefs(flavorList) );
344 if ( NS_FAILED(errCode) )
345 return NS_ERROR_FAILURE;
347 // Walk through flavors and see which flavor matches the one being pasted:
348 PRUint32 cnt;
349 flavorList->Count(&cnt);
350 nsCAutoString foundFlavor;
352 if (cnt > 0)
354 void *clipPtr;
355 PhClipHeader *cliphdr;
356 char *data = nsnull, type[8];
357 PRUint32 dataLen;
359 clipPtr = PhClipboardPasteStart( mInputGroup );
360 if(!clipPtr) return NS_ERROR_FAILURE;
363 Look at the timestamps of the data in the clipboard and eliminate the flavours if they are not synchronized.
364 We can have a HTML flavour from a previous copy and a TEXT flavour from a more recent copy from another application
365 ( from instance from ped or pterm ). The HTML flavour and TEXT flavour are desynchronized and we have
366 to use only the most recent one */
367 unsigned long *dont_use_flavour = ( unsigned long * ) calloc( cnt, sizeof( unsigned long ) );
368 if( !dont_use_flavour ) {
369 PhClipboardPasteFinish( clipPtr );
370 return NS_ERROR_FAILURE;
373 unsigned long max_time = 0;
374 PRUint32 i;
376 for ( i = 0; i < cnt; ++i )
378 nsCOMPtr<nsISupports> genericFlavor;
379 flavorList->GetElementAt ( i, getter_AddRefs(genericFlavor) );
380 nsCOMPtr<nsISupportsCString> currentFlavor ( do_QueryInterface(genericFlavor) );
381 if ( currentFlavor )
383 nsXPIDLCString flavorStr;
384 currentFlavor->ToString ( getter_Copies(flavorStr) );
386 nsresult err = GetFormat( flavorStr, type );
387 if (err != NS_OK)
388 continue;
390 dont_use_flavour[i] = GetFlavourTimestamp( type );
391 if( dont_use_flavour[i] > max_time ) max_time = dont_use_flavour[i];
395 for ( i = 0; i < cnt; ++i )
397 if( abs( dont_use_flavour[i] - max_time ) >= 4 )
398 dont_use_flavour[i] = 1; /* this flavour is desynchronized */
399 else dont_use_flavour[i] = 0; /* this flavour is ok */
402 for ( i = 0; i < cnt; ++i )
404 if( dont_use_flavour[i] ) continue; /* this flavour is desynchronized */
405 nsCOMPtr<nsISupports> genericFlavor;
406 flavorList->GetElementAt ( i, getter_AddRefs(genericFlavor) );
407 nsCOMPtr<nsISupportsCString> currentFlavor ( do_QueryInterface(genericFlavor) );
408 if ( currentFlavor )
410 nsXPIDLCString flavorStr;
411 currentFlavor->ToString ( getter_Copies(flavorStr) );
413 nsresult err = GetFormat( flavorStr, type );
414 if (err != NS_OK)
415 continue;
417 cliphdr = PhClipboardPasteType( clipPtr, type );
418 if (cliphdr)
420 data = (char*)cliphdr->data;
422 if( !strcmp(type, Ph_CLIPBOARD_TYPE_TEXT) )
423 /* for the Ph_CLIPBOARD_TYPE_TEXT, we null terminate the data, since PhClipboardCopyString() does that */
424 dataLen = cliphdr->length - 1;
425 else dataLen = cliphdr->length;
428 if( !strcmp(type, Ph_CLIPBOARD_TYPE_TEXT) ||
429 !strcmp(type, Ph_CLIPBOARD_TYPE_HTML) ||
430 !strcmp(type, Ph_CLIPBOARD_TYPE_MOZ_BOOKMARK) )
432 nsresult rv;
433 PRInt32 outUnicodeLen;
434 PRUnichar *unicodeData = nsnull;
436 // get the decoder
437 nsCOMPtr<nsIUnicodeDecoder> decoder;
438 nsCOMPtr<nsICharsetConverterManager> ccm = do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv);
439 rv = ccm->GetUnicodeDecoderRaw("UTF-8", getter_AddRefs(decoder));
441 if( NS_SUCCEEDED(rv) )
444 decoder->GetMaxLength(data, dataLen, &outUnicodeLen); // |outUnicodeLen| is number of chars
445 if (outUnicodeLen) {
446 unicodeData = reinterpret_cast<PRUnichar*>(nsMemory::Alloc((outUnicodeLen + 1) * sizeof(PRUnichar)));
447 if ( unicodeData ) {
448 PRInt32 numberTmp = dataLen;
449 rv = decoder->Convert(data, &numberTmp, unicodeData, &outUnicodeLen);
450 #ifdef DEBUG_CLIPBOARD
451 if (numberTmp != dataLen)
452 printf("didn't consume all the bytes\n");
453 #endif
455 (unicodeData)[outUnicodeLen] = '\0'; // null terminate. Convert() doesn't do it for us
457 } // if valid length
460 data = reinterpret_cast<char*>(unicodeData);
461 dataLen = outUnicodeLen * 2;
463 nsCOMPtr<nsISupports> genericDataWrapper;
464 nsPrimitiveHelpers::CreatePrimitiveForData( flavorStr, data, dataLen, getter_AddRefs(genericDataWrapper) );
465 aTransferable->SetTransferData( flavorStr, genericDataWrapper, dataLen );
467 /* free the allocated memory */
468 nsMemory::Free( unicodeData );
470 break;
477 free( dont_use_flavour );
478 PhClipboardPasteFinish( clipPtr );
481 return NS_OK;
484 NS_IMETHODIMP
485 nsClipboard::HasDataMatchingFlavors(const char** aFlavorList,
486 PRUint32 aLength,
487 PRInt32 aWhichClipboard,
488 PRBool * outResult)
490 if (aWhichClipboard == kSelectionClipboard)
491 return (NS_ERROR_FAILURE);
492 // XXX this doesn't work right. need to fix it.
494 // Note to implementor...(from pink the clipboard bitch).
496 // If a client asks for unicode, first check if unicode is present. If not, then
497 // check for plain text. If it's there, say "yes" as we will do the conversion
498 // in GetNativeClipboardData(). From this point on, no client will
499 // ever ask for text/plain explicitly. If they do, you must ASSERT!
500 #ifdef DEBUG_CLIPBOARD
501 printf(" nsClipboard::HasDataMatchingFlavors()\n {\n");
502 #endif
504 nsresult res = NS_OK;
505 * outResult = PR_FALSE;
507 // Walk through flavors and see which flavor matches the one being pasted:
508 nsCAutoString foundFlavor;
509 if (aLength > 0) {
510 void *clipPtr;
511 char type[8];
512 PhClipHeader *cliphdr;
514 clipPtr = PhClipboardPasteStart( 1 );
515 if(nsnull == clipPtr)
516 return res;
518 for ( PRUint32 i = 0; i < aLength; ++i ) {
519 nsresult err = GetFormat( aFlavorList[i], type );
520 if (err != NS_OK) continue;
522 cliphdr = PhClipboardPasteType( clipPtr, type );
523 if (cliphdr)
525 res = NS_OK;
526 *outResult = PR_TRUE;
527 break;
530 PhClipboardPasteFinish( clipPtr );
533 return res;
537 nsresult nsClipboard::GetFormat(const char* aMimeStr, char *format )
539 nsDependentCString mimeStr(aMimeStr);
540 int ret = NS_OK;
542 if( mimeStr.Equals(kUnicodeMime) || mimeStr.Equals(kTextMime) )
543 strcpy( format, Ph_CLIPBOARD_TYPE_TEXT );
544 else if( mimeStr.Equals(kHTMLMime) )
545 strcpy( format, Ph_CLIPBOARD_TYPE_HTML );
546 else if (mimeStr.Equals("moz/bookmarkclipboarditem"))
547 strcpy( format, Ph_CLIPBOARD_TYPE_MOZ_BOOKMARK );
548 else ret = NS_ERROR_FAILURE;
549 return ret;
552 /* inline */
553 nsITransferable *nsClipboard::GetTransferable(PRInt32 aWhichClipboard)
555 nsITransferable *transferable = nsnull;
556 switch (aWhichClipboard)
558 case kGlobalClipboard:
559 transferable = mGlobalTransferable;
560 break;
561 case kSelectionClipboard:
562 break;
564 return transferable;
567 unsigned long nsClipboard::GetFlavourTimestamp( char *type)
569 char fname[512];
570 extern struct _Ph_ctrl *_Ph_;
572 strcpy( fname, "/var/clipboard/" );
573 if( access( fname, X_OK ) != 0 )
574 return 0;
576 struct stat buf;
577 if( fstat( _Ph_->fd, &buf ) != 0 )
578 return 0;
580 if(gethostname(&fname[strlen(fname)],PATH_MAX-40)!=0)
581 strcpy(&fname[strlen(fname)],"localhost");
583 sprintf( &fname[strlen(fname)], "/%08x/%d.%s",buf.st_uid, mInputGroup, type );
584 struct stat st;
585 if( stat( fname, &st ) != 0 )
586 return 0;
588 return st.st_mtime;