I am working on a project that does not (currently) use any nib files at all.
I'm trying to figure out whether there is any way to add the NSRecentDocumentsMenu Open Recent menu that doesn't require use of a private API.
The below link is all I've managed to find thus far:
http://lapcatsoftware.com/blog/2007/07/10/working-without-a-nib-part-5-open-recent-menu/
Can anyone offer insights?
I'm trying to figure out whether there is any way to add the NSRecentDocumentsMenu Open Recent menu that doesn't require use of a private API.
The following link is for a document-based app in swift without using nibs:
https://www.dropbox.com/s/cfvsz11oe00lnp5/DocBased_swift.zip?dl=0
It uses a modification of menu code found in this reference:
https://talk.objc.io/episodes/S01E145-setting-up-a-document-based-app
The demo may be run in Xcode by creating a macOS app using swift and a XIB interface, although we will not use the XIB. Create a new file called main.swift and remove the existing AppDelegate class. Copy/paste the source code found above into the main.swift file (use import Cocoa instead of Foundation). When you hit the Run button you will notice that the menus are grayed out and there is no Open Recent menu item. To fix this be certain to add Cocoa NSDocument Class and Role to the info.plist (see image in folder above). The Cocoa NSDocument Class should be the nameOfYourApp.Document for swift or just plain Document for objc. When the Run button is hit after making these additions you should have a document based app with a functioning Open Recent menu item. Please post followup if there are problems.
Objc source code is here:
https://www.dropbox.com/s/dvs1u6lpk4l5xhq/DocBased_objc.zip?dl=0
Instructions are similar to those for swift, except a macOS app is created using objective-c. Copy/paste the source code into main.m after deleting what Xcode supplied. For simplicity, also remove AppDelegate and the Document class (if you checked 'Document based' in the setup), although you could use them if you so desire. The info.plist will also have to be amended with the two additions as noted above.
#import <Cocoa/Cocoa.h>
#interface Document : NSDocument {
NSWindow *window;
NSTextView *txtView;
}
- (void) buildWindow;
#end
#implementation Document
- (id) init {
if (self = [super init]) {
[self buildWindow];
}
return self;
}
+ (BOOL)autosavesInPlace {
return YES;
}
- (NSData *)dataOfType:(NSString *)typeName error:(NSError **)outError {
return [[txtView string] dataUsingEncoding:NSUTF8StringEncoding];
}
- (BOOL) readFromURL:(NSURL *) absoluteURL ofType:(NSString *)typeName error:(NSError **)outError {
NSString *str = [[NSString alloc] initWithContentsOfURL:absoluteURL encoding:NSUTF8StringEncoding error:outError];
[txtView setString:str];
return YES;
}
- (void) buildWindow {
#define _wndW 780
#define _wndH 700
window = [[NSWindow alloc] initWithContentRect: NSMakeRect( 0, 0, _wndW, _wndH )
styleMask: NSWindowStyleMaskTitled | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskClosable | NSWindowStyleMaskResizable
backing: NSBackingStoreBuffered defer: NO];
[window center];
[window setTitle: #"Test window"];
[window cascadeTopLeftFromPoint:NSMakePoint(600,0)];
[window makeKeyAndOrderFront: nil];
// **** Window Controller is Necessary **** //
NSWindowController *windowController = [[NSWindowController alloc]initWithWindow:window];
[self addWindowController: windowController];
// ****** NSTextView with Scroll ****** //
NSScrollView *scrlView = [[NSScrollView alloc] initWithFrame:NSMakeRect( 20, 50, _wndW - 40, _wndH - 70 )];
[[window contentView] addSubview:scrlView];
[scrlView setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable ];
[scrlView setHasVerticalScroller: YES];
txtView = [[NSTextView alloc] initWithFrame:NSMakeRect( 0, 0, _wndW - 40, _wndH - 70 )];
[txtView setUsesFindBar:YES];
[txtView setEditable:YES];
[txtView setAllowsUndo: YES];
txtView.automaticQuoteSubstitutionEnabled = NO;
[scrlView setDocumentView: txtView];
// ***** Quit btn ***** //
NSButton *quitBtn = [[NSButton alloc]initWithFrame:NSMakeRect( _wndW - 50, 5, 40, 40 )];
[quitBtn setBezelStyle:NSBezelStyleCircular ];
[quitBtn setTitle: #"Q" ];
[quitBtn setAutoresizingMask: NSViewMinXMargin];
[quitBtn setAction:#selector(terminate:)];
[[window contentView] addSubview: quitBtn];
}
#end
#interface AppDelegate : NSObject <NSApplicationDelegate>
- (void) buildMenu;
#end
#implementation AppDelegate
- (BOOL)applicationShouldOpenUntitledFile:(NSApplication *)sender {
return NO;
}
- (void) buildMenu {
NSMenu *mainMenu = [NSMenu new];
[NSApp setMainMenu:mainMenu];
// **** App Menu **** //
NSMenuItem *appMenuItem = [NSMenuItem new];
[mainMenu addItem:appMenuItem];
NSMenu *appMenu = [NSMenu new] ;
[appMenuItem setSubmenu:appMenu];
NSString *appName = [[NSProcessInfo processInfo] processName];
NSString *aboutTitle = [#"About " stringByAppendingString:appName];
[appMenu addItemWithTitle: aboutTitle action:#selector(orderFrontStandardAboutPanel:) keyEquivalent:#""];
[appMenu addItem:[NSMenuItem separatorItem]];
[appMenu addItemWithTitle: #"Quit" action:#selector(terminate:) keyEquivalent:#"q"];
// ******** File Menu ********//
NSMenuItem *fileMenuItem = [NSMenuItem new];
[mainMenu addItem:fileMenuItem];
NSMenu *fileMenu = [[NSMenu alloc] initWithTitle:#"File"];
[fileMenuItem setSubmenu:fileMenu];
[fileMenu addItemWithTitle: #"New" action: #selector(newDocument:) keyEquivalent:#"n"];
[fileMenu addItemWithTitle: #"Open..." action: #selector(openDocument:) keyEquivalent:#"o"];
[fileMenu addItem: [NSMenuItem separatorItem]];
[fileMenu addItemWithTitle: #"Close" action: #selector(performClose:) keyEquivalent:#"w"];
[fileMenu addItemWithTitle: #"Save" action: #selector(saveDocument:) keyEquivalent:#"s"];
[fileMenu addItemWithTitle: #"SaveAs..." action: #selector(saveDocumentAs:) keyEquivalent:#""];
// ******** Edit Menu ********//
NSMenuItem *editMenuItem = [NSMenuItem new];
[mainMenu addItem:editMenuItem];
NSMenu *editMenu = [[NSMenu alloc] initWithTitle:#"Edit"] ;
[editMenuItem setSubmenu:editMenu];
[editMenu addItemWithTitle: #"Undo" action:#selector(undo:) keyEquivalent:#"z"];
[editMenu addItemWithTitle: #"Redo" action:#selector(redo:) keyEquivalent:#"Z"];
[editMenu addItem:[NSMenuItem separatorItem]];
[editMenu addItemWithTitle: #"Cut" action:#selector(cut:) keyEquivalent:#"x"];
[editMenu addItemWithTitle: #"Copy" action:#selector(copy:) keyEquivalent:#"c"];
[editMenu addItemWithTitle: #"Paste" action:#selector(paste:) keyEquivalent:#"v"];
[editMenu addItemWithTitle: #"Delete" action:#selector(delete:) keyEquivalent:#""];
[editMenu addItemWithTitle: #"Select All" action:#selector(selectAll:) keyEquivalent:#"a"];
[editMenu addItem:[NSMenuItem separatorItem]];
NSMenuItem *findItem = [editMenu addItemWithTitle:#"Find" action:#selector(performTextFinderAction:) keyEquivalent:#"f"];
[findItem setTag: NSTextFinderActionShowFindInterface];
}
- (void) applicationWillFinishLaunching: (NSNotification *)notification {
[self buildMenu];
}
- (void) applicationDidFinishLaunching: (NSNotification *)notification {
}
#end
int main() {
NSApplication *application = [NSApplication sharedApplication];
AppDelegate *appDelegate = [[AppDelegate alloc] init];
[application setDelegate:appDelegate];
[application run];
return 0;
}
Unable to post image of plist. Sorry.
Related
I try to assign a file type to my application.
In Info.plist I add:
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>type</string>
</array>
<key>CFBundleTypeIconFile</key>
<string>icon</string>
<key>CFBundleTypeName</key>
<string>My Project</string>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>LSTypeIsPackage</key>
<false/>
</dict>
</array>
In Main.mm:
....
-(BOOL) application:(NSApplication *)sender openFile:(NSString *)filename {
NSLog(#"Opened by file");
return YES;
}
#end
int main(int argc, char* argv[]) {
[NSApplication sharedApplication];
[[[[Window alloc] init] autorelease] makeMainWindow];
[NSApp run];
return 0;
}
But when I try double click on the my file type, The app only open with the warn: could not be opened, MyApp cannot open file in format. Also the message from NSLog is not called at all.
There are several issues with the code you posted but I was able to get the desired behavior with a few modifications.
I assume this is your window interface and implementation:
#interface Window : NSWindow <NSApplicationDelegate>
- (BOOL)application:(NSApplication *)sender openFile:(NSString *)filename;
#end
#implementation Window
- (BOOL)application:(NSApplication *)sender openFile:(NSString *)filename {
NSLog(#"Opened by file");
return YES;
}
#end
This is extremely odd to be using a window object as an application delegate. Normally, you have a controller object that owns and manages the window and also acts as the application's delegate.
In any case, it's still possible to get... well, functional behavior by changing the main() function to the following:
int main(int argc, const char * argv[]) {
[NSApplication sharedApplication];
Window *window = [[[Window alloc] init] autorelease];
NSApp.delegate = window;
[window makeKeyAndOrderFront:nil];
[NSApp run];
return 0;
}
There are two notable changes. First, your problem was that you didn't set the window instance to be the application delegate. Second, IIRC, you should never call -makeMainWindow directly; rather, that method exists so that you can override it if you wish. If you want to display the window on screen, you call -makeKeyAndOrderFront:.
Opening a file should display the logged line in console (if you're using Xcode 12.5.1, resize the log window if needed to workaround the display bug).
Under manual reference counting, I believe this would leak memory, since no autorelease pool is created, but I didn't see any of the usual warnings in console. Anyway, while this code works, it results in a fairly undesirable scenario. There is no main menu in the app so to quit it you have to use the Dock. The window created is also tiny and has no resizing capabilities, etc.
EDIT: An example project is at https://github.com/NSGod/OpenFile.
The following subclass of NSWindow should allow you to save a file with a unique ‘.jaf’ extension and then reopen the file into the app by double clicking on it. The info.plist is not as critical as I initially thought; I did not alter the one created by Xcode. Most important for this non-Document based app seems to be the calling of NSApplicationDelegate method -(BOOL) application: openFile. The NSApplicationDelegate was added to the NSWindow subclass instead of having a separate AppDelegate as is usually the case. When working correctly you should hear a beep when this method is called after a .jaf file is double-clicked; I couldn’t find the NSLog output. To run the demo in Xcode first create an objc project and delete everything in the ‘main.m’ file and copy/paste the following source code into it. Delete the pre-supplied AppDelegate class to avoid duplicate symbols. In the entitlements set the App Sandbox to NO and set read-only to zero. After the JAF app has been made, use it to save a file to your desktop with the ‘.jaf’ extension. Then make a copy of the app (shown in the Finder) and copy/paste it into the Applications folder. The next step is critical; right click on the file that you just made and use either Get Info or Open With to set the file to always open with your newly made app. At this point you should be able to double click on the xxxx.jaf file and have it open into your app with an audible beep.
#import <Cocoa/Cocoa.h>
#interface Window : NSWindow <NSApplicationDelegate> {
NSTextView *txtView;
}
- (instancetype)initWithContentRect:(NSRect)contentRect styleMask:(NSWindowStyleMask)style backing:(NSBackingStoreType)backingStoreType defer:(BOOL)flag;
-(void) buildMenu;
-(void) openAction;
-(void) saveAction;
#end
#implementation Window
#define _wndW 700
#define _wndH 550
- (BOOL)application:(NSApplication *)sender openFile:(NSString *)filename {
NSLog(#"This comes from JAF : filename = %#.",filename);
NSBeep(); // Listen for this.
NSError *error;
NSURL *url = [NSURL fileURLWithPath:filename];
NSString *fileStr = [[NSString alloc] initWithContentsOfURL:url encoding:NSUTF8StringEncoding error:&error];
if (!fileStr) {
NSLog(#"Unable to open file %#", error);
} else {
[txtView setString:fileStr];
}
return YES;
}
-(void) buildMenu {
// **** Menu Bar **** //
NSMenu *menubar = [NSMenu new];
[NSApp setMainMenu:menubar];
// **** App Menu **** //
NSMenuItem *appMenuItem = [NSMenuItem new];
NSMenu *appMenu = [NSMenu new];
[appMenu addItemWithTitle: #"Quit" action:#selector(terminate:) keyEquivalent:#"q"];
[appMenuItem setSubmenu:appMenu];
[menubar addItem:appMenuItem];
}
-(void) openAction {
NSOpenPanel *op = [NSOpenPanel openPanel];
[op setAllowedFileTypes:[NSArray arrayWithObjects: #"jaf", #"txt", nil]];
[op beginSheetModalForWindow: self completionHandler: ^(NSInteger returnCode) {
if (returnCode == NSModalResponseOK) {
NSURL *url = [op URL];
NSError *error;
NSString *fileStr = [[NSString alloc] initWithContentsOfURL:url encoding:NSUTF8StringEncoding error:&error];
if (!fileStr) {
NSLog(#"Unable to open file %#", error);
} else {
[self->txtView setString:fileStr];
}
}
}];
}
-(void) saveAction {
NSSavePanel *sp = [NSSavePanel savePanel];
[sp setTitle:#"Save contents to file"];
[sp setAllowedFileTypes:[NSArray arrayWithObjects: #"jaf", nil]];
[sp setNameFieldStringValue: #".jaf"];
[sp beginSheetModalForWindow: self completionHandler: ^(NSInteger returnCode) {
if (returnCode == NSModalResponseOK) {
NSURL *url = [sp URL];
NSString *viewStr = [[self->txtView textStorage] string];
NSError *err;
BOOL fileSaved = [viewStr writeToURL:url atomically:YES encoding:NSUTF8StringEncoding error:&err];
if (!fileSaved) { NSLog(#"Unable to save file due to error: %#", err);}
}
}];
}
- (instancetype)initWithContentRect:(NSRect)contentRect styleMask:(NSWindowStyleMask)style backing:(NSBackingStoreType)backingStoreType defer:(BOOL)flag {
self = [super initWithContentRect:NSMakeRect(0, 0, _wndW, _wndH) styleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable backing:NSBackingStoreBuffered defer:NO];
[self setTitle: #"Test window"];
[self center];
[self makeKeyAndOrderFront: nil];
// ****** NSTextView with Scroll ****** //
NSScrollView *scrlView = [[NSScrollView alloc] initWithFrame:NSMakeRect( 10, 10, _wndW - 20, _wndH - 80 )];
[[self contentView] addSubview:scrlView];
[scrlView setHasVerticalScroller: YES];
[scrlView setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable ];
txtView = [[NSTextView alloc] initWithFrame:NSMakeRect( 0, 0, _wndW - 20, _wndH - 80 )];
[scrlView setDocumentView: txtView];
// **** Open Button **** //
NSButton *openBtn =[[NSButton alloc]initWithFrame:NSMakeRect( 30, _wndH - 50, 95, 30 )];
[openBtn setBezelStyle:NSBezelStyleRounded ];
[openBtn setTitle: #"Open"];
[openBtn setAutoresizingMask: NSViewMinYMargin];
[openBtn setAction: #selector (openAction)];
[[self contentView] addSubview: openBtn];
// **** Save Button **** //
NSButton *saveBtn =[[NSButton alloc]initWithFrame:NSMakeRect( 130, _wndH - 50, 95, 30 )];
[saveBtn setBezelStyle:NSBezelStyleRounded ];
[saveBtn setTitle: #"Save"];
[saveBtn setAutoresizingMask: NSViewMinYMargin];
[saveBtn setAction: #selector (saveAction)];
[[self contentView] addSubview: saveBtn];
return self;
}
- (BOOL)windowShouldClose:(id)sender {
[NSApp terminate:sender];
return YES;
}
#end
int main() {
NSApplication *application = [NSApplication sharedApplication];
Window *window = [[Window alloc]init];
[window buildMenu];
[application setDelegate:window];
[application activateIgnoringOtherApps:YES];
[NSApp run];
return 0;
}
The menu bar of the MAC should display the menu title and submenus I set.
NSMenu *subMenu = [[NSMenu alloc] initWithTitle:YMLocalizedString(#"assistant.menu.title")];
[subMenu addItems:#[preventRevokeItem,
autoAuthItem,
groupMgrMenu,
newWeChatItem,
forwardAndReplyItem,
]];
NSMenuItem *menuItem = [[NSMenuItem alloc] init];
menuItem.target = self;
menuItem.enabled = NO;
[menuItem setTitle:YMLocalizedString(#"assistant.menu.title")];
[menuItem setSubmenu:subMenu];
[[[NSApplication sharedApplication] mainMenu] addItem:menuItem];
This example may be run in Xcode by deleting the main.m code and replacing it with the following. Also delete the pre-supplied AppDelegate files.
#import <Cocoa/Cocoa.h>
#interface AppDelegate : NSObject <NSApplicationDelegate> {
NSWindow *window;
}
- (void) menuAction: (id)sender;
- (void) buildMenu;
- (void) buildWindow;
#end
#implementation AppDelegate
- (void) menuAction: (id)sender {
NSBeep();
NSLog(#"%#", sender);
}
- (void) buildMenu {
NSMenu *menubar = [NSMenu new];
NSMenuItem *menuBarItem = [NSMenuItem new];
[menubar addItem:menuBarItem];
[NSApp setMainMenu:menubar];
NSMenu *appMenu = [NSMenu new];
NSMenuItem *quitMenuItem = [[NSMenuItem alloc] initWithTitle:#"Quit"
action:#selector(terminate:) keyEquivalent:#"q"];
[appMenu addItem:quitMenuItem];
[menuBarItem setSubmenu:appMenu];
// **** Asst Menu **** //
NSMenuItem *asstMenuItem = [menubar addItemWithTitle:#"" action:nil keyEquivalent:#""];
NSMenu *asstMenu = [[NSMenu alloc] initWithTitle:#"assistant.menu.title"];
[menubar setSubmenu: asstMenu forItem:asstMenuItem];
NSArray *itemArray = #[#"preventRevokeItem", #"autoAuthItem", #"groupMgrMenu", #"newWeChatItem", #"forwardAndReplyItem"];
[asstMenu addItemWithTitle: itemArray[0] action:#selector(menuAction:) keyEquivalent:#""];
[asstMenu addItemWithTitle: itemArray[1] action:#selector(menuAction:) keyEquivalent:#""];
[asstMenu addItemWithTitle: itemArray[2] action:#selector(menuAction:) keyEquivalent:#""];
[asstMenu addItemWithTitle: itemArray[3] action:#selector(menuAction:) keyEquivalent:#""];
[asstMenu addItemWithTitle: itemArray[4] action:#selector(menuAction:) keyEquivalent:#""];
}
- (void) buildWindow {
#define _wndW 300
#define _wndH 250
window = [[NSWindow alloc] initWithContentRect: NSMakeRect( 0, 0, _wndW, _wndH )
styleMask: NSWindowStyleMaskTitled | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskClosable | NSWindowStyleMaskResizable
backing: NSBackingStoreBuffered defer: NO];
[window center];
[window setTitle: #"Test window"];
[window makeKeyAndOrderFront: nil];
// ***** Quit btn ***** //
NSButton *quitBtn = [[NSButton alloc]initWithFrame:NSMakeRect( _wndW - 50, 5, 40, 40 )];
[quitBtn setBezelStyle:NSBezelStyleCircular ];
[quitBtn setTitle: #"Q" ];
[quitBtn setAutoresizingMask: NSViewMinXMargin];
[quitBtn setAction:#selector(terminate:)];
[[window contentView] addSubview: quitBtn];
}
- (void) applicationWillFinishLaunching: (NSNotification *)notification {
[self buildMenu];
[self buildWindow];
}
- (void) applicationDidFinishLaunching: (NSNotification *)notification {
}
#end
int main () {
NSApplication *application = [NSApplication sharedApplication];
AppDelegate *appDelegate = [[AppDelegate alloc] init];
[application setDelegate:appDelegate];
[application run];
return 0;
}
I have created a custom NSView with an AVPlayer embedded and it is not showing at all
this is my header:
#interface VideoPlayer : NSView
- (void)loadVideo;
#end
Implementation:
#implementation VideoPlayer
AVPlayer *avPlayer;
AVPlayerLayer* playerLayer;
- (instancetype)initWithFrame:(NSRect)rect {
self = [super initWithFrame:rect];
[self setWantsLayer:YES];
[self setNeedsDisplay:YES];
self.hidden = NO;
return self;
}
-(void) loadVideo {
[avPlayer pause];
avPlayer = nil;
playerLayer = nil;
NSURL *videoURL = [NSURL fileURLWithPath:#"file://~/Documents/tests.mp4"];
//same error with a valid url
//NSURL *videoURL = [NSURL URLWithString:#"http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerEscapes.mp4"];
avPlayer = [AVPlayer playerWithURL:videoURL];
playerLayer = [AVPlayerLayer playerLayerWithPlayer:avPlayer];
playerLayer.frame = self.frame;//or your desired CGRect
playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
//playerLayer.masksToBounds = YES;
[self.layer addSublayer:playerLayer];
[avPlayer play];
}
#end
And this is how I am creating the view:
view = [[VideoPlayer alloc] initWithFrame:NSMakeRect(0, 0, 500, 500)];
view.hidden = false;
[view loadVideo];
[parent_view addSubview:view];
I have tried multiple combinations, but the result is always the same... Nothing is being rendered on the application.
On the other hand, if I override the method drawRect in my view like this:
- (void)drawRect:(NSRect)dirtyRect {
[super drawRect:dirtyRect];
[[NSColor whiteColor] setFill];
NSRectFill(dirtyRect);
[super drawRect:dirtyRect];
}
I am getting a white rectangle where it is suppose to show my video which is expected. So I assume that I am missing something else, but most of the examples are using UIView which is not an option for me at this moment (I am working with some specific constraints)
Any thoughts?
Thank you
Update:
This finally worked for me:
-(void) loadVideo {
AVPlayer *avPlayer = [AVPlayer playerWithURL:[NSURL URLWithString:#"file://localhost/Users/xxxxxxxx/Documents/xxxxxxx.mp4"]];
AVPlayerView *playerView = [[AVPlayerView alloc] initWithFrame:self.bounds];
[playerView setPlayer:avPlayer];
[self addSubview:playerView];
[playerView.player play];
}
To perhaps make things a little clearer the following source code will create a basic AVPlayer for audio files. Note that the addition of both AVKit and AVFoundation frameworks are required for AVPlayerView and AVPlayer respectively. The code uses automatic reference counting and may be run in Terminal or used in Xcode by replacing main.m and AppDelegate and deleting the main nib in info.plist. To run in Terminal, copy/paste code into a file named avplayer.m and use the cmdLine as shown below. Apple docs state that it only runs on MacOS.
/*
To run in Terminal: clang avplayer.m -fobjc-arc -framework Cocoa -framework AVKit -framework AVFoundation -o avplayer && ./avplayer
*/
#import <Cocoa/Cocoa.h>
#import <AVKit/AVKit.h>
#import <AVFoundation/AVFoundation.h>
#interface AppDelegate : NSObject <NSApplicationDelegate> {
NSWindow *window;
AVPlayerView *playerView;
}
- (void) openAction;
- (void) buildMenu;
- (void) buildWindow;
#end
#implementation AppDelegate
- (void) openAction {
NSOpenPanel *op = [NSOpenPanel openPanel];
if ( [op runModal] == NSModalResponseOK ) {
AVPlayer *player = [AVPlayer playerWithURL:[op URL]];
[playerView setPlayer:player];
[window setTitleWithRepresentedFilename:[[op URL]lastPathComponent]];
}
}
- (void) buildMenu {
NSMenu *menubar = [NSMenu new];
NSMenuItem *menuBarItem = [NSMenuItem new] ;
[menubar addItem:menuBarItem];
[NSApp setMainMenu:menubar];
NSMenu *appMenu = [NSMenu new];
NSMenuItem *quitMenuItem = [[NSMenuItem alloc] initWithTitle:#"Quit" action:#selector(terminate:) keyEquivalent:#"q"];
[appMenu addItem:quitMenuItem];
[menuBarItem setSubmenu:appMenu];
}
- (void) buildWindow {
#define _wndW 500
#define _wndH 400
window = [[NSWindow alloc] initWithContentRect: NSMakeRect( 0, 0, _wndW, _wndH ) styleMask: NSWindowStyleMaskTitled | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskClosable backing: NSBackingStoreBuffered defer: NO];
[window center];
[window setTitle: #"Test window"];
[window makeKeyAndOrderFront: nil];
// **** AVPlayerView **** //
playerView = [[AVPlayerView alloc] initWithFrame:NSMakeRect( 0, 60, _wndW, _wndH - 60)];
[[window contentView] addSubview:playerView];
// **** Open Button **** //
NSButton *myBtn =[[NSButton alloc]initWithFrame:NSMakeRect( 30, 20, 125, 30 )];
[myBtn setBezelStyle:NSBezelStyleRounded ];
[myBtn setTitle: #"Open audio file"];
[myBtn setAction: #selector (openAction)];
[[window contentView] addSubview: myBtn];
// **** Quit btn **** //
NSButton *quitBtn = [[NSButton alloc]initWithFrame:NSMakeRect( _wndW - 50, 5, 40, 40 )];
[quitBtn setBezelStyle:NSBezelStyleCircular ];
[quitBtn setTitle: #"Q" ];
[quitBtn setAutoresizingMask: NSViewMinXMargin];
[quitBtn setAction:#selector(terminate:)];
[[window contentView] addSubview: quitBtn];
}
- (void) applicationWillFinishLaunching: (NSNotification *)notification {
[self buildMenu];
[self buildWindow];
}
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender {
return YES;
}
#end
int main () {
NSApplication *application = [NSApplication sharedApplication];
AppDelegate *appDelegate = [[AppDelegate alloc] init];
[application setDelegate:appDelegate];
[application run];
return 0;
}
Make sure that you add the AVKit framework to your project.
There is a header in AVKit framework called AVPlayerView.h
Then all you need to do to see the player is to call it:
// **** AVPlayer ***** //
AVPlayerView *playerView = [[AVPlayerView alloc] initWithFrame:NSMakeRect( 0, 0, _wndW, _wndH - 100)];
[[window contentView] addSubview:playerView];
I have a programmatic demo which I could post if you are unable to get it to work.
I have a NSStatusItem with a menu attached. How can I get mouse/touch events from the status item without losing the menu? I was thinking perhaps some kind of workaround where I take in the events and manually pop the menu up, but I am unsure of the feasibility.
The following example demonstrates the problem. The only major difference from this example and my actual code is I am using a menu delegate.
#import <Cocoa/Cocoa.h>
#interface AppDelegate : NSObject <NSApplicationDelegate> {
IBOutlet NSWindow *window;
NSStatusItem* statusItem;
NSMenu* statusMenu;
NSMenuItem* menuItem;
}
-(IBAction)stuffHappened:(id)sender;
#end
#implementation AppDelegate
-(void)awakeFromNib{
statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength];
statusMenu = [[NSMenu alloc] initWithTitle:#""];
menuItem = [[NSMenuItem alloc] initWithTitle:#"test"
action:nil
keyEquivalent:#""];
statusItem.button.title = #"\U0001F410";
[statusItem setMenu:statusMenu]; //commenting out this line allows the action to fire
[statusMenu addItem:menuItem];
[[statusItem button] setTarget:self];
statusItem.button.action = #selector(stuffHappened:);
}
-(IBAction)stuffHappened:(id)sender {
NSLog(#"Stuff happened");
}
#end
This solution came from a previous SO question:Highlighting NSStatusItem with attributed string
and may do what you want. Unfortunately, popUpStatusItemMenu is now deprecated.
#import <Cocoa/Cocoa.h>
#interface AppDelegate : NSObject <NSApplicationDelegate> {
NSStatusItem* statusItem;
NSMenu* statusMenu;
NSMenuItem* menuItem;
}
-(void)statusItemHandler:(id)sender;
-(void)menuHandler:(id)sender;
#end
#implementation AppDelegate
-(void)menuHandler:(id)sender {
NSLog(#"Menu item = %#",sender);
}
-(void)statusItemHandler:(id)sender {
NSLog(#"StatusItem hit.");
statusMenu = [[NSMenu alloc] init];
menuItem = [statusMenu addItemWithTitle: #"Item 1" action:#selector(menuHandler:) keyEquivalent:#""];
menuItem = [statusMenu addItemWithTitle: #"Item 2" action:#selector(menuHandler:) keyEquivalent:#""];
[statusMenu addItem:[NSMenuItem separatorItem]];
menuItem = [statusMenu addItemWithTitle:#"Quit" action:#selector(terminate:) keyEquivalent:#""];
[statusItem popUpStatusItemMenu:statusMenu];
}
-(void)applicationDidFinishLaunching:(NSNotification *)notification {
statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength];
statusItem.button.title = #"\U0001F410";
statusItem.button.action = #selector(statusItemHandler:);
}
#end
int main(){
NSApplication *application = [NSApplication sharedApplication];
[application setActivationPolicy:NSApplicationActivationPolicyRegular];
AppDelegate *appDelegate = [[AppDelegate alloc] init];
[application setDelegate:appDelegate];
[application activateIgnoringOtherApps:YES];
[application run];
return 0;
}
This nib-less programmatic approach will run in Xcode if you replace main.m and delete the MainMenu nib in the info.plist (uses ARC):
#import <Cocoa/Cocoa.h>
#interface AppDelegate : NSObject <NSApplicationDelegate> {
NSStatusItem* statusItem;
NSMenuItem* menuItem;
}
-(void)stuffHappened:(id)sender;
#end
#implementation AppDelegate
//-(void)awakeFromNib{
- (void) applicationDidFinishLaunching:(NSNotification *)notification {
NSMenu *menu = [[NSMenu alloc] init];
statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:60];
statusItem.button.title = #"foobar";
[statusItem setMenu:menu];
menuItem = [menu addItemWithTitle:#"Item 1" action:#selector(stuffHappened:) keyEquivalent:#""];
[menuItem setTarget:self];
menuItem = [menu addItemWithTitle:#"Item 2" action:#selector(stuffHappened:) keyEquivalent:#""];
[menuItem setTarget:self];
[menu addItem:[NSMenuItem separatorItem]];
menuItem = [menu addItemWithTitle:#"Quit" action:#selector(terminate:) keyEquivalent:#""];
}
-(void)stuffHappened:(id)sender {
NSLog(#"Stuff happened : %#",sender);
}
#end
int main(){
NSApplication *application = [NSApplication sharedApplication];
[application setActivationPolicy:NSApplicationActivationPolicyRegular];
AppDelegate *appDelegate = [[AppDelegate alloc] init];
[application setDelegate:appDelegate];
[application activateIgnoringOtherApps:YES];
[application run];
return 0;
}
I'm building an OS X cocoa application and I'm not using interface builder (for a variety of reasons). I've got the application to the point of loading a menu, title bar and main window, but I can't seem to figure out how to add the stoplight buttons to the title bar (programmatically).
My AppDelegate.m looks like this:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
MainViewController *mVC = [MainViewController new];
[mVC showMainViewController];
}
Then code in the MainViewController then creates the menu, window, and loads the application, as follows:
//
// MainViewController.m
// TestApp
//
#import "MainViewController.h"
#implementation MainViewController
#synthesize menubar;
#synthesize appMenu;
#synthesize appMenuItem;
#synthesize quitMenuItem;
#synthesize appName;
#synthesize quitTitle;
#synthesize window;
#synthesize homeViewController;
#synthesize resolutionHeight;
#synthesize resolutionWidth;
#synthesize width;
#synthesize height;
- (id)init
{
self = [super init];
if (self) {
appName = #"TestApp";
[self setupMenubar];
[self setupMainWindow];
}
return self;
}
- (void)setupMenubar
{
// Set up the main menu
menubar = [NSMenu new];
appMenu = [NSMenu new];
appMenuItem = [NSMenuItem new];
quitTitle = [NSString stringWithFormat:#"Quit %#", appName];
quitMenuItem = [[NSMenuItem alloc] initWithTitle:quitTitle
action:#selector(terminate:)
keyEquivalent:#"q"];
[menubar addItem:appMenuItem];
[appMenu addItem:quitMenuItem];
[appMenuItem setSubmenu:appMenu];
[NSApp setMainMenu:menubar];
}
- (void)setupMainWindow
{
// set the dimensions of the application
resolutionWidth = [[NSScreen mainScreen] frame].size.width;
resolutionHeight = [[NSScreen mainScreen] frame].size.height;
width = resolutionWidth * 0.75;
height = resolutionHeight * 0.75;
window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, width, height)
styleMask:NSTitledWindowMask
backing:NSBackingStoreBuffered defer:NO];
[window cascadeTopLeftFromPoint:NSMakePoint(10, 10)];
// add window buttons
closeButton = [NSWindow standardWindowButton:NSWindowCloseButton forStyleMask:NSTitledWindowMask];
// set metadata for the window
[window setTitle:appName];
[window makeKeyAndOrderFront:nil];
}
- (void)showMainViewController
{
// Set app settings
[NSApplication sharedApplication];
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
[NSApp activateIgnoringOtherApps:YES];
[NSApp run];
}
#end
I've looked around and I'm kind of at a loss for how to proceed.
You might try changing your NSWindow init method to the following:
window = [[NSWindow alloc]
initWithContentRect:NSMakeRect(0, 0, width, height)
styleMask:NSTitledWindowMask | NSClosableWindowMask |
NSMiniaturizableWindowMask | NSResizableWindowMask
backing:NSBackingStoreBuffered defer:NO];
I believe that ORing in the additional masks automatically adds the corresponding buttons to the title bar for you: NSClosableWindowMask adds the close button, NSMiniaturizableWindowMask adds the minimize (center) button, and NSResizableWindowMask adds the zoom (rightmost) button.