diff --git a/lcl/interfaces/cocoa/cocoabuttons.pas b/lcl/interfaces/cocoa/cocoabuttons.pas index ddf8fa2063..2001c3b3dc 100644 --- a/lcl/interfaces/cocoa/cocoabuttons.pas +++ b/lcl/interfaces/cocoa/cocoabuttons.pas @@ -69,8 +69,6 @@ type procedure dealloc; override; function initWithFrame(frameRect: NSRect): id; override; function acceptsFirstResponder: Boolean; override; - function becomeFirstResponder: Boolean; override; - function resignFirstResponder: Boolean; override; procedure drawRect(dirtyRect: NSRect); override; function lclGetCallback: ICommonCallback; override; procedure lclClearCallback; override; @@ -236,20 +234,6 @@ begin Result := True; end; -function TCocoaButton.becomeFirstResponder: Boolean; -begin - Result := inherited becomeFirstResponder; - if Assigned(callback) then - callback.BecomeFirstResponder; -end; - -function TCocoaButton.resignFirstResponder: Boolean; -begin - Result := inherited resignFirstResponder; - if Assigned(callback) then - callback.ResignFirstResponder; -end; - procedure TCocoaButton.drawRect(dirtyRect: NSRect); var ctx: NSGraphicsContext; begin diff --git a/lcl/interfaces/cocoa/cocoadatepicker.pas b/lcl/interfaces/cocoa/cocoadatepicker.pas index 46586d1315..46d8de65fb 100755 --- a/lcl/interfaces/cocoa/cocoadatepicker.pas +++ b/lcl/interfaces/cocoa/cocoadatepicker.pas @@ -30,8 +30,6 @@ type procedure mouseMoved(event: NSEvent); override; function acceptsFirstResponder: Boolean; override; - function becomeFirstResponder: Boolean; override; - function resignFirstResponder: Boolean; override; procedure setFrame(aframe: NSRect); override; end; @@ -73,20 +71,6 @@ begin Result := True; end; -function TCocoaDatePicker.becomeFirstResponder: Boolean; -begin - Result := inherited becomeFirstResponder; - if Assigned(callback) then - callback.BecomeFirstResponder; -end; - -function TCocoaDatePicker.resignFirstResponder: Boolean; -begin - Result := inherited resignFirstResponder; - if Assigned(callback) then - callback.ResignFirstResponder; -end; - function TCocoaDatePicker.lclGetCallback: ICommonCallback; begin Result := callback; diff --git a/lcl/interfaces/cocoa/cocoaprivate.pas b/lcl/interfaces/cocoa/cocoaprivate.pas index eac35f78fa..2fffab6609 100644 --- a/lcl/interfaces/cocoa/cocoaprivate.pas +++ b/lcl/interfaces/cocoa/cocoaprivate.pas @@ -186,8 +186,6 @@ type auxMouseByParent: Boolean; procedure dealloc; override; function acceptsFirstResponder: Boolean; override; - function becomeFirstResponder: Boolean; override; - function resignFirstResponder: Boolean; override; procedure drawRect(dirtyRect: NSRect); override; function lclGetCallback: ICommonCallback; override; procedure lclClearCallback; override; @@ -254,8 +252,6 @@ type public callback: ICommonCallback; function acceptsFirstResponder: Boolean; override; - function becomeFirstResponder: Boolean; override; - function resignFirstResponder: Boolean; override; function lclGetCallback: ICommonCallback; override; procedure lclClearCallback; override; procedure resetCursorRects; override; @@ -275,8 +271,6 @@ type TCocoaProgressIndicator = objcclass(NSProgressIndicator) callback: ICommonCallback; function acceptsFirstResponder: Boolean; override; - function becomeFirstResponder: Boolean; override; - function resignFirstResponder: Boolean; override; function lclGetCallback: ICommonCallback; override; procedure lclClearCallback; override; procedure resetCursorRects; override; @@ -318,8 +312,6 @@ type procedure drawRect(dirtyRect: NSRect); override; function acceptsFirstResponder: Boolean; override; - function becomeFirstResponder: Boolean; override; - function resignFirstResponder: Boolean; override; function lclGetCallback: ICommonCallback; override; procedure lclClearCallback; override; procedure resetCursorRects; override; @@ -368,10 +360,19 @@ var // todo: this should be a threadvar TrackedControl : NSObject = nil; +function isCallbackForSameObject(cb1, cb2: ICommonCallback): Boolean; + implementation uses CocoaInt; +function isCallbackForSameObject(cb1, cb2: ICommonCallback): Boolean; +begin + Result := Assigned(cb1) and Assigned(cb2); + if Result then + Result := (cb1 = cb2) or (cb1.GetTarget = cb2.GetTarget); +end; + {$I mackeycodes.inc} procedure SetViewDefaults(AView: NSView); @@ -453,20 +454,6 @@ begin Result := True; end; -function TCocoaGroupBox.becomeFirstResponder: Boolean; -begin - Result := inherited becomeFirstResponder; - if Assigned(callback) then - callback.BecomeFirstResponder; -end; - -function TCocoaGroupBox.resignFirstResponder: Boolean; -begin - Result := inherited resignFirstResponder; - if Assigned(callback) then - callback.ResignFirstResponder; -end; - function TCocoaGroupBox.lclGetCallback: ICommonCallback; begin Result := callback; @@ -523,20 +510,6 @@ begin Result := True; end; -function TCocoaCustomControl.becomeFirstResponder: Boolean; -begin - Result := inherited becomeFirstResponder; - if Assigned(callback) then - callback.BecomeFirstResponder; -end; - -function TCocoaCustomControl.resignFirstResponder: Boolean; -begin - Result := inherited resignFirstResponder; - if Assigned(callback) then - callback.ResignFirstResponder; -end; - function TCocoaCustomControl.acceptsFirstMouse(event: NSEvent): Boolean; begin // By default, a mouse-down event in a window that isn’t the key window @@ -1178,18 +1151,6 @@ begin Result:=True; end; -function TCocoaProgressIndicator.becomeFirstResponder: Boolean; -begin - Result := inherited becomeFirstResponder; - callback.BecomeFirstResponder; -end; - -function TCocoaProgressIndicator.resignFirstResponder: Boolean; -begin - Result := inherited resignFirstResponder; - callback.ResignFirstResponder; -end; - function TCocoaProgressIndicator.lclGetCallback: ICommonCallback; begin Result:=callback; @@ -1361,18 +1322,6 @@ begin Result := True; end; -function TCocoaSlider.becomeFirstResponder: Boolean; -begin - Result := inherited becomeFirstResponder; - callback.BecomeFirstResponder; -end; - -function TCocoaSlider.resignFirstResponder: Boolean; -begin - Result := inherited resignFirstResponder; - callback.ResignFirstResponder; -end; - function TCocoaSlider.lclGetCallback: ICommonCallback; begin Result:=callback; diff --git a/lcl/interfaces/cocoa/cocoascrollers.pas b/lcl/interfaces/cocoa/cocoascrollers.pas index a85489d747..2da1e059f2 100644 --- a/lcl/interfaces/cocoa/cocoascrollers.pas +++ b/lcl/interfaces/cocoa/cocoascrollers.pas @@ -44,8 +44,6 @@ type procedure dealloc; override; procedure setFrame(aframe: NSRect); override; function acceptsFirstResponder: Boolean; override; - function becomeFirstResponder: Boolean; override; - function resignFirstResponder: Boolean; override; function lclGetCallback: ICommonCallback; override; procedure lclClearCallback; override; procedure resetCursorRects; override; @@ -114,8 +112,6 @@ type procedure actionScrolling(sender: NSObject); message 'actionScrolling:'; function IsHorizontal: Boolean; message 'IsHorizontal'; function acceptsFirstResponder: Boolean; override; - function becomeFirstResponder: Boolean; override; - function resignFirstResponder: Boolean; override; function lclGetCallback: ICommonCallback; override; procedure lclClearCallback; override; procedure resetCursorRects; override; @@ -746,20 +742,6 @@ begin Result := True; end; -function TCocoaScrollView.becomeFirstResponder: Boolean; -begin - Result := inherited becomeFirstResponder; - if Assigned(callback) then - callback.BecomeFirstResponder; -end; - -function TCocoaScrollView.resignFirstResponder: Boolean; -begin - Result := inherited resignFirstResponder; - if Assigned(callback) then - callback.ResignFirstResponder; -end; - function TCocoaScrollView.lclGetCallback: ICommonCallback; begin Result := callback; @@ -946,20 +928,6 @@ begin Result := True; end; -function TCocoaScrollBar.becomeFirstResponder: Boolean; -begin - Result := inherited becomeFirstResponder; - if Assigned(callback) then - callback.BecomeFirstResponder; -end; - -function TCocoaScrollBar.resignFirstResponder: Boolean; -begin - Result := inherited resignFirstResponder; - if Assigned(callback) then - callback.ResignFirstResponder; -end; - function TCocoaScrollBar.lclGetCallback: ICommonCallback; begin Result := callback; diff --git a/lcl/interfaces/cocoa/cocoatabcontrols.pas b/lcl/interfaces/cocoa/cocoatabcontrols.pas index 5366cfcf7e..07ba977d3c 100644 --- a/lcl/interfaces/cocoa/cocoatabcontrols.pas +++ b/lcl/interfaces/cocoa/cocoatabcontrols.pas @@ -479,22 +479,27 @@ procedure TCocoaTabControl.tabView_willSelectTabViewItem(tabView: NSTabView; tabViewItem: NSTabViewItem); begin if Assigned(callback) then + begin callback.willSelectTabViewItem( IndexOfTab( self, tabViewItem) ); + + // This must be called, prior to notification about focus (firstResponder) change + // Focus changing goes as following: + // First page becomes visible + // Then focus is switching to the control of the page + // In Cocoa world, first "willSelect" runs, then "firstResponder" changes, then "didSelect" is fired + callback.didSelectTabViewItem( IndexOfTab( self, tabViewItem) ); + end; end; procedure TCocoaTabControl.tabView_didSelectTabViewItem(tabView: NSTabView; tabViewItem: NSTabViewItem); -//var - //i: Integer; - //lTabView, lCurSubview: NSView; - //lLCLControl: TWinControl; - //lBounds: TRect; - //lCurCallback: ICommonCallback; begin - if Assigned(callback) then - begin - callback.didSelectTabViewItem( IndexOfTab( self, tabViewItem) ); - end; + //it's called together with "willSelect" + + //if Assigned(callback) then + //begin + //callback.didSelectTabViewItem( IndexOfTab( self, tabViewItem) ); + //end; // The recent clean up, drove the workaround below unnecessary // (at least the problem is not observed) diff --git a/lcl/interfaces/cocoa/cocoatables.pas b/lcl/interfaces/cocoa/cocoatables.pas index d9b5fb4bd3..ced168d5da 100644 --- a/lcl/interfaces/cocoa/cocoatables.pas +++ b/lcl/interfaces/cocoa/cocoatables.pas @@ -77,8 +77,6 @@ type smallimages : NSMutableDictionary; function acceptsFirstResponder: Boolean; override; - function becomeFirstResponder: Boolean; override; - function resignFirstResponder: Boolean; override; function lclGetCallback: ICommonCallback; override; procedure lclClearCallback; override; @@ -420,18 +418,6 @@ begin Result := True; end; -function TCocoaTableListView.becomeFirstResponder: Boolean; -begin - Result := inherited becomeFirstResponder; - callback.BecomeFirstResponder; -end; - -function TCocoaTableListView.resignFirstResponder: Boolean; -begin - Result := inherited resignFirstResponder; - callback.ResignFirstResponder; -end; - function TCocoaTableListView.lclGetCallback: ICommonCallback; begin Result := callback; diff --git a/lcl/interfaces/cocoa/cocoatextedits.pas b/lcl/interfaces/cocoa/cocoatextedits.pas index 8376047e74..07950f48d1 100644 --- a/lcl/interfaces/cocoa/cocoatextedits.pas +++ b/lcl/interfaces/cocoa/cocoatextedits.pas @@ -59,9 +59,6 @@ type TCocoaTextField = objcclass(NSTextField) callback: ICommonCallback; function acceptsFirstResponder: Boolean; override; - function becomeFirstResponder: Boolean; override; - function RealResignFirstResponder: Boolean; message 'RealResignFirstResponder'; - function resignFirstResponder: Boolean; override; function lclGetCallback: ICommonCallback; override; procedure lclClearCallback; override; procedure resetCursorRects; override; @@ -86,9 +83,6 @@ type public callback: ICommonCallback; function acceptsFirstResponder: Boolean; override; - function becomeFirstResponder: Boolean; override; - function RealResignFirstResponder: Boolean; message 'RealResignFirstResponder'; - function resignFirstResponder: Boolean; override; procedure resetCursorRects; override; // key //procedure keyDown(event: NSEvent); override; -> keyDown doesn't work in NSTextField @@ -115,8 +109,6 @@ type supressTextChangeEvent: Integer; // if above zero, then don't send text change event function acceptsFirstResponder: Boolean; override; - function becomeFirstResponder: Boolean; override; - function resignFirstResponder: Boolean; override; function lclGetCallback: ICommonCallback; override; procedure lclClearCallback; override; procedure resetCursorRects; override; @@ -150,7 +142,7 @@ type TCocoaFieldEditor = objcclass(NSTextView) public - function resignFirstResponder: Boolean; override; + function lclGetCallback: ICommonCallback; override; // keyboard procedure keyDown(event: NSEvent); override; // mouse @@ -228,8 +220,6 @@ type list: TCocoaComboBoxList; resultNS: NSString; //use to return values to combo function acceptsFirstResponder: Boolean; override; - function becomeFirstResponder: Boolean; override; - function resignFirstResponder: Boolean; override; procedure textDidChange(notification: NSNotification); override; procedure textDidEndEditing(notification: NSNotification); override; // NSComboBoxDataSourceProtocol @@ -287,8 +277,6 @@ type isOwnerDrawn: Boolean; isOwnerMeasure: Boolean; function acceptsFirstResponder: Boolean; override; - function becomeFirstResponder: Boolean; override; - function resignFirstResponder: Boolean; override; procedure dealloc; override; function lclGetCallback: ICommonCallback; override; procedure lclClearCallback; override; @@ -327,8 +315,6 @@ type procedure StepperChanged(sender: NSObject); message 'StepperChanged:'; // lcl function acceptsFirstResponder: Boolean; override; - function becomeFirstResponder: Boolean; override; - function resignFirstResponder: Boolean; override; function lclGetCallback: ICommonCallback; override; procedure lclClearCallback; override; // NSViewFix @@ -352,9 +338,6 @@ type procedure controlTextDidChange(obj: NSNotification); override; // lcl function acceptsFirstResponder: Boolean; override; - function becomeFirstResponder: Boolean; override; - function RealResignFirstResponder: Boolean; message 'RealResignFirstResponder'; - function resignFirstResponder: Boolean; override; function lclGetCallback: ICommonCallback; override; procedure lclClearCallback; override; procedure resetCursorRects; override; @@ -493,24 +476,10 @@ begin Result := NSView(v); end; -function TCocoaFieldEditor.resignFirstResponder: Boolean; -var - v : NSObject; +function TCocoaFieldEditor.lclGetCallback: ICommonCallback; begin - v := GetEditBox(Self); - //DebugLn('[TCocoaFieldEditor.resignFirstResponder]'); - if (v <> nil) then - begin - if v.isKindOfClass_(TCocoaTextField) then - begin - TCocoaTextField(v).RealResignFirstResponder(); - end - else if v.isKindOfClass_(TCocoaSecureTextField) then - begin - TCocoaSecureTextField(v).RealResignFirstResponder(); - end; - end; - Result := inherited resignFirstResponder; + if Assigned(delegate) then Result := NSObject(delegate).lclGetCallback + else Result := nil; end; procedure TCocoaFieldEditor.keyDown(event: NSEvent); @@ -655,30 +624,6 @@ begin Result := True; end; -function TCocoaTextField.becomeFirstResponder: Boolean; -begin - Result := inherited becomeFirstResponder; - callback.BecomeFirstResponder; -end; - -function TCocoaTextField.RealResignFirstResponder: Boolean; -begin - callback.ResignFirstResponder; - Result := True; -end; - -// Do not propagate this event to the LCL, -// because Cocoa NSTextField loses focus as soon as it receives it -// and the shared editor gets focus instead. -// see NSWindow.fieldEditor:forObject: -// 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; -begin - //DebugLn('[TCocoaTextField.resignFirstResponder]'); - Result := inherited resignFirstResponder; -end; - function TCocoaTextField.lclGetCallback: ICommonCallback; begin Result := callback; @@ -821,18 +766,6 @@ begin Result := True; end; -function TCocoaTextView.becomeFirstResponder: Boolean; -begin - Result := inherited becomeFirstResponder; - callback.BecomeFirstResponder; -end; - -function TCocoaTextView.resignFirstResponder: Boolean; -begin - Result := inherited resignFirstResponder; - callback.ResignFirstResponder; -end; - function TCocoaTextView.lclGetCallback: ICommonCallback; begin Result := callback; @@ -943,24 +876,6 @@ begin Result := True; end; -function TCocoaSecureTextField.becomeFirstResponder: Boolean; -begin - Result := inherited becomeFirstResponder; - callback.BecomeFirstResponder; -end; - -function TCocoaSecureTextField.RealResignFirstResponder: Boolean; -begin - callback.ResignFirstResponder; - Result := True; -end; - -function TCocoaSecureTextField.resignFirstResponder: Boolean; -begin - //DebugLn('[TCocoaTextField.resignFirstResponder]'); - Result := inherited resignFirstResponder; -end; - procedure TCocoaSecureTextField.resetCursorRects; begin if not callback.resetCursorRects then @@ -1144,18 +1059,6 @@ begin Result := True; end; -function TCocoaComboBox.becomeFirstResponder: Boolean; -begin - Result := inherited becomeFirstResponder; - callback.BecomeFirstResponder; -end; - -function TCocoaComboBox.resignFirstResponder: Boolean; -begin - Result := inherited resignFirstResponder; - callback.ResignFirstResponder; -end; - procedure TCocoaComboBox.textDidChange(notification: NSNotification); var TheEvent: NSEvent; @@ -1352,18 +1255,6 @@ begin Result := True; end; -function TCocoaReadOnlyComboBox.becomeFirstResponder: Boolean; -begin - Result := inherited becomeFirstResponder; - callback.BecomeFirstResponder; -end; - -function TCocoaReadOnlyComboBox.resignFirstResponder: Boolean; -begin - Result := inherited resignFirstResponder; - callback.ResignFirstResponder; -end; - procedure TCocoaReadOnlyComboBox.dealloc; begin if Assigned(list) then @@ -1649,20 +1540,6 @@ begin Result := True; end; -function TCocoaSpinEdit.becomeFirstResponder: Boolean; -begin - Result := Edit.becomeFirstResponder; - if Assigned(callback) then - callback.BecomeFirstResponder; -end; - -function TCocoaSpinEdit.resignFirstResponder: Boolean; -begin - Result := inherited resignFirstResponder; - if Assigned(callback) then - callback.ResignFirstResponder; -end; - function TCocoaSpinEdit.lclGetCallback: ICommonCallback; begin Result := callback; @@ -1822,25 +1699,6 @@ begin Result := True; end; -function TCocoaSpinEdit.becomeFirstResponder: Boolean; -begin - Result := inherited becomeFirstResponder; - callback.BecomeFirstResponder; -end; - -function TCocoaSpinEdit.RealResignFirstResponder: Boolean; -begin - callback.ResignFirstResponder; - Result := True; -end; - -// See TCocoaTextField.resignFirstResponder as to why this is done here -function TCocoaSpinEdit.resignFirstResponder: Boolean; -begin - //DebugLn('[TCocoaTextField.resignFirstResponder]'); - Result := inherited resignFirstResponder; -end; - function TCocoaSpinEdit.lclGetCallback: ICommonCallback; begin Result := callback; diff --git a/lcl/interfaces/cocoa/cocoawindows.pas b/lcl/interfaces/cocoa/cocoawindows.pas index 9c73e93182..29aa3c3af1 100644 --- a/lcl/interfaces/cocoa/cocoawindows.pas +++ b/lcl/interfaces/cocoa/cocoawindows.pas @@ -121,6 +121,10 @@ type isInFullScreen: Boolean; orderOutAfterFS : Boolean; fsview: TCocoaWindowContent; + + responderSwitch: Integer; + respInitCb : ICommonCallback; + function windowShouldClose(sender : id): LongBool; message 'windowShouldClose:'; procedure windowWillClose(notification: NSNotification); message 'windowWillClose:'; function windowWillReturnFieldEditor_toObject(sender: NSWindow; client: id): id; message 'windowWillReturnFieldEditor:toObject:'; @@ -160,6 +164,8 @@ type // NSDraggingDestinationCategory function draggingEntered(sender: NSDraggingInfoProtocol): NSDragOperation; override; function performDragOperation(sender: NSDraggingInfoProtocol): Boolean; override; + // windows + function makeFirstResponder(r: NSResponder): Boolean; override; // menu support procedure lclItemSelected(sender: id); message 'lclItemSelected:'; @@ -204,6 +210,7 @@ type procedure didAddSubview(aview: NSView); override; end; + implementation { TCocoaDesignOverlay } @@ -917,6 +924,33 @@ begin Result := True; end; +function TCocoaWindow.makeFirstResponder(r: NSResponder): Boolean; +var + cbnew: ICommonCallback; +begin + if (responderSwitch = 0) then + respInitCb := firstResponder.lclGetCallback; + + // makeFirstResponder calls can be recursive! + // the resulting NSResponder can be the same object (i.e. fieldEditor) + // yet, the callback should be the different anyway + + inc(responderSwitch); + Result:=inherited makeFirstResponder(r); + dec(responderSwitch); + + if (responderSwitch = 0) then + begin + cbnew := firstResponder.lclGetCallback; + + if not isCallbackForSameObject(respInitCb, cbnew) then + begin + if Assigned(respInitCb) then respInitCb.ResignFirstResponder; + if Assigned(cbnew) then cbnew.BecomeFirstResponder; + end; + end; +end; + procedure TCocoaWindow.lclItemSelected(sender: id); begin