I am using MonoMac to develop an application and so far have been delighted at how easy it is to use coming from the Windows world. However I am stumped on what should be an easy feature to implement: putting a close button in a tab header.
This was already asked here: Add a close button to NSTabviewitem
And one of the solutions was to use chromium tabs here: https://github.com/rsms/chromium-tabs
Is it possible to use something like that in a MonoMac project with MonoDevelop? I can add the library in xcode as a linked library but MonoDevelop doesn't seem to hold onto those changes.
Since (from my understanding) MonoDevelop basically generates a dynamic xCode project and discards it after editing I am not sure if it is possible and am hoping someone can shed some light on it for me.
I am not married to the idea of chromium tabs - open to any suggestions.
You are correct that you can't simply add the framework to the XCode project, because it's generated by MonoDevelop - it's not a 'real' project in that sense.
You have a couple of options:
1 - Write your own implementation in C#
2 - Choose an open source implementation (e.g. Chromium Tabs) and port it to C#. This should work but will obviously be time consuming. Also you may find that you need access to some Cocoa APIs that are not present in MonoMac yet - you would need to figure out a workaround or implement them.
3 - It's possible to bind a native framework into your app. Perhaps you can find someone that has already done this for the framework you're interested in; or you can do it yourself.
I've been struggling with #3 myself for a day or two now, but finally got it all figured out so I'll share the process with you and maybe this will be helpful.
I downloaded the chromium tabs source and compiled the framework. You will need to compile it as i386 only; since MonoMac currently only ships a 32 bit runtime
I added the ChromiumTabs.framework to my project, and set up a pre-build script to copy it to ${TargetDir}/${ProjectName}.app/Contents/Frameworks/
I load the framework manually inside Main, before the call to NSApplication.Init():
var baseAppPath = Directory.GetParent(Directory.GetParent(System.AppDomain.CurrentDomain.BaseDirectory).ToString());
var chromiumPath = baseAppPath + "/Frameworks/ChromiumTabs.framework/ChromiumTabs";
var hresult = Dlfcn.dlopen(chromiumPath, 0); // Non-zero result indicates success
Next, use parse.exe (available in MonoMac when you compile from source) and feed it the .h files from the framework. Use the generated output to create the interfaces that will define your binding (there is good documentation on binding types here). For example:
using System;
using System.Drawing;
using MonoMac.Foundation;
using MonoMac.AppKit;
namespace ChromiumTabs
{
[BaseType (typeof (NSWindowController))]
interface CTTabWindowController {
}
[BaseType (typeof (CTTabWindowController))]
interface CTBrowserWindowController {
[Export ("browser")]
CTBrowser Browser { get; }
[Export ("initWithBrowser:")]
IntPtr Constructor (CTBrowser browser);
}
[BaseType (typeof (NSObject))]
interface CTBrowser {
[Export ("addBlankTabInForeground:")]
CTTabContents AddBlankTabInForeground (bool foreground);
[Export ("createBlankTabBasedOn:")]
CTTabContents CreateBlankTabBasedOn (CTTabContents baseContents);
}
[BaseType (typeof (NSDocument))]
interface CTTabContents {
[Export ("initWithBaseTabContents:")]
IntPtr Constructor ([NullAllowed]CTTabContents baseContents);
[Export ("viewFrameDidChange:")]
void ViewFrameDidChange (RectangleF newFrame);
}
}
Now, feed that .cs file into bmac.exe (check the help for the arguments you need to supply). This will output a managed DLL which you can reference in your project.
You should now be able to use your new binding!
I did a very minimal binding on the library, just enough to get it up and running. You can download that here.