Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Follow OS behavior for out of focus modal dialogs #17220

Open
wants to merge 1 commit into
base: development
Choose a base branch
from

Conversation

yuzawa-san
Copy link
Contributor

@yuzawa-san yuzawa-san commented Aug 13, 2023

Description

  • I often have some linter hooks run on push over the course of 5-10 seconds. Sometimes I look at my email or another application, but the error dialog is opened very quietly since it is not a system error dialog. Both success and failure are quiet, but failure (and any other dialog) really should be more notable.
  • I added a system beep for auditory notification. There is already a comment referring to the need to do this
    * dialogs special treatment, such as playing a system alert sound."
  • I added a "dock bounce" in macOS. This only happens when the application is not in focus. This needs to IPC to the main.
  • I fire both off in the componentDidMount method of the dialog since the dialog type (informational,warning,error) is there. I would have preferred to do it further up in the dispatch, but this seemed like a reasonable place to do it since it would work on all dialogs. The dock bounce being "critical" (bouncing until the app comes back into focus) is a function of whether the dialog type is error. Warning dialogs will beep but only bounce once. Information dialogs won't beep or bounce. The beep and bounce will occur for any modal dialog opened out of view in order to match the macOS system dialog behavior.

Screenshots

Here is a video of me starting in the application, then triggering a push which has a push hook that takes several seconds and will fail. Then I change focus to another application. Then the hook fails, there is a beep (i could not record audio) and the dock bounce which continues until I focus on the application again.

dialog-beep-bounce.mp4

Release notes

Notes: Beep and bounce dock for out of focus modal dialogs

@yuzawa-san yuzawa-san force-pushed the dialog-beeps branch 2 times, most recently from bd42300 to 1ce3e4b Compare August 14, 2023 19:37
farahmandakbar26

This comment was marked as off-topic.

@niik
Copy link
Member

niik commented Aug 30, 2023

👋 @yuzawa-san Thanks for wanting to contribute! This seems like a pattern worth investigating. Could you see if you can dig up some references regarding when to use dock bounce from official Apple documentation so that we can make sure we're following official platform guidance?

Also, is there a similar pattern we should be using on Windows for consistency? Something like flashFrame perhaps? Again, could you see if you could find something about this in official Microsoft docs?

I added a system beep for auditory notification.

I haven't tried this myself but this appears to happen even when the Windows is in focus, is that right? Is that the intended behavior? It seems like it could be perceived as annoying, is there any documentation or guidance you can refer to here?

@farahmandakbar26

This comment was marked as spam.

@yuzawa-san
Copy link
Contributor Author

@niik Thanks for the comment. I was able to dig up this piece in the macOS docs for requestUserAttention:

If the inactive app presents a modal panel, this method will be invoked with NSCriticalRequest automatically. The modal panel is not brought to the front for an inactive app.

I was also able to run this AppleScript in the mac Script Editor (similar to electron's dialog.showMessageBox):

delay 5
display alert "hello" as informational
delay 5
display alert "hello" as warning
delay 5
display alert "hello" as critical

to validate the system's alert functionality.

So you are correct, there is (at least in Ventura) no beep when the application is focus. All cause the dock to bounce at critical level as the docs indicate, so I'll fix that up real soon to match the system dialog behavior.

Ideally, I would use flashFrame on mac as well, but that uses the non-critical level https://github.com/electron/electron/blob/0b0707145b157343c42266d2586ed9413a1d54f5/shell/browser/native_window_mac.mm#L1004C57-L1004C79

I may open a bug with electron since that would mean the Windows behavior does not match the Mac behavior (flashing until you stop vs just flashing once).

@yuzawa-san yuzawa-san changed the title Beep and bounce dock on error/warning dialogs Beep and bounce dock for out of focus modal dialogs Sep 1, 2023
@yuzawa-san
Copy link
Contributor Author

@niik is there anything else in particular that you are looking for in order to consider this PR?

@sergiou87
Copy link
Member

Hey @yuzawa-san , thank you for your work 💖 @niik is on leave but there was this outstanding question:

could you see if you could find something about this in official Microsoft docs?

Then, about this other thing you mentioned…

Ideally, I would use flashFrame on mac as well, but that uses the non-critical level https://github.com/electron/electron/blob/0b0707145b157343c42266d2586ed9413a1d54f5/shell/browser/native_window_mac.mm#L1004C57-L1004C79

I may open a bug with electron since that would mean the Windows behavior does not match the Mac behavior (flashing until you stop vs just flashing once).

That would be nice if you haven't done it already, but there seems to be a reasonable case for informationalRequest (that doesn't apply to us since as you said macOS apps get critical requests when an alert is displayed and the app is not focused). So maybe a new API like setFlashingWindow(true, 'critical') makes more sense, and then deprecate the existing one.

@yuzawa-san
Copy link
Contributor Author

@sergiou87 I was able to find this for windows https://learn.microsoft.com/en-us/windows/win32/uxguide/winenv-taskbar#taskbar-button-flashing and https://learn.microsoft.com/en-us/windows/win32/uxguide/mess-warn however its for windows 7, they seem to have newer docs but they are not as in depth as the older ones (which they say are still generally correct in the disclaimer at the tops of the old pages).

Here are the salient pieces:

If an inactive program requires immediate attention, flash its taskbar button to draw attention and leave it highlighted. Don't do anything else: don't restore or activate the window and don't play any sound effects. Instead, respect the user's window state selection and let the user activate the window when ready.

They also repeat "no sound" in the dialog docs:

Don't accompany warnings with a sound effect or beep. Doing so is jarring and unnecessary.
Exception: If the user must respond immediately, you can use a sound effect.

Given Windows seems very anti-sound, I have updated this PR to only beep on macOS (where that is the modal dialog behavior).

I created this PR in electron electron/electron#41391 so we'll see where that goes. Ideally, the code can be a little bit simpler if that gets merged.

Copy link
Member

@sergiou87 sergiou87 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you! That is very interesting, I haven't tested it yet but it looks like the app behavior will match those guidelines. For now, I will leave you with a few change suggestions 😄

@@ -155,6 +155,9 @@ export const getCurrentWindowZoomFactor = invokeProxy(
0
)

/** Tell the main process to that a modal dialog has opened */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/** Tell the main process to that a modal dialog has opened */
/** Tell the main process that a modal dialog has opened */

@@ -155,6 +155,9 @@ export const getCurrentWindowZoomFactor = invokeProxy(
0
)

/** Tell the main process to that a modal dialog has opened */
export const dialogOpened = sendProxy('dialog-opened', 0)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Following the convention from other event-related stuff, I think the function name should be sendDialogDidOpen and the event dialog-did-open:

Suggested change
export const dialogOpened = sendProxy('dialog-opened', 0)
export const sendDialogDidOpen = sendProxy('dialog-did-open', 0)

Comment on lines 334 to 338
if (__DARWIN__) {
shell.beep()
// This is used instead of flashFrame in order to match the OS dialog behavior.
app.dock.bounce('critical')
} else {
this.window.once('focus', () => this.window.flashFrame(false))
this.window.flashFrame(true)
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add a comment explaining this stuff? Basically, why beeping on macOS and using bounce('critical') vs flashFrame on Windows (feel free to link any of the UX docs you provided in this PR if needed)

@yuzawa-san yuzawa-san changed the title Beep and bounce dock for out of focus modal dialogs Follow OS behavior for out of focus modal dialogs Feb 27, 2024
@yuzawa-san
Copy link
Contributor Author

@sergiou87 I have updated the PR with your requested changes. I have also renamed the PR title as well to better reflect what we're trying to accomplish here.

When the application window is not in focus, but a modal dialog is opened, we can play the system beep then bounce the dock (mac) or flash the frame (windows, etc) in order to indicate to the user that something is seeking their attention.
@yuzawa-san
Copy link
Contributor Author

@sergiou87 electron/electron#41391 was just merged (presumably for v31), so I was able to clean up the macOS logic. It may not bounce continuously until this project gets to that version, but when then upgrade happens this code won't need to be updated.

@sergiou87
Copy link
Member

Great work, thank you @yuzawa-san !!! 🙇‍♂️

I'm personally ok with having this difference in behavior until we update to Electron v31 (probably at some point this year or in early 2025), but I will check with the team next week and let you know.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants