How to get Finder sidebar favorites content cocoa? - macos

I need to get paths of objects displayed in Favorites section of Finder Sidebar (for current user). How can I achieve this?

Getting the shared file list is only the first part, you still may want to get an actual string object with your path. Here is a little code snippet that will let you get a path for each object in the favorites section of the finder sidebar.
UInt32 seed;
LSSharedFileListRef sflRef = LSSharedFileListCreate(NULL,
kLSSharedFileListFavoriteItems,
NULL);
CFArrayRef items = LSSharedFileListCopySnapshot( sflRef, &seed );
for( size_t i = 0; i < CFArrayGetCount(items); i++ )
{
LSSharedFileListItemRef item = (LSSharedFileListItemRef)CFArrayGetValueAtIndex(items, i);
if( !item )
continue;
CFURLRef outURL = NULL;
LSSharedFileListItemResolve( item, kLSSharedFileListNoUserInteraction, (CFURLRef*) &outURL, NULL );
if( !outURL )
continue;
//The actual path string of the item
CFStringRef itemPath = CFURLCopyFileSystemPath(outURL,kCFURLPOSIXPathStyle);
// TODO: Do whatever you want to do with your path here!!!!
CFRelease(outURL);
CFRelease(itemPath);
}
CFRelease(items);
CFRelease(sflRef);

There's not a Cocoa API, per se. You would use the LSSharedFileList API. The API is public but the only documentation is the header file, /System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Headers/LSSharedFileList.h. You want the kLSSharedFileListFavoriteItems (and maybe kLSSharedFileListFavoriteVolumes) list type(s).

Use LSSharedFileList API(LaunchServices/LSSharedFileList.h.)
LSSharedFileListRef favoriteItems = LSSharedFileListCreate(NULL,
kLSSharedFileListFavoriteItems, NULL);

Related

How to add sidebar icon on osx version 10.10 and 10.11

I am tring to add a custom icon to sidebar (favorites).
I tried the next link - https://developer.apple.com/library/ios/documentation/General/Conceptual/ExtensibilityPG/Finder.html
But I cannt see any change.
I also tryed to add folder with objective c:
LSSharedFileListRef favoriteList = NULL;
CFStringRef urlStringRef = NULL;
CFURLRef url = NULL;
IconRef icon = NULL;
CFStringRef displayName = NULL;
LSSharedFileListItemRef item = NULL;
favoriteList = LSSharedFileListCreate(NULL, kLSSharedFileListFavoriteItems, NULL);
urlStringRef = CFStringCreateWithCString(NULL, (path.toUtf8().data()), kCFStringEncodingUTF8 );
url = CFURLCreateWithFileSystemPath(NULL, urlStringRef , kCFURLPOSIXPathStyle, NULL);
std::string str = "/Users/mac-templates/Package_Insert.icns";
FSPathMakeRef((const UInt8*) str.c_str(), &fsRef, &isDirectory);
RegisterIconRefFromFSRef(NULL, NULL, &fsRef, &icon);
displayName = CFStringCreateWithCString(NULL, FAVORITES_OSX_DISPLAY_NAME, kCFStringEncodingUTF8 );
item = LSSharedFileListInsertItemURL(favoriteList, kLSSharedFileListItemBeforeFirst, displayName, icon, url, NULL, NULL);
After running the bellow code, I can see the new folder in the sidebar but the icon is the standard folder icon.
it means command 'kLSSharedFileListItemBeforeFirst' works partially, it's add the folder to the sidebar but without icon.
Has someone added icon to the sidebar?
Thx

How to obtain IconRef from Application Resources

I want to add custom place to Finder Favorites sidebar using LSSharedFileList API as described here. But I need to add a custom icon to this item. The icon should be in the IconRef type. I have not found a way to do it. Found only a mention of the fact that the need to use Icon Services. But how?
You can use this function of Scplugin.
static IconRef IconRefFromIconFileNoCache(CFStringRef file)
{
IconRef iconRef;
IconFamilyHandle iconFamily;
FSRef fileRef;
CFURLRef url;
Boolean ok;
url = CFURLCreateWithFileSystemPath(NULL,file,kCFURLPOSIXPathStyle,false);
if (!url)
return 0;
ok = CFURLGetFSRef(url,&fileRef);
CFRelease(url);
if (!ok)
return 0;
if (ReadIconFromFSRef(&fileRef, &iconFamily))
return nil;
iconRef = 0;
HLock((Handle)iconFamily);
GetIconRefFromIconFamilyPtr(*iconFamily,(**iconFamily).resourceSize,&iconRef);
DisposeHandle((Handle)iconFamily);
return iconRef;
}

Wrong PIDL got from CIDA when dragging a Control Panel item

I'm working on a drag and drop problem now and trying to get the PIDLs of the items being dragged from windows shell to my application.
The code below can get correct PIDLs if the dragged item is 'My Computer' or 'Control Panel' itself, but it doesn't work when the dragged item is an item in the 'Control Panel'.
What's wrong with my code?
#define GetPIDLFolder(pida) (LPCITEMIDLIST)(((LPBYTE)pida)+(pida)->aoffset[0])
#define GetPIDLItem(pida, i) (LPCITEMIDLIST)(((LPBYTE)pida)+(pida)->aoffset[i+1])
STGMEDIUM medium;
UINT fmt = RegisterClipboardFormat(CFSTR_SHELLIDLIST);
FORMATETC fe= {fmt, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
HRESULT GETDATA_RESULT = pDataObject->GetData(&fe, &medium);
if (SUCCEEDED(GETDATA_RESULT))
{
LPIDA pida = (LPIDA)GlobalLock(medium.hGlobal);
LPCITEMIDLIST pidlFolder = GetPIDLFolder(pida);
int n = pida->cidl; // the n is always correct
if( n > 0 )
{
LPCITEMIDLIST pidlItem = GetPIDLItem(pida, 0);
// the pidlItem is wrong when the dragged object is an item in 'Control Panel'
}
GlobalUnlock(medium.hGlobal);
}
ReleaseStgMedium(&medium);
Any idea? Thanks
Zach#Shine
If I D&D Mouse, Network Connections and Fonts I get the following output in my test app:
0 Mouse | sfgao=4 hr=0
1 ::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\::{21EC2020-3AEA-1069-A2DD-08002B30309D}\::{7007ACC7-3202-11D1-AAD2-00805FC1270E} | sfgao=20000004 hr=0
2 C:\WINDOWS\Fonts | sfgao=60000004 hr=0
The Network Connections and Fonts pidls can be converted to fully qualified shell paths while Mouse only returns a relative path/displayname.
This makes sense if you check the documentation for IShellFolder::GetDisplayNameOf:
...They do not guarantee that
IShellFolder will return the requested
form of the name. If that form is not
available, a different one might be
returned. In particular, there is no
guarantee that the name returned by
the SHGDN_FORPARSING flag will be
successfully parsed by
IShellFolder::ParseDisplayName. There
are also some combinations of flags
that might cause the
GetDisplayNameOf/ParseDisplayName
round trip to not return the original
identifier list. This occurrence is
exceptional, but you should check to
be sure.
It is clear that when dealing with controlpanel items, you need to keep the pidl around and only use GetDisplayNameOf for display strings in your UI.
(IShellLink::SetIDList on the Mouse pidl will create a working shortcut so the pidl is valid)
void OnDrop(IDataObject*pDO)
{
STGMEDIUM medium;
UINT fmt = RegisterClipboardFormat(CFSTR_SHELLIDLIST);
FORMATETC fe= {fmt, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
HRESULT hr = pDO->GetData(&fe, &medium);
if (SUCCEEDED(hr))
{
LPIDA pida = (LPIDA)GlobalLock(medium.hGlobal);
if (pida)
{
LPCITEMIDLIST pidlFolder = GetPIDLFolder(pida);
for (UINT i=0; i<pida->cidl; ++i)
{
LPCITEMIDLIST pidlItem = GetPIDLItem(pida,i);
LPITEMIDLIST pidlAbsolute = ILCombine(pidlFolder,pidlItem);
if (pidlAbsolute)
{
IShellFolder*pParentSF;
hr= SHBindToParent(pidlAbsolute,IID_IShellFolder,(void**)&pParentSF,&pidlItem);
if (SUCCEEDED(hr))
{
STRRET str;
hr= pParentSF->GetDisplayNameOf(pidlItem, SHGDN_FORPARSING, &str);
if (SUCCEEDED(hr))
{
TCHAR szName[MAX_PATH];
hr= StrRetToBuf(&str,pidlItem,szName,MAX_PATH);
if (SUCCEEDED(hr))
{
SFGAOF sfgao = SFGAO_FOLDER|SFGAO_FILESYSTEM|SFGAO_HASSUBFOLDER|SFGAO_CANLINK;
hr= pParentSF->GetAttributesOf(1,&pidlItem,&sfgao);
TRACE(_T("%u %s | sfgao=%X hr=%X\n"),i,szName,sfgao,hr);
CreateTestShortcut(pidlAbsolute);
}
}
pParentSF->Release();
}
ILFree(pidlAbsolute);
}
}
GlobalUnlock(medium.hGlobal);
}
ReleaseStgMedium(&medium);
}
}

Can't edit IORegistryEntry

I am creating a software on Mac and I would like to change the value of an IORegistryEntry. I can view it on the IORegistryExplorer, but I can't edit it. So it's my understanding that I have to edit it via code. Here is my code:
CFMutableDictionaryRef matchingDict = IOServiceNameMatching("AppleUSBMultitouchDriver");
io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, matchingDict);
if(service) {
CFStringRef manufacturer = IORegistryEntryCreateCFProperty(service, CFSTR("Manufacturer"), kCFAllocatorDefault,0);
NSLog(#"%#", (NSString*)manufacturer);
kern_return_t err = IORegistryEntrySetCFProperty(service, CFSTR("Manufacturer"), CFSTR("test"));
NSLog(#"error = %d", err);
}
This will output
2010-04-10 16:09:09.015 Test[41548:a0f] Apple Inc.
2010-04-10 16:09:09.015 Test[41548:a0f] error = 0
But after I check the value in the IORegistryExplorer, it still doesn't change. Does anybody have any suggestions?
Thank you
In order for this to be possible, usually the driver for the particular hardware you're changing has to implement setProperties() (in IOKit) that makes this change for you.
It's unlikely that Apple will implement setProperty() in their AppleUSBMultitouchDriver in a way that allows you to change the manufacturer name. They want to specify what kind of fruit they are. ;)
Use IOConnectSetCFProperties instead of IORegistryEntrySetCFProperty. Pass it a dictionary with the settings you want to set.
For example to turn off three finger swipe to navigate, call it with a dictionary containing { TrackpadThreeFingerSwipe = 0; }
This is example how to change trackpad settings properly. Trackpad.prefpane do exactly this, but also save this setting somewhere in defaults (if you will not find out where exactly, ask here about it).
P.S. getEVSHandle() may be found in MachineSettings.framework.
P.P.S. Checked only on 10.5 & 10.6.
NSInteger zero = 0, one = 1;
CFNumberRef _numberWith0 = CFNumberCreate(kCFAllocatorDefault, kCFNumberNSIntegerType, &zero);
CFNumberRef _numberWith1 = CFNumberCreate(kCFAllocatorDefault, kCFNumberNSIntegerType, &one);
CFMutableDictionaryRef propertyDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, NULL, NULL);
CFDictionarySetValue(propertyDict, #"TrackpadThreeFingerSwipe", flag ? _numberWith1 : _numberWith0);
io_connect_t connect = getEVSHandle();
if (!connect)
{
// error
}
kern_return_t status = IOConnectSetCFProperties(connect, propertyDict);
if (status != KERN_SUCCESS)
{
//error
}
CFRelease(propertyDict);

Custom titles for Windows 7 Jump List Recent items

Quickie question: I'm toying with some of the new taskbar APIs in Windows 7 and have gotten Recent Items on my Apps jumplist to show up, but I would like to display them under a different title than the filename (most files my app will be opening will have very similar names). I don't see any way to do that with the IShellItem interface, though. Would I have to use custom categories and IShellLinks to accomplish this?
For reference, my current code looks like this:
void AddRecentApp(const wchar_t* path, const wchar_t* title /* Can I even use this? */ ) {
HRESULT hres;
hres = CoInitialize(NULL);
IShellItem* recentItem;
hres = SHCreateItemFromParsingName(path, NULL, IID_PPV_ARGS(&recentItem));
if(SUCCEEDED(hres)) {
SHARDAPPIDINFO recentItemInfo;
recentItemInfo.pszAppID = MY_APP_USER_MODEL_ID;
recentItemInfo.psi = recentItem;
SHAddToRecentDocs(SHARD_APPIDINFO, &recentItemInfo);
recentItem->Release();
}
}
Figured it out. IShellItems are just a representation of a file, so they only will provide that file's information (no custom title, etc.) An IShellLink is essentially a shortcut, and is much more flexible in terms of display and actions taken when launched, so are more appropriate in this situation. Here's my new code:
void AddRecentApp(const wchar_t* path, const wchar_t* title) {
HRESULT hres;
hres = CoInitialize(NULL);
// Shell links give us more control over how the item is displayed and run
IShellLink* shell_link;
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&shell_link));
if(SUCCEEDED(hres)) {
// Set up the basic link properties
shell_link->SetPath(path);
shell_link->SetArguments(L"--some-command-line-here"); // command line to execute when item is opened here!
shell_link->SetDescription(title); // This is what shows in the tooltip
shell_link->SetIconLocation(L"/path/to/desired/icon", 0); // can be an icon file or binary
// Open up the links property store and change the title
IPropertyStore* prop_store;
hres = shell_link->QueryInterface(IID_PPV_ARGS(&prop_store));
if(SUCCEEDED(hres)) {
PROPVARIANT pv;
InitPropVariantFromString(title, &pv);
// Set the title property.
prop_store->SetValue(PKEY_Title, pv); // THIS is where the displayed title is actually set
PropVariantClear(&pv);
// Save the changes we made to the property store
prop_store->Commit();
prop_store->Release();
}
// The link must persist in the file system somewhere, save it here.
IPersistFile* persist_file;
hres = shell_link->QueryInterface(IID_PPV_ARGS(&persist_file));
if(SUCCEEDED(hres)) {
hres = persist_file->Save(L"/link/save/directory", TRUE);
persist_file->Release();
}
// Add the link to the recent documents list
SHARDAPPIDINFOLINK app_id_info_link;
app_id_info_link.pszAppID = MY_APP_USER_MODEL_ID;
app_id_info_link.psl = shell_link;
SHAddToRecentDocs(SHARD_APPIDINFOLINK, &app_id_info_link);
shell_link->Release();
}
}

Resources