NS_IMETHODIMP nsClipboard::HasDataMatchingFlavors(nsISupportsArray *aFlavorList, PRInt32 aWhichClipboard, PRBool *_retval) { *_retval = PR_FALSE; PRUint32 length = 0; aFlavorList->Count(&length); if (!length) return NS_OK; GtkSelectionData *selection_data = GetTargets(GetSelectionAtom(aWhichClipboard)); if (!selection_data) return NS_OK; gint n_targets = 0; GdkAtom *targets = NULL; if (!gtk_selection_data_get_targets(selection_data, &targets, &n_targets) || !n_targets) return NS_OK; // Walk through the provided types and try to match it to a // provided type. for (PRUint32 i = 0; i < length && !*_retval; i++) { nsCOMPtr<nsISupports> genericFlavor; aFlavorList->GetElementAt(i, getter_AddRefs(genericFlavor)); nsCOMPtr<nsISupportsCString> flavorWrapper; flavorWrapper = do_QueryInterface(genericFlavor); if (flavorWrapper) { nsXPIDLCString myStr; flavorWrapper->ToString(getter_Copies(myStr)); // We special case text/unicode here. if (!strcmp(myStr, kUnicodeMime) && gtk_selection_data_targets_include_text(selection_data)) { *_retval = PR_TRUE; break; } for (PRInt32 j = 0; j < n_targets; j++) { gchar *atom_name = gdk_atom_name(targets[j]); if (!strcmp(atom_name, (const char *)myStr)) *_retval = PR_TRUE; g_free(atom_name); if (*_retval) break; } } } gtk_selection_data_free(selection_data); g_free(targets); return NS_OK; }
NS_IMETHODIMP nsClipboard::HasDataMatchingFlavors(const char** aFlavorList, PRUint32 aLength, PRInt32 aWhichClipboard, PRBool *_retval) { if (!aFlavorList || !_retval) return NS_ERROR_NULL_POINTER; *_retval = PR_FALSE; GtkSelectionData *selection_data = GetTargets(GetSelectionAtom(aWhichClipboard)); if (!selection_data) return NS_OK; gint n_targets = 0; GdkAtom *targets = NULL; if (!gtk_selection_data_get_targets(selection_data, &targets, &n_targets) || !n_targets) return NS_OK; // Walk through the provided types and try to match it to a // provided type. for (PRUint32 i = 0; i < aLength && !*_retval; i++) { // We special case text/unicode here. if (!strcmp(aFlavorList[i], kUnicodeMime) && gtk_selection_data_targets_include_text(selection_data)) { *_retval = PR_TRUE; break; } for (PRInt32 j = 0; j < n_targets; j++) { gchar *atom_name = gdk_atom_name(targets[j]); if (!atom_name) continue; if (!strcmp(atom_name, aFlavorList[i])) *_retval = PR_TRUE; // X clipboard wants image/jpeg, not image/jpg if (!strcmp(aFlavorList[i], kJPEGImageMime) && !strcmp(atom_name, "image/jpeg")) *_retval = PR_TRUE; g_free(atom_name); if (*_retval) break; } } gtk_selection_data_free(selection_data); g_free(targets); return NS_OK; }
NS_IMETHODIMP nsClipboard::GetData(nsITransferable *aTransferable, PRInt32 aWhichClipboard) { if (!aTransferable) return NS_ERROR_FAILURE; GtkClipboard *clipboard; clipboard = gtk_clipboard_get(GetSelectionAtom(aWhichClipboard)); guchar *data = NULL; gint length = 0; PRBool foundData = PR_FALSE; nsCAutoString foundFlavor; // Get a list of flavors this transferable can import nsCOMPtr<nsISupportsArray> flavors; nsresult rv; rv = aTransferable->FlavorsTransferableCanImport(getter_AddRefs(flavors)); if (!flavors || NS_FAILED(rv)) return NS_ERROR_FAILURE; PRUint32 count; flavors->Count(&count); for (PRUint32 i=0; i < count; i++) { nsCOMPtr<nsISupports> genericFlavor; flavors->GetElementAt(i, getter_AddRefs(genericFlavor)); nsCOMPtr<nsISupportsCString> currentFlavor; currentFlavor = do_QueryInterface(genericFlavor); if (currentFlavor) { nsXPIDLCString flavorStr; currentFlavor->ToString(getter_Copies(flavorStr)); // Special case text/unicode since we can convert any // string into text/unicode if (!strcmp(flavorStr, kUnicodeMime)) { gchar* new_text = wait_for_text(clipboard); if (new_text) { // Convert utf-8 into our unicode format. NS_ConvertUTF8toUCS2 ucs2string(new_text); data = (guchar *)ToNewUnicode(ucs2string); length = ucs2string.Length() * 2; g_free(new_text); foundData = PR_TRUE; foundFlavor = kUnicodeMime; break; } // If the type was text/unicode and we couldn't get // text off the clipboard, run the next loop // iteration. continue; } // Get the atom for this type and try to request it off // the clipboard. GdkAtom atom = gdk_atom_intern(flavorStr, FALSE); GtkSelectionData *selectionData; selectionData = wait_for_contents(clipboard, atom); if (selectionData) { length = selectionData->length; // Special case text/html since we can convert into UCS2 if (!strcmp(flavorStr, kHTMLMime)) { PRUnichar* htmlBody= nsnull; PRInt32 htmlBodyLen = 0; // Convert text/html into our unicode format ConvertHTMLtoUCS2((guchar *)selectionData->data, length, &htmlBody, htmlBodyLen); if (!htmlBodyLen) break; data = (guchar *)htmlBody; length = htmlBodyLen * 2; } else { data = (guchar *)nsMemory::Alloc(length); if (!data) break; memcpy(data, selectionData->data, length); } foundData = PR_TRUE; foundFlavor = flavorStr; break; } } } if (foundData) { nsCOMPtr<nsISupports> wrapper; nsPrimitiveHelpers::CreatePrimitiveForData(foundFlavor.get(), data, length, getter_AddRefs(wrapper)); aTransferable->SetTransferData(foundFlavor.get(), wrapper, length); } if (data) nsMemory::Free(data); return NS_OK; }
NS_IMETHODIMP nsClipboard::SetData(nsITransferable *aTransferable, nsIClipboardOwner *aOwner, PRInt32 aWhichClipboard) { // See if we can short cut if ((aWhichClipboard == kGlobalClipboard && aTransferable == mGlobalTransferable.get() && aOwner == mGlobalOwner.get()) || (aWhichClipboard == kSelectionClipboard && aTransferable == mSelectionTransferable.get() && aOwner == mSelectionOwner.get())) { return NS_OK; } // Clear out the clipboard in order to set the new data EmptyClipboard(aWhichClipboard); if (aWhichClipboard == kSelectionClipboard) { mSelectionOwner = aOwner; mSelectionTransferable = aTransferable; } else { mGlobalOwner = aOwner; mGlobalTransferable = aTransferable; } // Which selection are we about to claim, CLIPBOARD or PRIMARY? GdkAtom selectionAtom = GetSelectionAtom(aWhichClipboard); // Make ourselves the owner. If we fail to, return. if (!gtk_selection_owner_set(mWidget, selectionAtom, GDK_CURRENT_TIME)) return NS_ERROR_FAILURE; // Clear the old selection target list. gtk_selection_clear_targets(mWidget, selectionAtom); // Get the types of supported flavors nsresult rv; nsCOMPtr<nsISupportsArray> flavors; rv = aTransferable->FlavorsTransferableCanExport(getter_AddRefs(flavors)); if (!flavors || NS_FAILED(rv)) return NS_ERROR_FAILURE; // Add all the flavors to this widget's supported type. PRUint32 count; flavors->Count(&count); for (PRUint32 i=0; i < count; i++) { nsCOMPtr<nsISupports> tastesLike; flavors->GetElementAt(i, getter_AddRefs(tastesLike)); nsCOMPtr<nsISupportsCString> flavor = do_QueryInterface(tastesLike); if (flavor) { nsXPIDLCString flavorStr; flavor->ToString(getter_Copies(flavorStr)); // special case text/unicode since we can handle all of // the string types if (!strcmp(flavorStr, kUnicodeMime)) { AddTarget(gdk_atom_intern("UTF8_STRING", FALSE), selectionAtom); AddTarget(gdk_atom_intern("COMPOUND_TEXT", FALSE), selectionAtom); AddTarget(gdk_atom_intern("TEXT", FALSE), selectionAtom); AddTarget(GDK_SELECTION_TYPE_STRING, selectionAtom); // next loop iteration continue; } // Add this to our list of valid targets GdkAtom atom = gdk_atom_intern(flavorStr, FALSE); AddTarget(atom, selectionAtom); } } return NS_OK; }
NS_IMETHODIMP nsClipboard::SetData(nsITransferable *aTransferable, nsIClipboardOwner *aOwner, PRInt32 aWhichClipboard) { // See if we can short cut if ((aWhichClipboard == kGlobalClipboard && aTransferable == mGlobalTransferable.get() && aOwner == mGlobalOwner.get()) || (aWhichClipboard == kSelectionClipboard && aTransferable == mSelectionTransferable.get() && aOwner == mSelectionOwner.get())) { return NS_OK; } nsresult rv; if (!mPrivacyHandler) { rv = NS_NewClipboardPrivacyHandler(getter_AddRefs(mPrivacyHandler)); NS_ENSURE_SUCCESS(rv, rv); } rv = mPrivacyHandler->PrepareDataForClipboard(aTransferable); NS_ENSURE_SUCCESS(rv, rv); // Clear out the clipboard in order to set the new data EmptyClipboard(aWhichClipboard); // List of suported targets GtkTargetList *list = gtk_target_list_new(NULL, 0); // Get the types of supported flavors nsCOMPtr<nsISupportsArray> flavors; rv = aTransferable->FlavorsTransferableCanExport(getter_AddRefs(flavors)); if (!flavors || NS_FAILED(rv)) return NS_ERROR_FAILURE; // Add all the flavors to this widget's supported type. PRBool imagesAdded = PR_FALSE; PRUint32 count; flavors->Count(&count); for (PRUint32 i=0; i < count; i++) { nsCOMPtr<nsISupports> tastesLike; flavors->GetElementAt(i, getter_AddRefs(tastesLike)); nsCOMPtr<nsISupportsCString> flavor = do_QueryInterface(tastesLike); if (flavor) { nsXPIDLCString flavorStr; flavor->ToString(getter_Copies(flavorStr)); // special case text/unicode since we can handle all of // the string types if (!strcmp(flavorStr, kUnicodeMime)) { gtk_target_list_add(list, gdk_atom_intern("UTF8_STRING", FALSE), 0, 0); gtk_target_list_add(list, gdk_atom_intern("COMPOUND_TEXT", FALSE), 0, 0); gtk_target_list_add(list, gdk_atom_intern("TEXT", FALSE), 0, 0); gtk_target_list_add(list, GDK_SELECTION_TYPE_STRING, 0, 0); continue; } if (flavorStr.EqualsLiteral(kNativeImageMime) || flavorStr.EqualsLiteral(kPNGImageMime) || flavorStr.EqualsLiteral(kJPEGImageMime) || flavorStr.EqualsLiteral(kGIFImageMime)) { // don't bother adding image targets twice if (!imagesAdded) { // accept any writable image type gtk_target_list_add_image_targets(list, 0, TRUE); imagesAdded = PR_TRUE; } continue; } // Add this to our list of valid targets GdkAtom atom = gdk_atom_intern(flavorStr, FALSE); gtk_target_list_add(list, atom, 0, 0); } } // Get GTK clipboard (CLIPBOARD or PRIMARY) GtkClipboard *gtkClipboard = gtk_clipboard_get(GetSelectionAtom(aWhichClipboard)); gint numTargets; GtkTargetEntry *gtkTargets = gtk_target_table_new_from_list(list, &numTargets); // Set getcallback and request to store data after an application exit if (gtk_clipboard_set_with_data(gtkClipboard, gtkTargets, numTargets, clipboard_get_cb, clipboard_clear_cb, this)) { // We managed to set-up the clipboard so update internal state // We have to set it now because gtk_clipboard_set_with_data() calls clipboard_clear_cb() // which reset our internal state if (aWhichClipboard == kSelectionClipboard) { mSelectionOwner = aOwner; mSelectionTransferable = aTransferable; } else { mGlobalOwner = aOwner; mGlobalTransferable = aTransferable; gtk_clipboard_set_can_store(gtkClipboard, gtkTargets, numTargets); } rv = NS_OK; } else { rv = NS_ERROR_FAILURE; } gtk_target_table_free(gtkTargets, numTargets); gtk_target_list_unref(list); return rv; }
NS_IMETHODIMP nsClipboard::GetData(nsITransferable *aTransferable, PRInt32 aWhichClipboard) { if (!aTransferable) return NS_ERROR_FAILURE; GtkClipboard *clipboard; clipboard = gtk_clipboard_get(GetSelectionAtom(aWhichClipboard)); guchar *data = NULL; gint length = 0; bool foundData = false; nsCAutoString foundFlavor; // Get a list of flavors this transferable can import nsCOMPtr<nsISupportsArray> flavors; nsresult rv; rv = aTransferable->FlavorsTransferableCanImport(getter_AddRefs(flavors)); if (!flavors || NS_FAILED(rv)) return NS_ERROR_FAILURE; PRUint32 count; flavors->Count(&count); for (PRUint32 i=0; i < count; i++) { nsCOMPtr<nsISupports> genericFlavor; flavors->GetElementAt(i, getter_AddRefs(genericFlavor)); nsCOMPtr<nsISupportsCString> currentFlavor; currentFlavor = do_QueryInterface(genericFlavor); if (currentFlavor) { nsXPIDLCString flavorStr; currentFlavor->ToString(getter_Copies(flavorStr)); // Special case text/unicode since we can convert any // string into text/unicode if (!strcmp(flavorStr, kUnicodeMime)) { gchar* new_text = wait_for_text(clipboard); if (new_text) { // Convert utf-8 into our unicode format. NS_ConvertUTF8toUTF16 ucs2string(new_text); data = (guchar *)ToNewUnicode(ucs2string); length = ucs2string.Length() * 2; g_free(new_text); foundData = true; foundFlavor = kUnicodeMime; break; } // If the type was text/unicode and we couldn't get // text off the clipboard, run the next loop // iteration. continue; } // For images, we must wrap the data in an nsIInputStream then return instead of break, // because that code below won't help us. if (!strcmp(flavorStr, kJPEGImageMime) || !strcmp(flavorStr, kPNGImageMime) || !strcmp(flavorStr, kGIFImageMime)) { GdkAtom atom; if (!strcmp(flavorStr, kJPEGImageMime)) // This is image/jpg, but X only understands image/jpeg atom = gdk_atom_intern("image/jpeg", FALSE); else atom = gdk_atom_intern(flavorStr, FALSE); GtkSelectionData *selectionData = wait_for_contents(clipboard, atom); if (!selectionData) continue; nsCOMPtr<nsIInputStream> byteStream; NS_NewByteInputStream(getter_AddRefs(byteStream), (const char*)selectionData->data, selectionData->length, NS_ASSIGNMENT_COPY); aTransferable->SetTransferData(flavorStr, byteStream, sizeof(nsIInputStream*)); gtk_selection_data_free(selectionData); return NS_OK; } // Get the atom for this type and try to request it off // the clipboard. GdkAtom atom = gdk_atom_intern(flavorStr, FALSE); GtkSelectionData *selectionData; selectionData = wait_for_contents(clipboard, atom); if (selectionData) { length = selectionData->length; // Special case text/html since we can convert into UCS2 if (!strcmp(flavorStr, kHTMLMime)) { PRUnichar* htmlBody= nsnull; PRInt32 htmlBodyLen = 0; // Convert text/html into our unicode format ConvertHTMLtoUCS2((guchar *)selectionData->data, length, &htmlBody, htmlBodyLen); // Try next data format? if (!htmlBodyLen) continue; data = (guchar *)htmlBody; length = htmlBodyLen * 2; } else { data = (guchar *)nsMemory::Alloc(length); if (!data) break; memcpy(data, selectionData->data, length); } foundData = true; foundFlavor = flavorStr; break; } } } if (foundData) { nsCOMPtr<nsISupports> wrapper; nsPrimitiveHelpers::CreatePrimitiveForData(foundFlavor.get(), data, length, getter_AddRefs(wrapper)); aTransferable->SetTransferData(foundFlavor.get(), wrapper, length); } if (data) nsMemory::Free(data); return NS_OK; }