RhinoCommon Mods for V6/Mac

@Alain, @piac, @dan, @DavidRutten, @JohnM, @brian, @andy, @dale, @jesterKing you may all be interested in this topic with respect to future development of our .NET SDK. I’m making this topic public since it may be useful for other devs.

I’ve been working on V6 RhinoCommon for the last week and have finally gotten to a point where RhinoCommon does not have a reference to Windows.Forms!! My next step is to merge these changes into the Mac code.

RhinoCommon still has a dependency on System.Drawing which is platform specific, but I’m making sure to only use the basic structs like Point, Color, Rectangle, … and am staying away from anything more complex (i.e. not using Graphics or Brushes or Bitmaps). As we add more functions to RhinoCommon, please make sure that the only System.Drawing classes/structs you use are of these very basic types. Please don’t hesitate to ask when you run into cases where you want to add something to RhinoCommon that involves System.Drawing.

The one missing piece that people like @JohnM and @andy may be interested in is that we can’t use IWin32Window in our RhinoCommon functions anymore to define the parent window. I’m still working on this issue and will hopefully have something useful soon. For now, these functions just take an object as input and the Handle property is looked up through reflection.

Moving forward, everything Windows platform specific will be placed in the “RhinoWindows” project that will ship with V6 and everything Mac platform specific will be placed in the “RhinoMac” project. I’ve set up a basic ServiceLocator in RhinoCommon that will load implementations of interfaces from RhinoWindows/RhinoMac based on where the process is being executed (really stupid simple dependency injection.) Plug-in developers can reference these assemblies to get platform specific features.

An example of the dependency injection technique

The Rhino.UI.Dialogs class has a bunch of static functions to show some pre-canned dialogs. These are typically used by python to show user interface for basic tasks like a dialog with a textbox and a button to allow for input text. In V5 for Windows, RhinoCommon directly creates a Windows Form to show the UI. In the current code for Mac, this crashes Rhino since WinForms is a no no. In V6, there is now an interface in RhinoCommon

public interface IDialogService
  bool ShowEditBox(string title, string message, string defaultText, bool multiline, out string text);

  ... other functions ...

In RhinoWindows, we have a concrete implementation of this interface that still uses WinForms. RhinoCommon though has been changed to

public static bool ShowEditBox(string title, string message, string defaultText, bool multiline, out string text)
  return Service.ShowEditBox(title, message, defaultText, multiline, out text);

static IDialogService g_service_implementation;
static IDialogService Service
    if (g_service_implementation == null)
      // GetPlatformService gets interfaces from RhinoWindows when running on Windows
      // and from RhinoMac when running on Mac
      g_service_implementation = Runtime.HostUtils.GetPlatformService<IDialogService>();
      if (g_service_implementation == null)
        g_service_implementation = new NotImplementedDialogService();
    return g_service_implementation;

My next task is to implement this interface on Mac Rhino so dialogs like the edit box use Cocoa user interface instead of Winforms.

There’s nothing really new or extravagant here. I think we just need to follow this pattern of interfaces or abstract base classes in our platform agnostic libraries and concrete implementations in the platform specific libraries. @DavidRutten, I wanted to let you know where I’m currently at with all of this (which isn’t a whole lot of progress, but it’s a start.) Once I’ve figured out the RhinoMac part of IDialogService, I think we should start laying out the pieces to get a cross platform 2D drawing toolkit in place (using either GDI+ or Direct2D on Windows and CoreGraphics on OSX.) I’ve already done a lot of work in that area and need to just figure out an appropriate way to ship it with V6.

1 Like

@stevebaer, instead of doing a 2D drawing toolkit utilising separate backends, wouldn’t it make more sense to implement those on top of OpenGL - cross-platform and known to work well. That way there’d be even less code to maintain and even possible to get a (higher) degree of similarity between the apps.


2D drawing toolkits (GDI+, Direct2D, CoreGraphics) are typically highly optimized for crisp and clear 2D type entities. These toolkits also work well with generating vector type output.

We could always choose to use OpenGL as a concrete implementation on any platform, I just don’t want to ever expose any OpenGL specific functionality at the abstract layer.

Just out of curiosity, is there anything about this scheme that would make it difficult to add unix/linux at some future time?

I know that’s way out there, if ever, but may as well protect for the possibility.

Cool!, finally using a DI+factory technique… I knew you were going to, sooner or later! :slight_smile:


Pretty far out there for sure, but this approach is specifically for the purpose of multi platform development.

Rhino3dmIo which is a subset of RhinoCommon is already compiled and running on Windows, OSX, iOS, android, and Linux.

1 Like

Well I guess that proves you all know how to do it!