View Issue Details

IDProjectCategoryView StatusLast Update
0036760LazarusWidgetsetpublic2020-03-06 04:01
ReporterZoë Peterson Assigned ToDmitry Boyarintsev  
PrioritynormalSeverityminorReproducibilityalways
Status resolvedResolutionfixed 
Summary0036760: Make Cocoa ShowMessage close with [Esc] without beeping
DescriptionThis patch is an alternate fix for the changes in r59885. It prevents a beep when using [Esc] to close ShowMessage/MessageDlg dialogs, and adds support for closing MessageBox() sheets with [Esc], which the previous fix didn't handle.
Steps To ReproduceThe attached project has buttons for launching the various dialog box styles. Clicking any of the ShowMessage/MessageDlg/MessageBox buttons will call the respective functions. With the current implementation:

- ShowMessage & MessageDlg close with [Esc] but beep when doing so.
- MessageBox just beeps for [Esc] and stays open
- "MessageDlg w/ Cancel" and "MessageBox w/ Cancel" close with [Esc] and do not beep, since the system clicks their Cancel button.

With the new patch, all of the ShowMessage/MessageBox/MessageDlg buttons with or without cancel, close on [Esc] without beeping.
TagsNo tags attached.
Fixed in Revision62697
LazTarget-
WidgetsetCocoa
Attached Files

Activities

Zoë Peterson

2020-03-05 20:57

reporter  

CocoaEscForAlerts.zip (115,527 bytes)
CocoaEscForAlerts.patch (3,965 bytes)   
diff --git a/lcl/interfaces/cocoa/cocoalclintf.inc b/lcl/interfaces/cocoa/cocoalclintf.inc
index cc4ccb2f6f..db3980de6a 100644
--- a/lcl/interfaces/cocoa/cocoalclintf.inc
+++ b/lcl/interfaces/cocoa/cocoalclintf.inc
@@ -154,10 +154,11 @@ end;
 
 type
 
-  { TCocoaAlertController }
+  { TCocoaAlertCancelAccessoryView }
 
-  TCocoaAlertController = objcclass(NSWindowController)
-    procedure keyUp(theEvent: NSEvent); override;
+  TCocoaAlertCancelAccessoryView = objcclass(NSView)
+    sheetOfWindow: NSWindow;
+    function performKeyEquivalent (theEvent: NSEvent): LCLObjCBoolean; override;
   end;
 
   TCocoaSheetDelegate = objcclass(NSObject)
@@ -236,7 +237,8 @@ var
   I: Integer;
   aButton: NSButton;
   Str: string;
-  ctrl : TCocoaAlertController;
+  cancelAccessory: TCocoaAlertCancelAccessoryView;
+  needsCancel: Boolean;
 begin
   {Str := 'TCocoaWidgetSet.PromptUser DialogCaption: ' + DialogCaption +
     ' DialogMessage: ' + DialogMessage + ' DialogType: ' + DbgS(DialogType) +
@@ -252,6 +254,7 @@ begin
   Result := -1;
   AnAlert := NSAlert.alloc.init;
   try
+    cancelAccessory := nil;
     informativeText := NSStringUtf8(DialogMessage);
     messageText := NSStringUtf8(DialogCaption);
     case DialogType of
@@ -264,6 +267,7 @@ begin
       anAlert.setInformativeText(informativeText);
       anAlert.setMessageText(messageText);
 
+      needsCancel := True;
       for I := 0 to ButtonCount - 1 do
       begin
         if Buttons[I] = idButtonHelp then
@@ -292,13 +296,22 @@ begin
             // from the first button.
             aButton.setKeyEquivalent(NSSTR(''));
 
-          if Buttons[I]=mrCancel then
+          if Buttons[I]=mrCancel then begin
+            needsCancel := False;
             aButton.setKeyEquivalent(NSSTR(#27));
+          end;
 
           aButton.setTag(Buttons[I]);
         end;
       end;
 
+      if needsCancel then begin
+        cancelAccessory := TCocoaAlertCancelAccessoryView.alloc.init;
+        cancelAccessory.sheetOfWindow := sheetOfWindow;
+        cancelAccessory.setBounds(NSZeroRect);
+        anAlert.setAccessoryView(cancelAccessory);
+      end;
+
       ApplicationWillShowModal;
 
       if Assigned(sheetOfWindow) then
@@ -315,18 +328,14 @@ begin
       end
       else
       begin
-        ctrl := TCocoaAlertController(TCocoaAlertController.alloc).initWithWindow(AnAlert.window);
-        try
-          ToggleAppMenu(false);
-          Result := AnAlert.runModal;
-          if Result = NSCancelButton then
-            Result := EscapeResult;
-          ToggleAppMenu(true); // modal menu doesn't have a window, disabling it
-        finally
-          ctrl.release;
-        end;
+        ToggleAppMenu(false);
+        Result := AnAlert.runModal;
+        if Result = NSCancelButton then
+          Result := EscapeResult;
+        ToggleAppMenu(true); // modal menu doesn't have a window, disabling it
       end;
     finally
+      if Assigned(cancelAccessory) then cancelAccessory.release;
       informativeText.release;
       messageText.release;
     end;
@@ -342,15 +351,20 @@ end;
 
 {TCocoaWidgetSet.PromptUser}
 
-{ TCocoaAlertController }
+{ TCocoaAlertCancelAccessoryView }
 
-procedure TCocoaAlertController.keyUp(theEvent: NSEvent);
-const
-  NSModalResponseCancel = NSCancelButton; // NSCancelButton is deprecated
+function TCocoaAlertCancelAccessoryView.performKeyEquivalent(theEvent: NSEvent): LCLObjCBoolean;
 begin
-  inherited keyUp(theEvent);
   if theEvent.keyCode = kVK_Escape then
-    NSApplication(NSApp).stopModalWithCode(NSModalResponseCancel);
+  begin
+    if Assigned(sheetOfWindow) then
+      NSApplication(NSApp).endSheet(window) // use "sheetOfWindow.endSheet(window)" on 10.9+
+    else
+      NSApplication(NSApp).stopModalWithCode(NSCancelButton);
+    Result := True;
+  end
+  else
+    Result := inherited performKeyEquivalent(theEvent);
 end;
 
 {------------------------------------------------------------------------------
CocoaEscForAlerts.patch (3,965 bytes)   

Zoë Peterson

2020-03-05 20:58

reporter   ~0121401

The sample project has "Random Color", "Show Modal" and "Form.KeyPress" controls which can be ignored. They were used for testing but don't demonstrate anything relevant.

CudaText man

2020-03-05 21:05

reporter   ~0121402

Good, keep up the good work.

Dmitry Boyarintsev

2020-03-06 04:01

developer   ~0121407

thanks for the patch, applied!
please test and close if ok

Issue History

Date Modified Username Field Change
2020-03-05 20:57 Zoë Peterson New Issue
2020-03-05 20:57 Zoë Peterson File Added: CocoaEscForAlerts.zip
2020-03-05 20:57 Zoë Peterson File Added: CocoaEscForAlerts.patch
2020-03-05 20:58 Zoë Peterson Note Added: 0121401
2020-03-05 21:05 CudaText man Note Added: 0121402
2020-03-06 04:01 Dmitry Boyarintsev Assigned To => Dmitry Boyarintsev
2020-03-06 04:01 Dmitry Boyarintsev Status new => resolved
2020-03-06 04:01 Dmitry Boyarintsev Resolution open => fixed
2020-03-06 04:01 Dmitry Boyarintsev Fixed in Revision => 62697
2020-03-06 04:01 Dmitry Boyarintsev LazTarget => -
2020-03-06 04:01 Dmitry Boyarintsev Widgetset Cocoa => Cocoa
2020-03-06 04:01 Dmitry Boyarintsev Note Added: 0121407