Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

How to add default “Open recent” macOS menu item in Qt application?



  • Hello!

    Need help with an application menu created using QMenu and QActions on macOS plaform.
    Menu and application works fine, except for recently opened files part. Haven't found anything about working with sandbox access rights on macOS platform using Qt, and my submenu "Recent files" fails to load saved urls after app is restarted.

    Googling of that problem showed that pretty easy way exists: use NSDocumentController thing and default "open recent" cocoa menu that handles everything about access rights.

    That's where the question starts: whatever i do there is no "Open recent" submenu inside "File". Found some info here, but i can't understand how to do it in qt based application. No info about that menu in QMenuBar documentation either.

    Any advice, example?



  • @EekTheCat Hi,
    I don't know about NSDocumentController. But you can do this from the Qt side pretty easily. Please see this example: Recent Files Example.



  • @Gojir4, my app do have "recent files" and it works fine on Windows. But! on macOS with enabled Sandbox mode it becomes useless list of file names which the app fails to read unless user explicitly opens or drag&drop that file to app window to give it access rights.
    I can't find how to solve it with Qt, and have too little knowlege of Objective C and cocoa to do it other way.



  • @EekTheCat Sorry, I have misunderstood. Unfortunately I cannot help.



  • If i understand well, you want to call this from cocoa:

    [[NSDocumentController sharedDocumentController] noteNewRecentDocumentURL:[NSURL fileURLWithPath:aFileName]];
    

    Have a look at this link, I explain how to call a cocoa method from Qt:
    https://forum.qt.io/topic/82609/remove-native-mac-menu-items-such-as-show-tab-bar/3

    You need to create your method like that:

    void  CocoaBridge::registerRecentUrl(const QUrl &url)
     {
    	[[NSDocumentController sharedDocumentController] noteNewRecentDocumentURL: url.toNSURL()];
     }
    

    Hope it's work, i can't test it ...



  • @mpergand, thanks, but that is not what the question about. Maybe i failed to explain the problem properly... sorry.

    I did wrote exactly same code with QUrl and noteNewRecentDocumentURL. As i said the part with NSDocumentController was easy to google.

    The problem is:
    Menu in my application created using QMenu and QMenu.addAction(...), which is then (i guess) translated by Qt to native cocoa menu.
    NSDocumentController should automatically add new menu item called "Open recent" to "File" menu (or first item?) right next to some specific menu item.
    I can't find how to create that specific menu item, or set some specific property using Qt menu.
    Or maybe Qt have something that handles macOS security-scoped bookmarks and all that apple annoying sandbox limitations?



  • I can't find how to create that specific menu item, or set some specific property using Qt menu.

    I think it's pretty hard, this item is created by IB.
    Look at this link:
    http://lapcatsoftware.com/blog/2007/07/10/working-without-a-nib-part-5-open-recent-menu/

    I wonder how this security issue is resolved in recent Qt apps, like QtCreator who has recent menu ?



  • I wonder how this security issue is resolved in recent Qt apps, like QtCreator who has recent menu ?

    QtCreator is not on AppStore and works without sandbox mode on macOS, so it needs no entitlements to read files, just access rights that the user has.

    Everything turned out easier than i thought.

    I was able to get it to work without using 'default' cocoa menu, but using url list from NSDocumentController.
    Now recent menu works even simplier on macOS since everything about saving/loading the url list and access rights NSDocumentController does itself. I just need to rebuild QMenu when the list changes.

    And as a bonus 'recent files' appeared inside application context menu in dock panel.
    (note: code in .mm file)

    QStringList GetRecentList( )
    {
        QStringList result;
        NSArray<NSURL *>* urls = [[NSDocumentController sharedDocumentController] recentDocumentURLs];
    
        for (int i=0; i< [urls count]; i++) {
    	NSURL* url = [urls objectAtIndex:i];
    	NSString* str = [url absoluteString];
    			
    	result.append( QString::fromNSString(str) );
        }
    
        return result;
    }
    
    bool SendToRecent( QString filepath )
    {
        [[NSDocumentController sharedDocumentController] noteNewRecentDocumentURL: [NSURL     fileURLWithPath:filepath.toNSString()]];
    
    	return YES;
    }

Log in to reply