diff --git a/lcl/interfaces/cocoa/cocoatextedits.pas b/lcl/interfaces/cocoa/cocoatextedits.pas index 199da11198..e081a1f3d2 100644 --- a/lcl/interfaces/cocoa/cocoatextedits.pas +++ b/lcl/interfaces/cocoa/cocoatextedits.pas @@ -141,7 +141,12 @@ type TCocoaFieldEditor = objcclass(NSTextView) public + // This flag is used to hack an infinite loop + // when switching "editable" (readonly) mode of NSTextField + // see TCocoaWSCustomEdit.SetReadOnly + goingReadOnly: Boolean; function lclGetCallback: ICommonCallback; override; + function becomeFirstResponder: Boolean; override; // mouse procedure keyDown(event: NSEvent); override; procedure mouseDown(event: NSEvent); override; @@ -593,6 +598,12 @@ begin else Result := nil; end; +function TCocoaFieldEditor.becomeFirstResponder: Boolean; +begin + if goingReadOnly then Result := false + else Result:=inherited becomeFirstResponder; +end; + procedure TCocoaFieldEditor.keyDown(event: NSEvent); begin if event.keyCode = kVK_Return then diff --git a/lcl/interfaces/cocoa/cocoawsstdctrls.pas b/lcl/interfaces/cocoa/cocoawsstdctrls.pas index 48145ac54b..769776f4e5 100644 --- a/lcl/interfaces/cocoa/cocoawsstdctrls.pas +++ b/lcl/interfaces/cocoa/cocoawsstdctrls.pas @@ -977,8 +977,54 @@ end; class procedure TCocoaWSCustomEdit.SetReadOnly(const ACustomEdit: TCustomEdit; NewReadOnly: boolean); +var + lHandle: TCocoaTextField; + w : NSWindow; + t : NSText; + isFocused: Boolean; + r : Boolean; + b : Boolean; + rsp : NSResponder; + ed : TCocoaFieldEditor; begin -// NSTextField(ACustomEdit.Handle).setEditable(not NewReadOnly); + lHandle := GetTextField(ACustomEdit); + if not Assigned(lHandle) then Exit; + + ed := nil; //if lHandle is "focused" then ed would be <> nil + w := lHandle.window; + if not Assigned(w) then t := nil + else begin + rsp := w.firstResponder; + if (Assigned(rsp)) and (rsp.isKindOfClass(TCocoaFieldEditor)) then + begin + ed := TCocoaFieldEditor(rsp); + if (NSObject(ed.delegate) = lHandle) then + begin + ed.retain; + // the hack is needed to prevent infinite loop + // on switching editable (ReadOnly) status. + // without prevention of Editor focusing, AppKit goes into an infinite loop: + // AppKit`-[_NSKeyboardFocusClipView removeFromSuperview] + 55 + // AppKit`-[NSWindow endEditingFor:] + 429 + // AppKit`-[NSView removeFromSuperview] + 78 + // AppKit`-[_NSKeyboardFocusClipView removeFromSuperview] + 55 + // AppKit`-[NSWindow endEditingFor:] + 429 + // AppKit`-[NSView removeFromSuperview] + 78 + // AppKit`-[_NSKeyboardFocusClipView removeFromSuperview] + 55 + ed.goingReadOnly := true; + end + else + ed := nil; // someone else is focused + end; + end; + + lHandle.setEditable_(ObjCBool(not NewReadOnly)); + lHandle.setSelectable_(1); // allow to select read-only text (LCL compatible) + + if Assigned(ed) then begin + ed.goingReadOnly := false; + ed.release; + end; end; class procedure TCocoaWSCustomEdit.SetSelStart(const ACustomEdit: TCustomEdit; NewStart: integer);