From 7ff50b386f8817c29aa49aa37a25959f59df87ba Mon Sep 17 00:00:00 2001 From: dmitry Date: Fri, 14 Sep 2018 19:01:14 +0000 Subject: [PATCH] cocoa: update detection of focused HWND. Updated handling of fieldEditor. No need for an extra field, as editors delegate property is populated by the system git-svn-id: trunk@58994 - --- lcl/interfaces/cocoa/cocoaint.pas | 2 +- lcl/interfaces/cocoa/cocoatextedits.pas | 153 +++++++++++------------- lcl/interfaces/cocoa/cocoawinapi.inc | 38 +++++- lcl/interfaces/cocoa/cocoawindows.pas | 1 - 4 files changed, 100 insertions(+), 94 deletions(-) diff --git a/lcl/interfaces/cocoa/cocoaint.pas b/lcl/interfaces/cocoa/cocoaint.pas index 3c93e7fefa..fdecc974d9 100644 --- a/lcl/interfaces/cocoa/cocoaint.pas +++ b/lcl/interfaces/cocoa/cocoaint.pas @@ -35,7 +35,7 @@ uses // private CocoaAll, CocoaPrivate, CocoaUtils, CocoaGDIObjects, cocoa_extra, CocoaWSMenus, CocoaWSForms, CocoaWindows, CocoaScrollers, - CocoaWSClipboard, + CocoaWSClipboard, CocoaTextEdits, // LCL LCLStrConsts, LMessages, LCLMessageGlue, LCLProc, LCLIntf, LCLType, Controls, Forms, Themes, Menus, diff --git a/lcl/interfaces/cocoa/cocoatextedits.pas b/lcl/interfaces/cocoa/cocoatextedits.pas index 5cad7037c6..a8cc8f203a 100644 --- a/lcl/interfaces/cocoa/cocoatextedits.pas +++ b/lcl/interfaces/cocoa/cocoatextedits.pas @@ -58,7 +58,6 @@ type TCocoaTextField = objcclass(NSTextField) callback: ICommonCallback; - procedure dealloc; override; function acceptsFirstResponder: Boolean; override; function becomeFirstResponder: Boolean; override; function RealResignFirstResponder: Boolean; message 'RealResignFirstResponder'; @@ -87,7 +86,6 @@ type TCocoaSecureTextField = objcclass(NSSecureTextField) public callback: ICommonCallback; - procedure dealloc; override; function acceptsFirstResponder: Boolean; override; function becomeFirstResponder: Boolean; override; function RealResignFirstResponder: Boolean; message 'RealResignFirstResponder'; @@ -156,7 +154,6 @@ type TCocoaFieldEditor = objcclass(NSTextView) public - lastEditBox: NSTextField; function resignFirstResponder: Boolean; override; // keyboard procedure keyDown(event: NSEvent); override; @@ -491,31 +488,46 @@ end;} { TCocoaFieldEditor } -function TCocoaFieldEditor.resignFirstResponder: Boolean; +function GetEditBox(src: TCocoaFieldEditor): NSView; +var + v : NSObject; begin + Result := nil; + if not Assigned(src) then Exit; + v := NSObject(src.delegate); + if Assigned(v) and (v.isKindOfClass(NSView)) then + Result := NSView(v); +end; + +function TCocoaFieldEditor.resignFirstResponder: Boolean; +var + v : NSObject; +begin + v := GetEditBox(Self); //DebugLn('[TCocoaFieldEditor.resignFirstResponder]'); - if (lastEditBox <> nil) then + if (v <> nil) then begin - if lastEditBox.isKindOfClass_(TCocoaTextField) then + if v.isKindOfClass_(TCocoaTextField) then begin - TCocoaTextField(lastEditBox).RealResignFirstResponder(); + TCocoaTextField(v).RealResignFirstResponder(); end - else if lastEditBox.isKindOfClass_(TCocoaSecureTextField) then + else if v.isKindOfClass_(TCocoaSecureTextField) then begin - TCocoaSecureTextField(lastEditBox).RealResignFirstResponder(); + TCocoaSecureTextField(v).RealResignFirstResponder(); end; - lastEditBox := nil; end; Result := inherited resignFirstResponder; end; procedure TCocoaFieldEditor.keyDown(event: NSEvent); var - cb : ICommonCallback; + cb : ICommonCallback; res : Boolean; + v : NSView; begin - if Assigned(lastEditBox) then - cb := lastEditBox.lclGetCallback + v := GetEditBox(Self); + if Assigned(v) then + cb := v.lclGetCallback else cb := nil; @@ -537,87 +549,111 @@ begin end; procedure TCocoaFieldEditor.mouseDown(event: NSEvent); +var + v : NSView; begin - if Assigned(lastEditBox) then + v := GetEditBox(Self); + if Assigned(v) then begin - if Assigned(lastEditBox.lclGetCallback) and not lastEditBox.lclGetCallback.MouseUpDownEvent(event) then + if Assigned(v.lclGetCallback) and not v.lclGetCallback.MouseUpDownEvent(event) then begin inherited mouseDown(event); // NSTextView runs internal mouse-tracking loop in it's mouseDown implemenation. // Thus "inherited mouseDown" only returns after the mouse has been released. // why is TCocoaTextView not affected? - if Assigned(lastEditBox) and Assigned(lastEditBox.lclGetCallback) then - lastEditBox.lclGetCallback.MouseUpDownEvent(event, true); + if Assigned(v) and Assigned(v.lclGetCallback) then + v.lclGetCallback.MouseUpDownEvent(event, true); end; end else inherited mouseDown(event); end; procedure TCocoaFieldEditor.mouseUp(event: NSEvent); +var + v : NSView; begin - if Assigned(lastEditBox) then + v := GetEditBox(Self); + if Assigned(v) then begin - if Assigned(lastEditBox.lclGetCallback) and not lastEditBox.lclGetCallback.MouseUpDownEvent(event) then + if Assigned(v.lclGetCallback) and not v.lclGetCallback.MouseUpDownEvent(event) then inherited mouseUp(event); end else inherited mouseUp(event); end; procedure TCocoaFieldEditor.rightMouseDown(event: NSEvent); +var + v : NSView; begin - if Assigned(lastEditBox) then + v := GetEditBox(Self); + if Assigned(v) then begin - if Assigned(lastEditBox.lclGetCallback) and not lastEditBox.lclGetCallback.MouseUpDownEvent(event) then + if Assigned(v.lclGetCallback) and not v.lclGetCallback.MouseUpDownEvent(event) then inherited rightMouseDown(event); end else inherited rightMouseDown(event); end; procedure TCocoaFieldEditor.rightMouseUp(event: NSEvent); +var + v : NSView; begin - if Assigned(lastEditBox) then + v := GetEditBox(Self); + if Assigned(v) then begin - if Assigned(lastEditBox.lclGetCallback) and not lastEditBox.lclGetCallback.MouseUpDownEvent(event) then + if Assigned(v.lclGetCallback) and not v.lclGetCallback.MouseUpDownEvent(event) then inherited rightMouseUp(event); end else inherited rightMouseUp(event); end; procedure TCocoaFieldEditor.otherMouseDown(event: NSEvent); +var + v : NSView; begin - if Assigned(lastEditBox) then + v := GetEditBox(Self); + if Assigned(v) then begin - if Assigned(lastEditBox.lclGetCallback) and not lastEditBox.lclGetCallback.MouseUpDownEvent(event) then + if Assigned(v.lclGetCallback) and not v.lclGetCallback.MouseUpDownEvent(event) then inherited otherMouseDown(event); end else inherited otherMouseDown(event); end; procedure TCocoaFieldEditor.otherMouseUp(event: NSEvent); +var + v : NSView; begin - if Assigned(lastEditBox) then + v := GetEditBox(Self); + if Assigned(v) then begin - if Assigned(lastEditBox.lclGetCallback) and not lastEditBox.lclGetCallback.MouseUpDownEvent(event) then + if Assigned(v.lclGetCallback) and not v.lclGetCallback.MouseUpDownEvent(event) then inherited otherMouseUp(event); end else inherited otherMouseUp(event); end; procedure TCocoaFieldEditor.mouseDragged(event: NSEvent); +var + v : NSView; begin - if Assigned(lastEditBox) then + v := GetEditBox(Self); + if Assigned(v) then begin - if Assigned(lastEditBox.lclGetCallback) and not lastEditBox.lclGetCallback.MouseMove(event) then + if Assigned(v.lclGetCallback) and not v.lclGetCallback.MouseMove(event) then inherited mouseDragged(event); end else inherited mouseDragged(event); end; procedure TCocoaFieldEditor.mouseMoved(event: NSEvent); +var + v : NSView; begin - if Assigned(lastEditBox) then + v := GetEditBox(Self); + if Assigned(v) then begin - if Assigned(lastEditBox.lclGetCallback) and not lastEditBox.lclGetCallback.MouseMove(event) then + if Assigned(v.lclGetCallback) and not v.lclGetCallback.MouseMove(event) then inherited mouseMoved(event); end else inherited mouseMoved(event); @@ -630,19 +666,6 @@ begin Result := True; end; -procedure TCocoaTextField.dealloc; -var - lFieldEditor: TCocoaFieldEditor; -begin - lFieldEditor := GetFieldEditor(self); - if (lFieldEditor <> nil) and (lFieldEditor.lastEditBox = Self) then - begin - lFieldEditor.lastEditBox := nil; - end; - - inherited dealloc; -end; - function TCocoaTextField.acceptsFirstResponder: Boolean; begin Result := True; @@ -667,16 +690,9 @@ end; // See http://www.cocoabuilder.com/archive/cocoa/103607-resignfirstresponder-called-immediately.html // See http://stackoverflow.com/questions/3192905/nstextfield-not-noticing-lost-focus-when-pressing-tab function TCocoaTextField.resignFirstResponder: Boolean; -var - lFieldEditor: TCocoaFieldEditor; begin //DebugLn('[TCocoaTextField.resignFirstResponder]'); Result := inherited resignFirstResponder; - lFieldEditor := GetFieldEditor(self); - if (lFieldEditor <> nil) then - begin - lFieldEditor.lastEditBox := Self; - end; end; function TCocoaTextField.lclGetCallback: ICommonCallback; @@ -952,19 +968,6 @@ begin Result := True; end; -procedure TCocoaSecureTextField.dealloc; -var - lFieldEditor: TCocoaFieldEditor; -begin - lFieldEditor := GetFieldEditor(Self); - if (lFieldEditor <> nil) and (lFieldEditor.lastEditBox = Self) then - begin - lFieldEditor.lastEditBox := nil; - end; - - inherited dealloc; -end; - function TCocoaSecureTextField.acceptsFirstResponder: Boolean; begin Result := True; @@ -983,16 +986,9 @@ begin end; function TCocoaSecureTextField.resignFirstResponder: Boolean; -var - lFieldEditor: TCocoaFieldEditor; begin //DebugLn('[TCocoaTextField.resignFirstResponder]'); Result := inherited resignFirstResponder; - lFieldEditor := GetFieldEditor(Self); - if (lFieldEditor <> nil) then - begin - lFieldEditor.lastEditBox := Self; - end; end; procedure TCocoaSecureTextField.resetCursorRects; @@ -1727,15 +1723,7 @@ end; {$ELSE} procedure TCocoaSpinEdit.dealloc; -var - lFieldEditor: TCocoaFieldEditor; begin - lFieldEditor := GetFieldEditor(Self); - if (lFieldEditor <> nil) and (lFieldEditor.lastEditBox = Self) then - begin - lFieldEditor.lastEditBox := nil; - end; - if Stepper <> nil then Stepper.release; if NumberFormatter <> nil then @@ -1884,16 +1872,9 @@ end; // See TCocoaTextField.resignFirstResponder as to why this is done here function TCocoaSpinEdit.resignFirstResponder: Boolean; -var - lFieldEditor: TCocoaFieldEditor; begin //DebugLn('[TCocoaTextField.resignFirstResponder]'); Result := inherited resignFirstResponder; - lFieldEditor := GetFieldEditor(Self); - if (lFieldEditor <> nil) then - begin - lFieldEditor.lastEditBox := Self; - end; end; function TCocoaSpinEdit.lclGetCallback: ICommonCallback; diff --git a/lcl/interfaces/cocoa/cocoawinapi.inc b/lcl/interfaces/cocoa/cocoawinapi.inc index e605109ab8..78e4ada6db 100644 --- a/lcl/interfaces/cocoa/cocoawinapi.inc +++ b/lcl/interfaces/cocoa/cocoawinapi.inc @@ -1956,14 +1956,40 @@ end; function TCocoaWidgetSet.GetFocus: HWND; var - Obj: NSObject; + Obj : NSObject; + win : NSWindow; + rsp : NSResponder; + view : NSView; + dl : NSObject; begin - Result := HWND(NSApp.keyWindow); - if Result <> 0 then + Result := 0; + win := NSApp.keyWindow; + if not Assigned(win) then Exit; + // assuming that that the content view of Window + // is the focused handle and return it, by default + Result := HWND(win.contentView); + + rsp := win.firstResponder; + if not Assigned(rsp) then Exit; + + // todo: The HANDLE is allocated in "WS" side, thus we should be using + // "callback" object to determine, what actual NSView is the handle + + if rsp.isKindOfClass(TCocoaFieldEditor) then begin - Obj := NSWindow(Result).firstResponder; - if Assigned(Obj) and Obj.isKindOfClass(NSView) then - Result := HWND(Obj); + // field editor is a "popup" editor over many controls + // the editor itself is never returned as any kind of HANDLE. + // The handle is the box, that's editing + dl := NSObject(TCocoaFieldEditor(rsp).delegate); + if Assigned(dl) and (dl.isKindOfClass(NSView)) and Assigned(dl.lclGetCallback) then + Result := HWND(dl); + end + else if (rsp.isKindOfClass(NSView)) then + begin + if Assigned(NSView(rsp).enclosingScrollView) then + Result := HWND(NSView(rsp).enclosingScrollView) + else + Result := HWND(rsp); end; end; diff --git a/lcl/interfaces/cocoa/cocoawindows.pas b/lcl/interfaces/cocoa/cocoawindows.pas index 2152632a18..752de3329b 100644 --- a/lcl/interfaces/cocoa/cocoawindows.pas +++ b/lcl/interfaces/cocoa/cocoawindows.pas @@ -636,7 +636,6 @@ begin fieldEditor.setFieldEditor(True); end; Result := fieldEditor; - TCocoaFieldEditor(fieldEditor).lastEditBox := NSTextField(client) end; end;