Using native Cocoa WebKit for System.Windows.Forms.WebBrowser on Mac OS X

View: New views
8 Messages — Rating Filter:   Alert me  

Using native Cocoa WebKit for System.Windows.Forms.WebBrowser on Mac OS X

by Alexander Shulgin :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

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-osx mailing list
Mono-osx@...
http://lists.ximian.com/mailman/listinfo/mono-osx

mono-cocoa-webkit-0.1.0.tar.gz (4K) Download Attachment
SimpleBrowser.zip (3K) Download Attachment

Re: Using native Cocoa WebKit for System.Windows.Forms.WebBrowser on Mac OS X

by Alexander Shulgin :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Alex Shulgin wrote:
> Hi,
>
> Recently I've been struggling to bring up native (Cocoa-based) WebKit as
> WinForms WebBrowser control on OS X.

Just wondering...  Do my efforts look _that_ crazy so no one is willing
even to comment? ;)

--
Yours,
Alex

_______________________________________________
Mono-osx mailing list
Mono-osx@...
http://lists.ximian.com/mailman/listinfo/mono-osx

Re: Using native Cocoa WebKit for System.Windows.Forms.WebBrowser on Mac OS X

by Atsushi Eno-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

There is a few hackers who can _review and_ commit changes, and
it is very likely no osx hacker has enough time to do it now.

We are pretty much resource-limited team :(

Atsushi Eno


Alex Shulgin wrote:

> Alex Shulgin wrote:
>> Hi,
>>
>> Recently I've been struggling to bring up native (Cocoa-based) WebKit as
>> WinForms WebBrowser control on OS X.
>
> Just wondering...  Do my efforts look _that_ crazy so no one is willing
> even to comment? ;)
>
> --
> Yours,
> Alex
>
> _______________________________________________
> Mono-osx mailing list
> Mono-osx@...
> http://lists.ximian.com/mailman/listinfo/mono-osx
>
>
>

_______________________________________________
Mono-osx mailing list
Mono-osx@...
http://lists.ximian.com/mailman/listinfo/mono-osx

Re: Using native Cocoa WebKit for System.Windows.Forms.WebBrowser on Mac OS X

by Alexander Shulgin :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Atsushi Eno wrote:
> There is a few hackers who can _review and_ commit changes, and
> it is very likely no osx hacker has enough time to do it now.

I didn't say it should be committed.  I just need some help from OSX
guys out there.  If they could say anything, even "it can't be done, so
forget about it", I'd go look for another options. :)

> We are pretty much resource-limited team :(

OK, at least I know I'm not being ignored.

--
Regards,
Alex

> Alex Shulgin wrote:
>> Alex Shulgin wrote:
>>> Hi,
>>>
>>> Recently I've been struggling to bring up native (Cocoa-based) WebKit
>>> as WinForms WebBrowser control on OS X.
>>
>> Just wondering...  Do my efforts look _that_ crazy so no one is
>> willing even to comment? ;)
>>
>> --
>> Yours,
>> Alex
>>
>> _______________________________________________
>> Mono-osx mailing list
>> Mono-osx@...
>> http://lists.ximian.com/mailman/listinfo/mono-osx

_______________________________________________
Mono-osx mailing list
Mono-osx@...
http://lists.ximian.com/mailman/listinfo/mono-osx

Re: Using native Cocoa WebKit for System.Windows.Forms.WebBrowser on Mac OS X

by Atsushi Eno-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Alex Shulgin wrote:
> Atsushi Eno wrote:
>> There is a few hackers who can _review and_ commit changes, and
>> it is very likely no osx hacker has enough time to do it now.
>
> I didn't say it should be committed.  I just need some help from OSX
> guys out there.  If they could say anything, even "it can't be done, so
> forget about it", I'd go look for another options. :)

They'd do it more or less later I guess.

>> We are pretty much resource-limited team :(
>
> OK, at least I know I'm not being ignored.

We don't - at least I don't. See http://twitter.com/monocontributor :)

Atsushi Eno

>
> --
> Regards,
> Alex
>
>> Alex Shulgin wrote:
>>> Alex Shulgin wrote:
>>>> Hi,
>>>>
>>>> Recently I've been struggling to bring up native (Cocoa-based)
>>>> WebKit as WinForms WebBrowser control on OS X.
>>>
>>> Just wondering...  Do my efforts look _that_ crazy so no one is
>>> willing even to comment? ;)
>>>
>>> --
>>> Yours,
>>> Alex
>>>
>>> _______________________________________________
>>> Mono-osx mailing list
>>> Mono-osx@...
>>> http://lists.ximian.com/mailman/listinfo/mono-osx
>
>
>

_______________________________________________
Mono-osx mailing list
Mono-osx@...
http://lists.ximian.com/mailman/listinfo/mono-osx

Re: [Mono-winforms-list] Using native Cocoa WebKit for System.Windows.Forms.WebBrowser on Mac OS X

by Miguel de Icaza-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hello,

> > Recently I've been struggling to bring up native (Cocoa-based) WebKit as
> > WinForms WebBrowser control on OS X.
>
> Just wondering...  Do my efforts look _that_ crazy so no one is willing
> even to comment? ;)

I think it is a good idea.

But I do not know anything about the technical requirements of running
WebKit with our current Carbon-based mainloop.

I am sure it can be creatively integrated, but I am unable to provide
any assitance.

Miguel.

_______________________________________________
Mono-osx mailing list
Mono-osx@...
http://lists.ximian.com/mailman/listinfo/mono-osx

Re: [Mono-winforms-list] Using native Cocoa WebKit for System.Windows.Forms.WebBrowser on Mac OS X

by Geoff Norton-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


On 25-Jun-09, at 9:13 PM, Miguel de Icaza wrote:

> Hello,
>
>>> Recently I've been struggling to bring up native (Cocoa-based)  
>>> WebKit as
>>> WinForms WebBrowser control on OS X.
>>
>> Just wondering...  Do my efforts look _that_ crazy so no one is  
>> willing
>> even to comment? ;)
>
> I think it is a good idea.
>
> But I do not know anything about the technical requirements of running
> WebKit with our current Carbon-based mainloop.
>
> I am sure it can be creatively integrated, but I am unable to provide
> any assitance.

Last I looked (in the 10.4 days) this was a no go because of the  
Carbon-based mainloop.  There was talk that apple would unify and  
deliver the Cocoa events but I'm not too sure if that has happened.

I'm sure its surmountable if osmeone decided to run with it, but its  
certainly non-trivial.

-g

_______________________________________________
Mono-osx mailing list
Mono-osx@...
http://lists.ximian.com/mailman/listinfo/mono-osx

Re: Using native Cocoa WebKit for System.Windows.Forms.WebBrowser on Mac OS X

by Alexander Shulgin :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Alex Shulgin wrote:
> Hi,
>
> Recently I've been struggling to bring up native (Cocoa-based) WebKit as
> WinForms WebBrowser control on OS X.
>
[snip]
>
> * 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.

UPDATE: in mono-cocoa-webkit module, WebBrowser.cs: a call to
NSThread.MakeMultithreaded() causes memory corruption and random crashes
on Mac OS X 10.6 Snow Leopard.

Turned out, it is not really needed so can be safely removed.

--
Regards,
Alex

_______________________________________________
Mono-osx mailing list
Mono-osx@...
http://lists.ximian.com/mailman/listinfo/mono-osx