How to obtain IconRef from Application Resources - macos

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;
}

Related

Xamarin.Mac How to get the file path when I launch my app from an associated file?

As follows, I edited info.plist and set it to associate ".atc" extension in Visual Studio 2019 for Mac.
Then, I was able to launch the application by double-clicking the "*.atc" file.
However, I don't know how to get the "full path" in the application by double-clicking the "*.atc" file. Is it written around AppDelegate.cs?
I solved it myself. I used the following example of a swift project as a reference.
ref. How to associate existing file type for Mac OS application in XCode 7?
First, add the "Document.cs" file, a class derived from NSDocument, to the project.
using System;
using AppKit;
using Foundation;
namespace AttacheCase
{
[Register("Document")]
public class Document : NSDocument
{
public Document(IntPtr handle) : base(handle)
{
// Add your subclass-specific initialization here.
}
public override void WindowControllerDidLoadNib(NSWindowController windowController)
{
base.WindowControllerDidLoadNib(windowController);
// Add any code here that needs to be executed once the windowController has loaded the document's window.
}
[Export("autosavesInPlace")]
public static bool AutosaveInPlace()
{
return true;
}
public override void MakeWindowControllers()
{
//Override to return the Storyboard file name of the document.
var storyboard = NSStoryboard.FromName("Main", null);
var wincontroller = (NSWindowController)storyboard.InstantiateControllerWithIdentifier("ViewController");
AddWindowController(wincontroller);
}
public override NSData GetAsData(string typeName, out NSError outError)
{
// Insert code here to write your document to data of the specified type.
// If outError != NULL, ensure that you create and set an appropriate error when returning nil.
throw new NotImplementedException();
}
public override bool ReadFromUrl(NSUrl url, string typeName, out NSError outError)
{
var alert = new NSAlert()
{
AlertStyle = NSAlertStyle.Critical,
InformativeText = "Information",
MessageText = url.Path,
};
alert.RunModal();
outError = null;
return true;
}
}
}
At this time, register the name of Window Controller by launching Xcode from Main.storyboard.
Now double click on the "*.atc" file, the application will launch and you will get the full path to the file.

Get currently selected text in active application in Cocoa

I have a status-menu app that can be started using a system wide shortcut. When the app gets active, it would be great if I could somehow get the text that is selected in the currently running application.
So for example I type something in my text-editor, select the text, hit my global shortcut, my app comes up and I would now love to know the selected text from the text-editor.
What I have so far is the following (adopted code from How to get global screen coordinates of currently selected text via Accessibility APIs.)
AXUIElementRef systemWideElement = AXUIElementCreateSystemWide();
AXUIElementRef focussedElement = NULL;
AXError error = AXUIElementCopyAttributeValue(systemWideElement, kAXFocusedUIElementAttribute, (CFTypeRef *)&focussedElement);
if (error != kAXErrorSuccess) {
NSLog(#"Could not get focussed element");
} else {
AXValueRef selectedTextValue = NULL;
AXError getSelectedTextError = AXUIElementCopyAttributeValue(focussedElement, kAXSelectedTextAttribute, (CFTypeRef *)&selectedTextValue);
if (getSelectedTextError == kAXErrorSuccess) {
selectedText = (__bridge NSString *)(selectedTextValue);
NSLog(#"%#", selectedText);
} else {
NSLog(#"Could not get selected text");
}
}
if (focussedElement != NULL) CFRelease(focussedElement);
CFRelease(systemWideElement);
The problem here is that it does not work with apps like Safari and Mail...
Thanks
This is actually very easy, kAXSelectedTextAttribute is your friend.
extension AXUIElement {
var selectedText: String? {
rawValue(for: kAXSelectedTextAttribute) as? String
}
func rawValue(for attribute: String) -> AnyObject? {
var rawValue: AnyObject?
let error = AXUIElementCopyAttributeValue(self, attribute as CFString, &rawValue)
return error == .success ? rawValue : nil
}
}
This is not technically a solution to your exact question because the user would have to trigger this from the Services menu rather than it simply happening when they trigger your menu bar app.
You could use a System Service. You create a service for your app that sends the currently selected text to your menu bar app via a Pasteboard.

How to get Finder sidebar favorites content cocoa?

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);

Changing filename color in Windows Explorer list view.

I would like to customize Windows Explorer.
One thing I want to do is changing file name's color in list view if the file has a special condition.
Is it possible by window subclassing? or does it need api hooking?
Please let me know what is the best way to do this.
Thanks.
Yes, you can do it with the window subclassing:
Add NM_CUSTOMDRAW handler to your CListCtrl-derived class
void CMyList::OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult)
{
LPNMLVCUSTOMDRAW lplvcd = (LPNMLVCUSTOMDRAW)pNMHDR;
switch (lplvcd->nmcd.dwDrawStage)
{
case CDDS_PREPAINT:
*pResult = CDRF_NOTIFYITEMDRAW;
break;
case CDDS_ITEMPREPAINT:
*pResult = CDRF_NOTIFYSUBITEMDRAW;
break;
case CDDS_ITEMPREPAINT | CDDS_SUBITEM:
lplvcd->clrText = **MY_COLOR**;
*pResult = CDRF_DODEFAULT;
}
}

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