/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 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 * Mozilla Foundation. * Portions created by the Initial Developer are Copyright (C) 2009 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Jim Mathies * * 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 ***** */ #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7 #include "JumpListBuilder.h" #include "nsError.h" #include "nsCOMPtr.h" #include "nsServiceManagerUtils.h" #include "nsAutoPtr.h" #include "nsString.h" #include "nsArrayUtils.h" #include "nsIMutableArray.h" #include "nsWidgetsCID.h" namespace mozilla { namespace widget { static NS_DEFINE_CID(kJumpListItemCID, NS_WIN_JUMPLISTITEM_CID); static NS_DEFINE_CID(kJumpListLinkCID, NS_WIN_JUMPLISTLINK_CID); static NS_DEFINE_CID(kJumpListShortcutCID, NS_WIN_JUMPLISTSHORTCUT_CID); // defined in WinTaskbar.cpp extern const wchar_t *gMozillaJumpListIDGeneric; PRPackedBool JumpListBuilder::sBuildingList = PR_FALSE; NS_IMPL_ISUPPORTS1(JumpListBuilder, nsIJumpListBuilder) JumpListBuilder::JumpListBuilder() : mMaxItems(0), mHasCommit(PR_FALSE) { ::CoInitialize(NULL); CoCreateInstance(CLSID_DestinationList, NULL, CLSCTX_INPROC_SERVER, IID_ICustomDestinationList, getter_AddRefs(mJumpListMgr)); } JumpListBuilder::~JumpListBuilder() { mJumpListMgr = nsnull; ::CoUninitialize(); } /* readonly attribute short available; */ NS_IMETHODIMP JumpListBuilder::GetAvailable(PRInt16 *aAvailable) { *aAvailable = PR_FALSE; if (mJumpListMgr) *aAvailable = PR_TRUE; return NS_OK; } /* readonly attribute boolean isListCommitted; */ NS_IMETHODIMP JumpListBuilder::GetIsListCommitted(PRBool *aCommit) { *aCommit = mHasCommit; return NS_OK; } /* readonly attribute short maxItems; */ NS_IMETHODIMP JumpListBuilder::GetMaxListItems(PRInt16 *aMaxItems) { if (!mJumpListMgr) return NS_ERROR_NOT_AVAILABLE; *aMaxItems = 0; if (sBuildingList) { *aMaxItems = mMaxItems; return NS_OK; } IObjectArray *objArray; if (SUCCEEDED(mJumpListMgr->BeginList(&mMaxItems, IID_PPV_ARGS(&objArray)))) { *aMaxItems = mMaxItems; if (objArray) objArray->Release(); mJumpListMgr->AbortList(); } return NS_OK; } /* boolean initListBuild(in nsIMutableArray removedItems); */ NS_IMETHODIMP JumpListBuilder::InitListBuild(nsIMutableArray *removedItems, PRBool *_retval) { NS_ENSURE_ARG_POINTER(removedItems); *_retval = PR_FALSE; if (!mJumpListMgr) return NS_ERROR_NOT_AVAILABLE; if(sBuildingList) AbortListBuild(); IObjectArray *objArray; if (SUCCEEDED(mJumpListMgr->BeginList(&mMaxItems, IID_PPV_ARGS(&objArray)))) { if (objArray) { TransferIObjectArrayToIMutableArray(objArray, removedItems); objArray->Release(); } sBuildingList = PR_TRUE; *_retval = PR_TRUE; return NS_OK; } return NS_OK; } /* boolean addListToBuild(in short aCatType, [optional] in nsIArray items, [optional] in AString catName); */ NS_IMETHODIMP JumpListBuilder::AddListToBuild(PRInt16 aCatType, nsIArray *items, const nsAString &catName, PRBool *_retval) { nsresult rv; *_retval = PR_FALSE; if (!mJumpListMgr) return NS_ERROR_NOT_AVAILABLE; switch(aCatType) { case nsIJumpListBuilder::JUMPLIST_CATEGORY_TASKS: { NS_ENSURE_ARG_POINTER(items); HRESULT hr; nsRefPtr collection; hr = CoCreateInstance(CLSID_EnumerableObjectCollection, NULL, CLSCTX_INPROC_SERVER, IID_IObjectCollection, getter_AddRefs(collection)); if (FAILED(hr)) return NS_ERROR_UNEXPECTED; // Build the list PRUint32 length; items->GetLength(&length); for (PRUint32 i = 0; i < length; ++i) { nsCOMPtr item = do_QueryElementAt(items, i); if (!item) continue; // Check for separators if (IsSeparator(item)) { nsRefPtr link; rv = JumpListSeparator::GetSeparator(link); if (NS_FAILED(rv)) return rv; collection->AddObject(link); continue; } // These should all be ShellLinks nsRefPtr link; rv = JumpListShortcut::GetShellLink(item, link); if (NS_FAILED(rv)) return rv; collection->AddObject(link); } // We need IObjectArray to submit nsRefPtr pArray; hr = collection->QueryInterface(IID_IObjectArray, getter_AddRefs(pArray)); if (FAILED(hr)) return NS_ERROR_UNEXPECTED; // Add the tasks hr = mJumpListMgr->AddUserTasks(pArray); if (SUCCEEDED(hr)) *_retval = PR_TRUE; return NS_OK; } break; case nsIJumpListBuilder::JUMPLIST_CATEGORY_RECENT: { if (SUCCEEDED(mJumpListMgr->AppendKnownCategory(KDC_RECENT))) *_retval = PR_TRUE; return NS_OK; } break; case nsIJumpListBuilder::JUMPLIST_CATEGORY_FREQUENT: { if (SUCCEEDED(mJumpListMgr->AppendKnownCategory(KDC_FREQUENT))) *_retval = PR_TRUE; return NS_OK; } break; case nsIJumpListBuilder::JUMPLIST_CATEGORY_CUSTOMLIST: { NS_ENSURE_ARG_POINTER(items); if (catName.IsEmpty()) return NS_ERROR_INVALID_ARG; HRESULT hr; nsRefPtr collection; hr = CoCreateInstance(CLSID_EnumerableObjectCollection, NULL, CLSCTX_INPROC_SERVER, IID_IObjectCollection, getter_AddRefs(collection)); if (FAILED(hr)) return NS_ERROR_UNEXPECTED; PRUint32 length; items->GetLength(&length); for (PRUint32 i = 0; i < length; ++i) { nsCOMPtr item = do_QueryElementAt(items, i); if (!item) continue; PRInt16 type; if (NS_FAILED(item->GetType(&type))) continue; switch(type) { case nsIJumpListItem::JUMPLIST_ITEM_SEPARATOR: { nsRefPtr shellItem; rv = JumpListSeparator::GetSeparator(shellItem); if (NS_FAILED(rv)) return rv; collection->AddObject(shellItem); } break; case nsIJumpListItem::JUMPLIST_ITEM_LINK: { nsRefPtr shellItem; rv = JumpListLink::GetShellItem(item, shellItem); if (NS_FAILED(rv)) return rv; collection->AddObject(shellItem); } break; case nsIJumpListItem::JUMPLIST_ITEM_SHORTCUT: { nsRefPtr shellItem; rv = JumpListShortcut::GetShellLink(item, shellItem); if (NS_FAILED(rv)) return rv; collection->AddObject(shellItem); } break; } } // We need IObjectArray to submit nsRefPtr pArray; hr = collection->QueryInterface(IID_IObjectArray, (LPVOID*)&pArray); if (FAILED(hr)) return NS_ERROR_UNEXPECTED; // Add the tasks hr = mJumpListMgr->AppendCategory(catName.BeginReading(), pArray); if (SUCCEEDED(hr)) *_retval = PR_TRUE; return NS_OK; } break; } return NS_OK; } /* void abortListBuild(); */ NS_IMETHODIMP JumpListBuilder::AbortListBuild() { if (!mJumpListMgr) return NS_ERROR_NOT_AVAILABLE; mJumpListMgr->AbortList(); sBuildingList = PR_FALSE; return NS_OK; } /* boolean commitListBuild(); */ NS_IMETHODIMP JumpListBuilder::CommitListBuild(PRBool *_retval) { *_retval = PR_FALSE; if (!mJumpListMgr) return NS_ERROR_NOT_AVAILABLE; HRESULT hr = mJumpListMgr->CommitList(); sBuildingList = PR_FALSE; // XXX We might want some specific error data here. if (SUCCEEDED(hr)) { *_retval = PR_TRUE; mHasCommit = PR_TRUE; } return NS_OK; } /* boolean deleteActiveList(); */ NS_IMETHODIMP JumpListBuilder::DeleteActiveList(PRBool *_retval) { *_retval = PR_FALSE; if (!mJumpListMgr) return NS_ERROR_NOT_AVAILABLE; if(sBuildingList) AbortListBuild(); if (SUCCEEDED(mJumpListMgr->DeleteList(gMozillaJumpListIDGeneric))) *_retval = PR_TRUE; return NS_OK; } /* internal */ PRBool JumpListBuilder::IsSeparator(nsCOMPtr& item) { PRInt16 type; item->GetType(&type); if (NS_FAILED(item->GetType(&type))) return PR_FALSE; if (type == nsIJumpListItem::JUMPLIST_ITEM_SEPARATOR) return PR_TRUE; return PR_FALSE; } // TransferIObjectArrayToIMutableArray - used in converting removed items // to our objects. nsresult JumpListBuilder::TransferIObjectArrayToIMutableArray(IObjectArray *objArray, nsIMutableArray *removedItems) { NS_ENSURE_ARG_POINTER(objArray); NS_ENSURE_ARG_POINTER(removedItems); nsresult rv; PRUint32 count = 0; objArray->GetCount(&count); nsCOMPtr item; for (PRUint32 idx = 0; idx < count; idx++) { IShellLinkW * pLink = nsnull; IShellItem * pItem = nsnull; if (SUCCEEDED(objArray->GetAt(idx, IID_IShellLinkW, (LPVOID*)&pLink))) { nsCOMPtr shortcut = do_CreateInstance(kJumpListShortcutCID, &rv); if (NS_FAILED(rv)) return NS_ERROR_UNEXPECTED; rv = JumpListShortcut::GetJumpListShortcut(pLink, shortcut); item = do_QueryInterface(shortcut); } else if (SUCCEEDED(objArray->GetAt(idx, IID_IShellItem, (LPVOID*)&pItem))) { nsCOMPtr link = do_CreateInstance(kJumpListLinkCID, &rv); if (NS_FAILED(rv)) return NS_ERROR_UNEXPECTED; rv = JumpListLink::GetJumpListLink(pItem, link); item = do_QueryInterface(link); } if (pLink) pLink->Release(); if (pItem) pItem->Release(); if (NS_SUCCEEDED(rv)) { removedItems->AppendElement(item, PR_FALSE); } } return NS_OK; } } // namespace widget } // namespace mozilla #endif // MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7