diff --git a/demos/Lazarus_Mac/ExternalPumpBrowser/create_mac_helper.sh b/demos/Lazarus_Mac/ExternalPumpBrowser/create_mac_helper.sh index bd124ded..c9065689 100755 --- a/demos/Lazarus_Mac/ExternalPumpBrowser/create_mac_helper.sh +++ b/demos/Lazarus_Mac/ExternalPumpBrowser/create_mac_helper.sh @@ -5,4 +5,9 @@ cd "$(dirname "$0")" ../../Lazarus_any_OS/AppHelper/create_mac_helper_apps.sh ../../../bin/ExternalPumpBrowser.app +if [ "$(grep -i TCrCocoaApplication ../../../bin/ExternalPumpBrowser.app/Contents/Info.plist)" = "" ]; +then +sed -i '' "1,4s//\n NSPrincipalClass<\/key>\n TCrCocoaApplication<\/string>/" ../../../bin/ExternalPumpBrowser.app/Contents/Info.plist +fi + cd "$CDIR" diff --git a/demos/Lazarus_Mac/ExternalPumpBrowser/uExternalPumpBrowser.pas b/demos/Lazarus_Mac/ExternalPumpBrowser/uExternalPumpBrowser.pas index 177bb3d5..5abb22b3 100644 --- a/demos/Lazarus_Mac/ExternalPumpBrowser/uExternalPumpBrowser.pas +++ b/demos/Lazarus_Mac/ExternalPumpBrowser/uExternalPumpBrowser.pas @@ -43,7 +43,9 @@ unit uExternalPumpBrowser; interface uses - GlobalCefApplication, Classes, SysUtils, Messages, Forms, Controls, Graphics, + GlobalCefApplication, + uCEFLazarusCocoa, // required for Cocoa + Classes, SysUtils, Messages, Forms, Controls, Graphics, Dialogs, ExtCtrls, StdCtrls, LMessages, uCEFChromium, uCEFWindowParent, uCEFConstants, uCEFTypes, uCEFInterfaces, uCEFChromiumEvents, uCEFLinkedWindowParent, uCEFWorkScheduler; @@ -194,7 +196,9 @@ end; procedure TForm1.Chromium1Close(Sender: TObject; const browser: ICefBrowser; var aAction: TCefCloseBrowserAction); begin - aAction := cbaClose; + // continue closing the browser + CEFLinkedWindowParent1.DestroyChildWindow; + aAction := cbaDelay; end; procedure TForm1.Chromium1BeforeClose(Sender: TObject; const browser: ICefBrowser); @@ -267,6 +271,7 @@ begin end; initialization + AddCrDelegate; if GlobalCEFApp = nil then begin CreateGlobalCEFApp; if not GlobalCEFApp.StartMainProcess then begin diff --git a/demos/Lazarus_any_OS/ExternalPumpBrowser/create_mac_helper.sh b/demos/Lazarus_any_OS/ExternalPumpBrowser/create_mac_helper.sh index 83d700b3..cecaf4d7 100755 --- a/demos/Lazarus_any_OS/ExternalPumpBrowser/create_mac_helper.sh +++ b/demos/Lazarus_any_OS/ExternalPumpBrowser/create_mac_helper.sh @@ -5,4 +5,9 @@ cd "$(dirname "$0")" ../AppHelper/create_mac_helper_apps.sh ../../../bin/ExternalPumpBrowser.app +if [ "$(grep -i TCrCocoaApplication ../../../bin/ExternalPumpBrowser.app/Contents/Info.plist)" = "" ]; +then +sed -i '' "1,4s//\n NSPrincipalClass<\/key>\n TCrCocoaApplication<\/string>/" ../../../bin/ExternalPumpBrowser.app/Contents/Info.plist +fi + cd "$CDIR" diff --git a/demos/Lazarus_any_OS/ExternalPumpBrowser/uExternalPumpBrowser.pas b/demos/Lazarus_any_OS/ExternalPumpBrowser/uExternalPumpBrowser.pas index e1099b4b..6047a901 100644 --- a/demos/Lazarus_any_OS/ExternalPumpBrowser/uExternalPumpBrowser.pas +++ b/demos/Lazarus_any_OS/ExternalPumpBrowser/uExternalPumpBrowser.pas @@ -43,7 +43,9 @@ unit uExternalPumpBrowser; interface uses - GlobalCefApplication, Classes, SysUtils, Messages, Forms, Controls, Graphics, + GlobalCefApplication, + uCEFLazarusCocoa, // required for Cocoa + Classes, SysUtils, Messages, Forms, Controls, Graphics, Dialogs, ExtCtrls, StdCtrls, LMessages, uCEFChromium, uCEFWindowParent, uCEFConstants, uCEFTypes, uCEFInterfaces, uCEFChromiumEvents, uCEFLinkedWindowParent, uCEFWorkScheduler; @@ -291,6 +293,9 @@ end; {$ENDIF} initialization + {$IFDEF DARWIN} // $IFDEF MACOSX + AddCrDelegate; + {$ENDIF} if GlobalCEFApp = nil then begin CreateGlobalCEFApp; if not GlobalCEFApp.StartMainProcess then begin diff --git a/packages/cef4delphi_lazarus.lpk b/packages/cef4delphi_lazarus.lpk index 94fe124f..b0be2c1b 100644 --- a/packages/cef4delphi_lazarus.lpk +++ b/packages/cef4delphi_lazarus.lpk @@ -22,7 +22,7 @@ - + @@ -831,6 +831,10 @@ + + + + diff --git a/packages/cef4delphi_lazarus.pas b/packages/cef4delphi_lazarus.pas index 91ef40df..e3ac23de 100644 --- a/packages/cef4delphi_lazarus.pas +++ b/packages/cef4delphi_lazarus.pas @@ -65,7 +65,8 @@ uses uCEFMediaSinkDeviceInfoCallback, uCEFJson, uCEFBitmapBitBuffer, uCEFPrintDialogCallback, uCEFPrintHandler, uCEFPrintJobCallback, uCEFLinuxFunctions, uCEFLinuxTypes, uCEFLinuxConstants, - uCEFWorkSchedulerQueueThread, uCEFLinkedWinControlBase, LazarusPackageIntf; + uCEFWorkSchedulerQueueThread, uCEFLinkedWinControlBase, uCEFLazarusCocoa, + LazarusPackageIntf; implementation diff --git a/source/uCEFWinControl.pas b/source/uCEFWinControl.pas index 23ad611d..9eccbb1a 100644 --- a/source/uCEFWinControl.pas +++ b/source/uCEFWinControl.pas @@ -37,15 +37,18 @@ unit uCEFWinControl; +{$I cef.inc} + {$IFDEF FPC} {$MODE OBJFPC}{$H+} + {$IFDEF MACOSX} + {$ModeSwitch objectivec1} + {$ENDIF} {$ENDIF} {$IFNDEF CPUX64}{$ALIGN ON}{$ENDIF} {$MINENUMSIZE 4} -{$I cef.inc} - interface uses @@ -57,6 +60,9 @@ uses LCLProc, LCLType, LCLIntf, LResources, InterfaceBase, {$ENDIF} {$ENDIF} + {$IFDEF FPC}{$IFDEF MACOSX} + CocoaAll, + {$ENDIF}{$ENDIF} uCEFTypes, uCEFInterfaces; type @@ -186,12 +192,25 @@ function TCEFWinControl.DestroyChildWindow : boolean; var TempHWND : HWND; {$ENDIF} +{$IFDEF FPC}{$IFDEF MACOSX} +var + ViewObj: NSObject; +{$ENDIF}{$ENDIF} begin {$IFDEF MSWINDOWS} TempHWND := ChildWindowHandle; Result := (TempHWND <> 0) and DestroyWindow(TempHWND); {$ELSE} Result := False; + {$IFDEF FPC}{$IFDEF MACOSX} + ViewObj := NSObject(ChildWindowHandle); + if ViewObj <> nil then begin + if ViewObj.isKindOfClass_(nsview) then begin + NSView(ViewObj).removeFromSuperview; + Result := True; + end; + end; + {$ENDIF}{$ENDIF} {$ENDIF} end; diff --git a/source/uceflazaruscocoa.pas b/source/uceflazaruscocoa.pas new file mode 100644 index 00000000..7684107e --- /dev/null +++ b/source/uceflazaruscocoa.pas @@ -0,0 +1,174 @@ +// ************************************************************************ +// ***************************** CEF4Delphi ******************************* +// ************************************************************************ +// +// CEF4Delphi is based on DCEF3 which uses CEF to embed a chromium-based +// browser in Delphi applications. +// +// The original license of DCEF3 still applies to CEF4Delphi. +// +// For more information about CEF4Delphi visit : +// https://www.briskbard.com/index.php?lang=en&pageid=cef +// +// Copyright © 2021 Salvador Diaz Fau. All rights reserved. +// +// Unit Author: Jonas Maebe +// + +unit uCEFLazarusCocoa; + + +{$mode objfpc}{$H+} +{$I cef.inc} + +{$IFDEF DARWIN} // $IFDEF MACOSX +{$ModeSwitch objectivec2} +{$ENDIF} + +interface + +uses +{$IFDEF DARWIN} // $IFDEF MACOSX + CocoaAll, CocoaInt, Cocoa_Extra, +{$ENDIF} + Classes, SysUtils; + +{$IFDEF DARWIN} // $IFDEF MACOSX +type + CrAppProtocol = objcprotocol + function isHandlingSendEvent: objcbool; message 'isHandlingSendEvent'; + end; + + CrAppControlProtocol = objcprotocol(CrAppProtocol) + procedure setHandlingSendEvent(handlingSendEvent: objcbool); message 'setHandlingSendEvent:'; + end; + + TCrCocoaApplication = objcclass(TCocoaApplication, CrAppControlProtocol) + public + function isHandlingSendEvent: LCLObjCBoolean; + procedure setHandlingSendEvent(handlingSendEvent: LCLObjCBoolean); + procedure sendEvent(theEvent: NSEvent); override; + + procedure terminate(sender: id); override; + private + fHandlingSendEvent: LCLObjCBoolean; + end; + + procedure AddCrDelegate; + +{$ENDIF} + +implementation + +{$IFDEF DARWIN} // $IFDEF MACOSX +uses + Forms; + +type + TChromeAppDelegateIntercept = objcclass(NSProxy) + procedure tryToTerminateApplication(app: NSApplication); message 'tryToTerminateApplication:'; + function initWithDelegate(delegate: id): id; message 'initWithDelegate:'; + procedure dealloc; override; + function respondsToSelector(aSelector: SEL): LCLObjCBoolean; override; + procedure forwardInvocation (invocation: NSInvocation); override; + function methodSignatureForSelector (sel_: SEL): NSMethodSignature; override; + + private + fLCLDelegate: id; + end; + +procedure TChromeAppDelegateIntercept.tryToTerminateApplication(app: NSApplication); + begin + Application.MainForm.Close; + end; + + +function TChromeAppDelegateIntercept.initWithDelegate(delegate: id): id; + begin + fLCLDelegate:=delegate; + fLCLDelegate.retain; + result:=self; + end; + + +procedure TChromeAppDelegateIntercept.dealloc; +begin + fLCLDelegate.release; + fLCLDelegate:=nil; + inherited dealloc; +end; + + +function TChromeAppDelegateIntercept.respondsToSelector(aSelector: SEL): LCLObjCBoolean; +begin + if aSelector = objcselector('tryToTerminateApplication:') then + result:=true + else if assigned(fLCLDelegate) then + result:=fLCLDelegate.respondsToSelector(aSelector) + else + result:=false; +end; + + +procedure TChromeAppDelegateIntercept.forwardInvocation(invocation: NSInvocation); +begin + { this only gets called in case we can't handle the invocation } + if assigned(fLCLDelegate) then + begin + invocation.setTarget(fLCLDelegate); + invocation.invoke; + end; +end; + + +function TChromeAppDelegateIntercept.methodSignatureForSelector(sel_: SEL): NSMethodSignature; +begin + { if the original delegate can handle it, send it there. Otherwise we try to handle it } + if assigned(fLCLDelegate) then + result:=fLCLDelegate.methodSignatureForSelector(sel_); + if not assigned(result) then + result:=inherited; +end; + + +procedure AddCrDelegate; +var + delegate: id; +begin + delegate := TChromeAppDelegateIntercept.alloc.initWithDelegate(NSApp.delegate); + NSApp.setDelegate(delegate); +end; + + +function TCrCocoaApplication.isHandlingSendEvent: LCLObjCBoolean; +begin + result:=fHandlingSendEvent; +end; + +procedure TCrCocoaApplication.setHandlingSendEvent(handlingSendEvent: LCLObjCBoolean); +begin + fHandlingSendEvent:=handlingSendEvent; +end; + +procedure TCrCocoaApplication.sendEvent(theEvent: NSEvent); +var + CurrentHandling: LCLObjCBoolean; +begin + CurrentHandling:=isHandlingSendEvent; + setHandlingSendEvent(true); + inherited; + setHandlingSendEvent(CurrentHandling); +end; + +procedure TCrCocoaApplication.terminate(sender: id); +var + AppDelegate: TChromeAppDelegateIntercept; +begin + AppDelegate:=TChromeAppDelegateIntercept(NSApp.delegate); + AppDelegate.tryToTerminateApplication(CocoaWidgetSet.NSApp); +end; + +{$ENDIF} + +end. +