Hi,
Recently I've been struggling to bring up native (Cocoa-based) WebKit as
WinForms WebBrowser control on OS X.
The approach I've used works to some degree, but has problems for which
I need your help to solve.
Here's what I've come up with:
* I've found out that there's an API to integrate Cocoa views into
Carbon views (HICocoaViewCreate, HICocoaViewSetView et al).
For this to work with WinForms we'd need to subclass
"com.apple.HICocoaView", otherwise system events won't be translated to
WinForms messages.
I have taken a shortcut and added new internal field to CreateParams
class and used it in CreateWindow to select special subclass name.
To support this on the WebBrowser control side, I've patched
WebBrowserBase.cs to use CreateParams.internal_param when running on Mac OS.
This might look a bit clumsy, but it works. See hicocoaview-subclass.patch.
* After that I've noticed that the actual browser engine to use is
chosen in Mono.WebBrowser/Manager.cs. I've patched it to use alternate
implementation on Mac OS by default. See Mono.WebBrowser.Manager.patch.
* Finally, I've added mono-cocoa-webkit.dll modeled after
mono-webkit.dll to provide minimum required functionality: create WebKit
& navigate to URL.
I've used Monobjc bridge to create WebKit instance for simplicity:
http://monobjc.net/See attached sources archive for details. You can use make; sudo make
install. Also, you'll need to install Monobjc dlls to gac too for this
to work:
e.g. in ~/src/Monobjc-2.0.357.0/dist/2.0/
$ sudo gacutil -i Monobjc.dll
$ sudo gacutil -i Monobjc.Cocoa.dll
$ sudo gacutil -i Monobjc.WebKit.dll
With all this I was able to use WinForms WebBrowser with native WebKit
sitting inside it. :) But there are some problems. :(
With this approach the WebBrowser control is grabbing focus after a
click on it and extra click on some other control is required to make it
lose the focus.
Sample code to test is attached in SimpleBrowser.zip.
I've compiled System.Windows.Forms.dll with most of debugging macros
defined, and it all boils down to the fact that during the click
WebBrowser control is receiving button down event, but no button up.
The relevant part of debugging info is like this:
NativeWindow.cs: Message WM_MOUSEFIRST, result 0
CarbonInternal.EventHandler: callref=BFFFED20, eventref=9D9C80,
handle=9BD070, klass=1836021107, kind=1
CarbonInternal.MouseHandler: callref=BFFFED20, eventref=9D9C80,
handle=9BD070, kind=1
NativeWindow.cs (10227120, WM_LBUTTONDOWN, 1, 7405631): result 0
Control 'System.Windows.Forms.WebBrowser' (9C0DB0) received message
msg=0x201 (WM_LBUTTONDOWN) hwnd=0x9c0db0 wparam=0x1 lparam=0x71003f
result=0x0
IsEnabled('System.Windows.Forms.WebBrowser' (9C0DB0)): Called, Result=True
set_Capture: 'System.Windows.Forms.WebBrowser' (9C0DB0) value=True
is_captured=False IsHandleCreated=True
GrabWindow('System.Windows.Forms.WebBrowser' (9C0DB0), '' (0)): Called
NativeWindow.cs: Message WM_LBUTTONDOWN, result 0
Moreover, after the click inside the browser it seems that it stops
receiving Carbon events altogether, so there's no chance to translate
them into WinForms messages...
So, basically I'm stuck here. Any pointers & suggestions are much
appreciated!
--
Cheers,
Alex
Index: Manager.cs
===================================================================
--- Manager.cs (revision 136302)
+++ Manager.cs (working copy)
@@ -25,6 +25,7 @@
using System;
using System.Reflection;
+using System.Runtime.InteropServices;
namespace Mono.WebBrowser
{
@@ -39,8 +40,17 @@
{
string browserEngine = Environment.GetEnvironmentVariable ("MONO_BROWSER_ENGINE");
-#if NET_2_0
- if (browserEngine == "webkit") {
+#if NET_2_0
+ if (RunningOnMacOSX) {
+ if (browserEngine == null || browserEngine == "webkit") {
+ try {
+ Assembly assembly = Assembly.LoadWithPartialName ("mono-cocoa-webkit");
+ return (IWebBrowser) assembly.CreateInstance ("Mono.CocoaWebKit.WebBrowser");
+ } catch {
+ browserEngine = null;
+ }
+ }
+ } else if (browserEngine == "webkit") {
Assembly ass;
try {
ass = Assembly.LoadWithPartialName ("mono-webkit");
@@ -57,6 +67,31 @@
throw new Exception (Mono.WebBrowser.Exception.ErrorCodes.EngineNotSupported, browserEngine);
}
-
+ // OS detection hackery grabbed from System.Windows.Forms/XplatUI.cs
+ static bool RunningOnUnix {
+ get {
+ int p = (int) Environment.OSVersion.Platform;
+ return (p == 4 || p == 6 || p == 128);
+ }
+ }
+
+ static bool RunningOnMacOSX {
+ get {
+ bool ret = false;
+ if (RunningOnUnix) {
+ IntPtr buf = Marshal.AllocHGlobal (8192);
+ if (uname (buf) == 0) {
+ string os = Marshal.PtrToStringAnsi (buf);
+ if (os == "Darwin")
+ ret = true;
+ }
+ Marshal.FreeHGlobal (buf);
+ }
+ return ret;
+ }
+ }
+
+ [DllImport ("libc")]
+ static extern int uname (IntPtr buf);
}
}
Index: XplatUICarbon.cs
===================================================================
--- XplatUICarbon.cs (revision 136302)
+++ XplatUICarbon.cs (working copy)
@@ -244,6 +244,7 @@
SetFrontProcess (ref psn);
HIObjectRegisterSubclass (__CFStringMakeConstantString ("com.novell.mwfview"), __CFStringMakeConstantString ("com.apple.hiview"), 0, Carbon.EventHandler.EventHandlerDelegate, (uint)Carbon.EventHandler.HIObjectEvents.Length, Carbon.EventHandler.HIObjectEvents, IntPtr.Zero, ref Subclass);
+ HIObjectRegisterSubclass (__CFStringMakeConstantString ("com.novell.mwfhicocoaview"), __CFStringMakeConstantString ("com.apple.HICocoaView"), 0, Carbon.EventHandler.EventHandlerDelegate, (uint)Carbon.EventHandler.HIObjectEvents.Length, Carbon.EventHandler.HIObjectEvents, IntPtr.Zero, ref Subclass);
Carbon.EventHandler.InstallApplicationHandler ();
@@ -996,7 +997,7 @@
}
HIObjectCreate (__CFStringMakeConstantString ("com.novell.mwfview"), 0, ref WholeWindow);
- HIObjectCreate (__CFStringMakeConstantString ("com.novell.mwfview"), 0, ref ClientWindow);
+ HIObjectCreate (__CFStringMakeConstantString (cp.internal_param != null ? (string) cp.internal_param : "com.novell.mwfview"), 0, ref ClientWindow);
Carbon.EventHandler.InstallControlHandler (WholeWindow);
Carbon.EventHandler.InstallControlHandler (ClientWindow);
Index: CreateParams.cs
===================================================================
--- CreateParams.cs (revision 136302)
+++ CreateParams.cs (working copy)
@@ -45,6 +45,7 @@
private IntPtr parent;
internal Menu menu;
internal Control control;
+ internal object internal_param;
#endregion // Local variables
#region Public Constructors
Index: WebBrowserBase.cs
===================================================================
--- WebBrowserBase.cs (revision 136302)
+++ WebBrowserBase.cs (working copy)
@@ -304,9 +304,80 @@
{
base.WndProc (ref m);
}
+
+ protected override CreateParams CreateParams {
+ get {
+ CreateParams cp = base.CreateParams;
+ if (UsingCocoaWebKit) {
+ cp.internal_param = "com.novell.mwfhicocoaview";
+ }
+ return cp;
+ }
+ }
+
+ protected override void OnPaint (PaintEventArgs e)
+ {
+ if (UsingCocoaWebKit)
+ return;
+
+ base.OnPaint (e);
+ }
+ protected override void OnPaintBackground (PaintEventArgs e)
+ {
+ if (UsingCocoaWebKit)
+ return;
+
+ base.OnPaintBackground (e);
+ }
+
#endregion
+ // OS detection hackery grabbed from System.Windows.Forms/XplatUI.cs
+ static bool? using_cocoa_webkit = null;
+
+ static bool UsingCocoaWebKit {
+ get {
+ if (using_cocoa_webkit == null) {
+ using_cocoa_webkit = false;
+
+ if (RunningOnMacOSX) {
+ string browserEngine = Environment.GetEnvironmentVariable ("MONO_BROWSER_ENGINE");
+ if (browserEngine == null || browserEngine == "webkit")
+ using_cocoa_webkit = true;
+ }
+ }
+
+ return (bool) using_cocoa_webkit;
+ }
+ }
+
+ static bool RunningOnUnix {
+ get {
+ int p = (int) Environment.OSVersion.Platform;
+ return (p == 4 || p == 6 || p == 128);
+ }
+ }
+
+ static bool RunningOnMacOSX {
+ get {
+ bool ret = false;
+ if (RunningOnUnix) {
+ IntPtr buf = Marshal.AllocHGlobal (8192);
+ if (uname (buf) == 0) {
+ string os = Marshal.PtrToStringAnsi (buf);
+ if (os == "Darwin")
+ ret = true;
+ }
+ Marshal.FreeHGlobal (buf);
+ }
+ return ret;
+ }
+ }
+
+ [DllImport ("libc")]
+ static extern int uname (IntPtr buf);
+
#region Internal Properties
enum State
_______________________________________________
Mono-winforms-list maillist -
Mono-winforms-list@...
http://lists.ximian.com/mailman/listinfo/mono-winforms-list