I'm developing a cocoa application for Mac. I'm applying overlay icons on files and folders using my application. But my problem is that when I change icon for file or folder from my Application than its not reflecting it in the Finder unless I click on any file or folder in the Finder. For refreshing Finder I'm running following applescript using following code from my Application:
NSString *source=[NSString stringWithFormat:#"tell application \"Finder\" to update POSIX file \"%#\"",itemPath];
NSAppleScript *run = [[NSAppleScript alloc] initWithSource:source];
[run executeAndReturnError:nil];
But this code is not refreshing my Finder. Any idea how to refresh Finder to immediately reflect icon for file or folder??? Thanks in advance...
You must specify the class (folder, file, disk, item, ...) when you use a string in the Finder, item will work for all (folder, file, ...).
Without it, It works for some, but it is not the case for everyone
Also, "posix file thePath" in the Finder is more reliable with parentheses.
Try this
NSString *source=[NSString stringWithFormat:#"tell application \"Finder\" to update item (POSIX file \"%#\")",itemPath];
Or without NSApplescript :
[[NSWorkspace sharedWorkspace] noteFileSystemChanged: itemPath];
#"tell application \"Finder\" to update POSIX file \"%#\"" this script working fine for me.
You can also use apple events.
Below code is written by JWWalker
OSStatus SendFinderSyncEvent( const FSRef* inObjectRef )
{
AppleEvent theEvent = { typeNull, NULL };
AppleEvent replyEvent = { typeNull, NULL };
AliasHandle itemAlias = NULL;
const OSType kFinderSig = 'MACS';
OSStatus err = FSNewAliasMinimal( inObjectRef, &itemAlias );
if (err == noErr)
{
err = AEBuildAppleEvent( kAEFinderSuite, kAESync, typeApplSignature,
&kFinderSig, sizeof(OSType), kAutoGenerateReturnID,
kAnyTransactionID, &theEvent, NULL, "'----':alis(##)", itemAlias );
if (err == noErr)
{
err = AESendMessage( &theEvent, &replyEvent, kAENoReply,
kAEDefaultTimeout );
AEDisposeDesc( &replyEvent );
AEDisposeDesc( &theEvent );
}
DisposeHandle( (Handle)itemAlias );
}
return err;
}
Here's how I "refresh the Finder" when needed. Maybe it will help you ;)
tell application "Finder"
tell window 1 to update items
end tell
What worked for me is to 'touch' the file which updates the file modification date and thus triggers thumbnail icon refresh by the Finder.
NSString* path = "/Users/xx/...path_to_file"
NSString* command = [NSString stringWithFormat:#"touch \"%#\"", path];
int res = system(command.UTF8String);
Related
Running in macOS 10.15.6, built with Xcode 11.1, my app is suddenly (at least I just noticed) spitting out these warnings on the console when I present a save dialog:
WARNING: <NSSavePanel: 0x100e43250> found it necessary to prepare implicitly; please prepare panels using NSSavePanel rather than NSApplication or NSWindow.
WARNING: <NSSavePanel: 0x100e43250> found it necessary to start implicitly; please start panels using NSSavePanel rather than NSApplication or NSWindow.
WARNING: <NSSavePanel: 0x100e43250> running implicitly; please run panels using NSSavePanel rather than NSApplication.
The problem is, I am using NSSavePanel to present this dialog. Here's the entire method. I can't see what's wrong with it. I'm not using any deprecated methods. (In the case I'm having problems with, window is nil, so runModel gets called.)
/** Present a modal dialog (window==nil) or begin a sheet (window!=nil) that prompts the user to create a new archive.
*
* Attaches the rundancy picker view to the save panel so the user can choose the redundancy level.
* Presents a warning if the user picks a volume that has size limitations.
* If successful, invokes the handler with the URL of the new repository and its creation settings.
* #param window window for sheet, or nil for modal dialog
* #param title optional title
* #param name optional default name
* #param directory optional default directory
* #param handler completion handler
*/
+ (void)newArchivePrompForWindow:(nullable NSWindow *)window
withTitle:(nullable NSString*)title
name:(nullable NSString*)name
inDirectory:(nullable NSURL*)directory
completionHandler:(void (^)(NSURL* repositoryURL, NSDictionary* settings))handler
{
NSSavePanel* savePanel = [NSSavePanel savePanel];
savePanel.title = ( title ?: #"New Archive" );
savePanel.allowedFileTypes = #[kRepositoryFileType];
// savePanel.canSelectHiddenExtension = YES;
savePanel.extensionHidden = YES;
savePanel.prompt = #"Create";
savePanel.nameFieldLabel = #"Archive:";
if (directory!=nil)
savePanel.directoryURL = directory; // set optional default folder
if (name!=nil)
savePanel.nameFieldStringValue = name; // set optional name
// attach the redundancy picker controller
RepositoryPickRedundancyViewController* redundancyAccessoryController;
redundancyAccessoryController = [[RepositoryPickRedundancyViewController alloc] initWithNibName:#"RepositoryPickRedundancyView"
bundle:nil];
[savePanel setAccessoryView:redundancyAccessoryController.view];
redundancyAccessoryController.version = kDataRedundancyPickerSchemeDefault;
redundancyAccessoryController.configurationIndex = kDataRedundancyPickerConfigIndexDefault;
// Present the panel
if (window!=nil)
{
// The dialog is attached to a window
// Present a sheet attached to the window
[savePanel beginSheetModalForWindow:window completionHandler:^(NSInteger result) {
if (result==NSFileHandlingPanelOKButton)
// User picked an archive: vet it and continue
NewArchivePostProcessing(savePanel,window,redundancyAccessoryController,savePanel.URL,handler);
else
// canceled
handler(nil,nil);
}];
}
else
{
// No parent window: run a modal dialog
if ([savePanel runModal]==NSModalResponseOK)
// User picked an archive: vet it and continue
NewArchivePostProcessing(savePanel,nil,redundancyAccessoryController,savePanel.URL,handler);
else
// canceled
handler(nil,nil);
}
}
Anyone have a clue as to what's going on here?
If you replace
if ([savePanel runModal]==NSModalResponseOK)
...
with
[savePanel beginWithCompletionHandler:^(NSModalResponse result) {
if (result==NSFileHandlingPanelOKButton)
...
}];
The message goes away.
I'm guess it's a subtle way of trying to encourage the use of more modern APIs.
The only problem is, the message is wrong, runModal isn't deprecated, and there's no mention or documentation of this anywhere. Which seems to be par for the course, these days. :(
Much like Safari, trying to implement a button that when clicked opens System Preferences > Extensions > Share Menu pane.
I have tried:
NSURL *URL = [NSURL URLWithString:#"x-apple.systempreferences:com.apple.preferences.extensions?Share_Menu"];
[[NSWorkspace sharedWorkspace] openURL:URL];
However it seems like that is not working on newer versions, any ideas?
You can use Scripting Bridge to do something like this:
SBSystemPreferencesApplication *systemPrefs =
[SBApplication applicationWithBundleIdentifier:#"com.apple.systempreferences"];
[systemPrefs activate];
SBElementArray *panes = [systemPrefs panes];
SBSystemPreferencesPane *notificationsPane = nil;
for (SBSystemPreferencesPane *pane in panes) {
if ([[pane id] isEqualToString:#"com.apple.preferences.extensions"]) {
notificationsPane = pane;
break;
}
}
[systemPrefs setCurrentPane:notificationsPane];
SBElementArray *anchors = [notificationsPane anchors];
for (SBSystemPreferencesAnchor *anchor in anchors) {
if ([anchor.name isEqualToString:#"Extensions"]) {
[anchor reveal];
}
}
Of course you need to add the ScriptingBridge framework to your project and a Scripting Bridge header file for system preferences. More details on how to use Scripting Bridge you can find in the developer documentation from Apple.
Hope this helps
Since macOS Ventura (13.0) you can call the URL
x-apple.systempreferences:com.apple.preferences.extensions?Sharing
I have a very strange (& serious) problem.
My app uses a UIDocumentInteractionController to share a PDF document.
When the user selects the "Mail" option in the controller's pop-up the MailCompose window is opened.
But, neither the Send nor Cancel button in this window causes the MailCompose window to be dismissed, meaning the user gets stuck and has to kill the app. The mail does go out though.
Here's the catch:
This happens only in iOS8 (both versions released so far) and only on apps installed via the AppStore. That EXACT same version of the app, when running on my device via USB debugging works fine.
Here's some code:
-(void)sharePDF:(id)sender
{
#try
{
NSURL *fileURL = [NSURL fileURLWithPath:currentFileObject.LocalPath];
if(fileURL)
{
//UIDocumentInteractionController
NSString *newPath;
#try
{
//Create a copy of the file for sharing with a friendly name
if (currentFileObject.isSpecialReport)
{
newPath = [svc saveReport:[NSData dataWithContentsOfURL:fileURL] ToFile:[NSString stringWithFormat:#"%#.pdf", currentFileObject.ReportName]];
}
else
{
newPath = [svc saveReport:[NSData dataWithContentsOfURL:fileURL] ToFile:[NSString stringWithFormat:#"%#.pdf", currentFileObject.PatientFullName]];
}
}
#catch (NSException *exception) {
return;
}
NSURL *newURL = [NSURL fileURLWithPath:newPath];
self.docController = [UIDocumentInteractionController interactionControllerWithURL:newURL];
self.docController.delegate = self;
if (currentFileObject.isSpecialReport)
{
self.docController.name = [NSString stringWithFormat:#"Pathology - %#", currentFileObject.ReportName];
}
else
{
self.docController.name = [NSString stringWithFormat:#"Pathology - %#", currentFileObject.PatientFullName];
}
[self.docController presentOptionsMenuFromBarButtonItem:btnShare animated:YES];
}
}
#catch (NSException *exception) {
return;
}
}
I do not implement any of the delegate methods since non of them are required, I also do not make use of the preview functionality.
What's most puzzling to me is that the app from the AppStore behaves differently than my local one although the code is identical. My next step is to use the new beta developer tools (Test Flight) to re-publish the app, hoping that I can replicate the problem.
EDIT: I found a similar question on SO here: Cannot dismiss email sheet invoked from UIDocumentInteractionController in iOS 8
After reading that post I think it worth mentioning that I submitted the app to the AppStore via XCode 5 (the last version before XCode 6). Can that really be a factor here? Does Apple not use the same version on their side as the version in which the app was originally built?
I think this is a bug in iOS 8, and if it's still not working for you, I don't think Apple are likely to fix it. I'd upgrade to Xcode 6 and see if that fixes it for you. (It did for us, as you've discovered).
I am developing in MAC and need to get the list of all the active applications currently running, I mean the ones which have actual window and the user can see/close/minimize/maximize.
I tried using NSWorkspace runningApplications function, but it gives a long list of applications (most probably it also lists some hidden applications) but I need only the ones that has window UI.
I've also used the suggestion in the following post to get the windows below the Dock and it worked fine in case if the Dock is visible:
CGWindowListCreate generates a hugely long list of windows
However when the Dock is hidden this solution doesn't work.
Does anyone have any idea how to get the list of running applications visible to user on MAC?
It may help you. Try this
for (NSRunningApplication *app in [[NSWorkspace sharedWorkspace] runningApplications]) {
NSLog(#"%#",[app localizedName]);
}
#import <Foundation/Foundation.h>
void ListWindows()
{
NSMutableArray* windows =
(__bridge NSMutableArray *)CGWindowListCopyWindowInfo(
kCGWindowListOptionOnScreenOnly |
kCGWindowListExcludeDesktopElements,
kCGNullWindowID);
for (NSDictionary* window in windows) {
if([[window objectForKey:#"kCGWindowLayer" ] intValue] == 0)
{
NSLog(#"%#", [window objectForKey:#"kCGWindowOwnerName"]);
}
}
}
int main(int argc, const char * argv[])
{
NSLog(#"Active windows:");
ListWindows();
return 0;
}
Sample output :
Active windows:
Xcode
TextEdit
Finder
I'm trying to figure out how to programatically add a folder to Finder's Places sidebar. I've seen ways to modify it through the Finder Preferences, but I've also seen some applications actually add folders to the sidebar.
If someone has any advice/pointers on what I should look up, it would be greatly appreciated
(This is for Snow Leopard and Leopard... hopefully it didn't change)
Try this:
-(void) addPathToSharedItem:(NSString *)path
{
CFURLRef url = (CFURLRef)[NSURL fileURLWithPath:path];
// Create a reference to the shared file list.
LSSharedFileListRef favoriteItems = LSSharedFileListCreate(NULL,
kLSSharedFileListFavoriteItems, NULL);
if (favoriteItems) {
//Insert an item to the list.
LSSharedFileListItemRef item = LSSharedFileListInsertItemURL(favoriteItems,
kLSSharedFileListItemLast, NULL, NULL,
url, NULL, NULL);
if (item){
CFRelease(item);
}
}
CFRelease(favoriteItems);
}