cocoa: revise window creation approach. the handle returned from CreateHandle method is now window content, rather than window itself. to be done: create either window or panel based on the border style

git-svn-id: trunk@43481 -
This commit is contained in:
dmitry 2013-11-26 05:14:46 +00:00
parent faa6ee5f53
commit 863c0b7125
2 changed files with 325 additions and 26 deletions

View File

@ -25,7 +25,7 @@ uses
Types, Classes, SysUtils,
CGGeometry,
// Libs
MacOSAll, CocoaAll, CocoaUtils, CocoaGDIObjects,
CocoaAll, CocoaUtils, CocoaGDIObjects,
// LCL
LCLType, Controls;
@ -272,6 +272,37 @@ type
procedure sendEvent(event: NSEvent); override;
end;
TCocoaWindow = objcclass(NSWindow, NSWindowDelegateProtocol)
protected
function windowShouldClose(sender : id): LongBool; message 'windowShouldClose:';
procedure windowWillClose(notification: NSNotification); message 'windowWillClose:';
procedure windowDidBecomeKey(notification: NSNotification); message 'windowDidBecomeKey:';
procedure windowDidResignKey(notification: NSNotification); message 'windowDidResignKey:';
procedure windowDidResize(notification: NSNotification); message 'windowDidResize:';
procedure windowDidMove(notification: NSNotification); message 'windowDidMove:';
public
callback: IWindowCallback;
function acceptsFirstResponder: Boolean; override;
function canBecomeKeyWindow: Boolean; override;
function becomeFirstResponder: Boolean; override;
function resignFirstResponder: Boolean; override;
function lclGetCallback: ICommonCallback; override;
procedure lclClearCallback; override;
// mouse
procedure mouseDown(event: NSEvent); override;
procedure mouseUp(event: NSEvent); override;
procedure rightMouseDown(event: NSEvent); override;
procedure rightMouseUp(event: NSEvent); override;
procedure otherMouseDown(event: NSEvent); override;
procedure otherMouseUp(event: NSEvent); override;
procedure mouseDragged(event: NSEvent); override;
procedure mouseEntered(event: NSEvent); override;
procedure mouseExited(event: NSEvent); override;
procedure mouseMoved(event: NSEvent); override;
procedure sendEvent(event: NSEvent); override;
end;
{ TCocoaCustomControl }
TCocoaCustomControl = objcclass(NSControl)
@ -302,6 +333,20 @@ type
procedure resetCursorRects; override;
end;
{ TCocoaWindowContent }
TCocoaWindowContent = objcclass(TCocoaCustomControl)
public
isembedded: Boolean; // true - if the content is inside of another control, false - if the content is in its own window;
ownwin: NSWindow;
function lclOwnWindow: NSWindow; message 'lclOwnWindow';
procedure lclSetFrame(const r: TRect); override;
procedure viewDidMoveToSuperview; override;
procedure viewDidMoveToWindow; override;
procedure viewWillMoveToWindow(newWindow: NSWindow); override;
procedure dealloc; override;
end;
{ TCocoaScrollView }
TCocoaScrollView = objcclass(NSScrollView)
@ -433,6 +478,53 @@ begin
Result := NSThread.currentThread.isMainThread;
end;
{ TCocoaWindowContent }
function TCocoaWindowContent.lclOwnWindow: NSWindow;
begin
if not isembedded then Result:=window
else Result:=nil;
end;
procedure TCocoaWindowContent.lclSetFrame(const r: TRect);
begin
if isembedded then inherited lclSetFrame(r)
else window.lclSetFrame(r);
end;
procedure TCocoaWindowContent.viewDidMoveToSuperview;
begin
inherited viewDidMoveToSuperview;
end;
procedure TCocoaWindowContent.viewDidMoveToWindow;
begin
isembedded:=window.contentView<>self;
if isembedded then begin
if Assigned(ownwin) then ownwin.close;
ownwin:=nil;
end else begin
ownwin:=window;
end;
inherited viewDidMoveToWindow;
end;
procedure TCocoaWindowContent.viewWillMoveToWindow(newWindow: NSWindow);
begin
if not isembedded then begin
window.close;
ownwin:=nil;
isembedded:=false;
end;
inherited viewWillMoveToWindow(newWindow);
end;
procedure TCocoaWindowContent.dealloc;
begin
inherited dealloc;
end;
{ TCocoaPanel }
function TCocoaPanel.windowShouldClose(sender: id): LongBool;
@ -601,6 +693,174 @@ begin
inherited sendEvent(event);
end;
{ TCocoaWindow }
function TCocoaWindow.windowShouldClose(sender: id): LongBool;
var
canClose: Boolean;
begin
canClose := True;
if Assigned(callback) then
callback.CloseQuery(canClose);
Result := canClose;
end;
procedure TCocoaWindow.windowWillClose(notification: NSNotification);
begin
if Assigned(callback) then
callback.Close;
end;
procedure TCocoaWindow.windowDidBecomeKey(notification: NSNotification);
begin
if Assigned(callback) then
callback.Activate;
end;
procedure TCocoaWindow.windowDidResignKey(notification: NSNotification);
begin
if Assigned(callback) then
callback.Deactivate;
end;
procedure TCocoaWindow.windowDidResize(notification: NSNotification);
begin
if Assigned(callback) then
callback.Resize;
end;
procedure TCocoaWindow.windowDidMove(notification: NSNotification);
begin
if Assigned(callback) then
callback.Move;
end;
function TCocoaWindow.acceptsFirstResponder: Boolean;
begin
Result := True;
end;
function TCocoaWindow.canBecomeKeyWindow: Boolean;
begin
Result := Assigned(callback) and callback.CanActivate;
end;
function TCocoaWindow.becomeFirstResponder: Boolean;
begin
Result := inherited becomeFirstResponder;
if Assigned(callback) then
callback.BecomeFirstResponder;
end;
function TCocoaWindow.resignFirstResponder: Boolean;
begin
Result := inherited resignFirstResponder;
if Assigned(callback) then
callback.ResignFirstResponder;
end;
function TCocoaWindow.lclGetCallback: ICommonCallback;
begin
Result := callback;
end;
procedure TCocoaWindow.lclClearCallback;
begin
callback := nil;
contentView.lclClearCallback;
end;
procedure TCocoaWindow.mouseDown(event: NSEvent);
begin
if not Assigned(callback) or not callback.MouseUpDownEvent(event) then
inherited mouseDown(event);
end;
procedure TCocoaWindow.mouseUp(event: NSEvent);
begin
if not Assigned(callback) or not callback.MouseUpDownEvent(event) then
inherited mouseUp(event);
end;
procedure TCocoaWindow.rightMouseDown(event: NSEvent);
begin
if not Assigned(callback) or not callback.MouseUpDownEvent(event) then
inherited rightMouseUp(event);
end;
procedure TCocoaWindow.rightMouseUp(event: NSEvent);
begin
if not Assigned(callback) or not callback.MouseUpDownEvent(event) then
inherited rightMouseDown(event);
end;
procedure TCocoaWindow.otherMouseDown(event: NSEvent);
begin
if not Assigned(callback) or not callback.MouseUpDownEvent(event) then
inherited otherMouseDown(event);
end;
procedure TCocoaWindow.otherMouseUp(event: NSEvent);
begin
if not Assigned(callback) or not callback.MouseUpDownEvent(event) then
inherited otherMouseUp(event);
end;
procedure TCocoaWindow.mouseDragged(event: NSEvent);
begin
if not Assigned(callback) or not callback.MouseMove(event) then
inherited mouseDragged(event);
end;
procedure TCocoaWindow.mouseEntered(event: NSEvent);
begin
inherited mouseEntered(event);
end;
procedure TCocoaWindow.mouseExited(event: NSEvent);
begin
inherited mouseExited(event);
end;
procedure TCocoaWindow.mouseMoved(event: NSEvent);
begin
if not Assigned(callback) or not callback.MouseMove(event) then
inherited mouseMoved(event);
end;
procedure TCocoaWindow.sendEvent(event: NSEvent);
var
Message: NSMutableDictionary;
Handle: HWND;
Msg: Cardinal;
WP: WParam;
LP: LParam;
Result: NSNumber;
Obj: NSObject;
begin
if event.type_ = NSApplicationDefined then
begin
// event which we get through PostMessage or SendMessage
if event.subtype = LCLEventSubTypeMessage then
begin
// extract message data
Message := NSMutableDictionary(event.data1);
Handle := NSNumber(Message.objectForKey(NSMessageWnd)).unsignedIntegerValue;
Msg := NSNumber(Message.objectForKey(NSMessageMsg)).unsignedLongValue;
WP := NSNumber(Message.objectForKey(NSMessageWParam)).integerValue;
LP := NSNumber(Message.objectForKey(NSMessageLParam)).integerValue;
// deliver message and set result
Obj := NSObject(Handle);
// todo: check that Obj is still a valid NSView/NSWindow
Result := NSNumber.numberWithInteger(Obj.lclDeliverMessage(Msg, WP, LP));
Message.setObject_forKey(Result, NSMessageResult);
Result.release;
end;
end
else
inherited sendEvent(event);
end;
{ TCocoaScrollView }
function TCocoaScrollView.acceptsFirstResponder: Boolean;

View File

@ -313,12 +313,15 @@ class function TCocoaWSCustomForm.CreateHandle(const AWinControl: TWinControl;
const AParams: TCreateParams): TLCLIntfHandle;
var
Form: TCustomForm absolute AWinControl;
win: TCocoaPanel;
cnt: TCocoaCustomControl;
win: TCocoaWindow;
cnt: TCocoaWindowContent;
ns: NSString;
R: NSRect;
begin
win := TCocoaPanel(TCocoaPanel.alloc);
//todo: create TCocoaWindow or TCocoaPanel depending on the border style
// if parent is specified neither Window nor Panel needs to be created
// the only thing that needs to be created is Content
win := TCocoaWindow(TCocoaWindow.alloc);
if not Assigned(win) then
begin
@ -327,12 +330,11 @@ begin
end;
R := CreateParamsToNSRect(AParams);
win := TCocoaPanel(win.initWithContentRect_styleMask_backing_defer(R, GetStyleMaskFor(GetDesigningBorderStyle(Form), Form.BorderIcons), NSBackingStoreBuffered, False));
win.setHidesOnDeactivate(False);
win := TCocoaWindow(win.initWithContentRect_styleMask_backing_defer(R, GetStyleMaskFor(GetDesigningBorderStyle(Form), Form.BorderIcons), NSBackingStoreBuffered, False));
UpdateWindowIcons(win, GetDesigningBorderStyle(Form), Form.BorderIcons);
win.setLevel(FormStyleToWindowLevel[Form.FormStyle]);
win.enableCursorRects;
TCocoaPanel(win).callback := TLCLWindowCallback.Create(win, AWinControl);
TCocoaWindow(win).callback := TLCLWindowCallback.Create(win, AWinControl);
win.setDelegate(win);
ns := NSStringUtf8(AWinControl.Caption);
win.setTitle(ns);
@ -342,7 +344,7 @@ begin
R.origin.x := 0;
R.origin.y := 0;
cnt := TCocoaCustomControl.alloc.initWithFrame(R);
cnt := TCocoaWindowContent.alloc.initWithFrame(R);
cnt.callback := TCocoaPanel(win).callback;
win.setContentView(cnt);
@ -356,31 +358,47 @@ begin
// TODO: docked forms
end;
Result := TLCLIntfHandle(win);
Result := TLCLIntfHandle(cnt);
end;
class function TCocoaWSCustomForm.GetText(const AWinControl: TWinControl; var AText: String): Boolean;
var
win : NSWindow;
begin
Result := AWinControl.HandleAllocated;
if Result then
AText := NSStringToString(NSWindow(AWinControl.Handle).title);
if Result then begin
win := TCocoaWindowContent(AWinControl.Handle).lclOwnWindow;
if not Assigned(win) then AText:=''
else AText := NSStringToString(win.title);
end;
end;
class function TCocoaWSCustomForm.GetTextLen(const AWinControl: TWinControl; var ALength: Integer): Boolean;
var
win : NSWindow;
begin
Result := AWinControl.HandleAllocated;
if Result then
ALength := NSWindow(AWinControl.Handle).title.length;
if Result then begin
win := TCocoaWindowContent(AWinControl.Handle).lclOwnWindow;
if Assigned(win) then
ALength := NSWindow(AWinControl.Handle).title.length
else
ALength := 0;
end;
end;
class procedure TCocoaWSCustomForm.SetText(const AWinControl: TWinControl; const AText: String);
var
ns: NSString;
win : NSWindow;
begin
if not AWinControl.HandleAllocated then Exit;
ns := NSStringUtf8(AText);
NSwindow(AWinControl.Handle).setTitle(ns);
ns.release;
win:=TCocoaWindowContent(AWinControl.Handle).lclOwnWindow;
if Assigned(win) then begin
ns := NSStringUtf8(AText);
NSwindow(win).setTitle(ns);
ns.release;
end;
end;
class procedure TCocoaWSCustomForm.CloseModal(const ACustomForm: TCustomForm);
@ -396,33 +414,53 @@ begin
end;
class procedure TCocoaWSCustomForm.SetAlphaBlend(const ACustomForm: TCustomForm; const AlphaBlend: Boolean; const Alpha: Byte);
var
win : NSWindow;
begin
if ACustomForm.HandleAllocated then
if ACustomForm.HandleAllocated then begin
win:=TCocoaWindowContent(ACustomForm.Handle).lclOwnWindow;
if not Assigned(win) then Exit;
if AlphaBlend then
NSWindow(ACustomForm.Handle).setAlphaValue(Alpha / 255)
win.setAlphaValue(Alpha / 255)
else
NSWindow(ACustomForm.Handle).setAlphaValue(1);
win.setAlphaValue(1);
end;
end;
class procedure TCocoaWSCustomForm.SetBorderIcons(const AForm: TCustomForm;
const ABorderIcons: TBorderIcons);
var
win : NSWindow;
begin
if AForm.HandleAllocated then
UpdateWindowMask(NSWindow(AForm.Handle), GetDesigningBorderStyle(AForm), ABorderIcons);
if AForm.HandleAllocated then begin
win:=TCocoaWindowContent(AForm.Handle).lclOwnWindow;
if Assigned(win) then
UpdateWindowMask(win, GetDesigningBorderStyle(AForm), ABorderIcons);
end;
end;
class procedure TCocoaWSCustomForm.SetFormBorderStyle(const AForm: TCustomForm;
const AFormBorderStyle: TFormBorderStyle);
var
win : NSWindow;
begin
if AForm.HandleAllocated then
UpdateWindowMask(NSWindow(AForm.Handle), AFormBorderStyle, AForm.BorderIcons);
if AForm.HandleAllocated then begin
win:=TCocoaWindowContent(AForm.Handle).lclOwnWindow;
if Assigned(win) then
UpdateWindowMask(win, AFormBorderStyle, AForm.BorderIcons);
end;
end;
class procedure TCocoaWSCustomForm.SetFormStyle(const AForm: TCustomform;
const AFormStyle, AOldFormStyle: TFormStyle);
var
win : NSWindow;
begin
if AForm.HandleAllocated then
NSWindow(AForm.Handle).setLevel(FormStyleToWindowLevel[AFormStyle]);
if AForm.HandleAllocated then begin
win:=TCocoaWindowContent(AForm.Handle).lclOwnWindow;
if Assigned(win) then
win.setLevel(FormStyleToWindowLevel[AFormStyle]);
end;
end;
class procedure TCocoaWSCustomForm.SetPopupParent(
@ -470,8 +508,9 @@ end;
class procedure TCocoaWSCustomForm.SetBounds(const AWinControl: TWinControl;
const ALeft, ATop, AWidth, AHeight: Integer);
begin
if AWinControl.HandleAllocated then
if AWinControl.HandleAllocated then begin
NSObject(AWinControl.Handle).lclSetFrame(Bounds(ALeft, ATop, AWidth, AHeight));
end;
end;
end.