Fyne: Menu bar initially doesn't respond to mouse input on macOS

Created on 28 Oct 2019  路  16Comments  路  Source: fyne-io/fyne

Describe the bug
Playing with the demo (commit 98fc45eeb2f12a3d3d0ad62f485883130e292312) on macOS (catalina), the menu bar won鈥檛 respond to mouse clicks when launching it from the command line (admittedly not normal for a macOS app) until you switch to another app and come back.

To Reproduce
Steps to reproduce the behavior:

  1. cd cmd/fyne_demo
  2. go run main.go
  3. Try to click on the menu entries the demo app put up... none respond
  4. Switch to another app
  5. Switch back to the demo app
  6. Menu now responds to mouse input

Screenshots
If applicable, add screenshots to help explain your problem.

Device (please complete the following information):

  • OS: macOS
  • Version 10.15 (Catalina)
  • Go version 1.13.3
  • Fyne version 98fc45eeb2f12a3d3d0ad62f485883130e292312
macOS bug

All 16 comments

Hi, I'm on Mojave here and cannot reproduce this. Can anyone confirm the steps to reproduce this issue? And if so, on which OS version?

It only happens on Catalina. If you open a Fyne app it鈥檚 menu does not respond. Switch away and back again and it works ok.

I have since found out that if you package the app up the problem does not occur. So this is really only an issue for us developers. I may consider removing "Blocker" now...

Yes. I did mention it is only an issue when the executable is launched directly from the command line (i.e. not via the UI nor via the use of open, which ultimately behaves as if you opened the app from the UI). This is true whether packaged or not -- but I agree that no one should consider this a blocker.

I've found a workaround that you can use to fix this problem. First, you need a way to detect you're being launched without a bundle. The easiest way I could think of to do this is to determine if os.stdout was connected to a terminal. If it is, then issue a hide followed immediately by an unhide.

var termios syscall.Termios
if _, _, errno := syscall.Syscall6(syscall.SYS_IOCTL, os.Stdout.Fd(), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0); errno == 0 {
    hideApp() // needs to do this in native code: [[NSRunningApplication currentApplication] hide];
    unhideApp() // needs to do this in native code: [[NSRunningApplication currentApplication] unhide];
}

I do this right before entering the run loop.

This is really helpful thanks - let's see if we can find a nice way to work it in

I have coded something in (though I had to activate after unhide to get the window back on top.
Unfortunately the flicker it produces is noticeable.
Of course a flicker is better than not working... this may have to be extended so that it doesn't flicker on other systems so minimising the impact.

Calling this before the first window is shown:

void menuFix() {
    if ([[NSBundle mainBundle] bundleIdentifier] != nil) {
        return;
    }

    NSRunningApplication *app = [NSRunningApplication currentApplication];
    [app hide];
    [app unhide];
    [app activateWithOptions:NSApplicationActivateIgnoringOtherApps];
}

Not sure why it flickers as it should happen before shown, possibly needs more investigation.

I don't think you can do much, if anything, about the flicker, unfortunately. However, it should only be triggered if you are launching from the command-line (and not using open), so really should only affect developers. Much less annoying (for me, anyway), than having to manually switch to another app and back every time I try to debug something.

Short of a real fix to the underlying issue this is probably the best we can do.
I wish I knew how much more difficult it would be to actually fix the issue with activatyion on Catalina so that the app just worked like it should. As I write this bugfix in it keeps looking uglier :(

If someone on your team has an actual Apple Developer account, an issue could be raised with them. They clearly made a change here, so they should be able to give specific directions on what needs to be done now that they no longer do whatever it is they did previously.

I see this is still not functioning correctly... did the change above not get applied? One difference between what @andydotxyz listed and what I've done in my own Go apps is that I do the hide/unhide after doing the activate... although I only do that when launched from a terminal, which I detect like this:

// IsTerminal returns true if the writer's file descriptor is a terminal.
func IsTerminal(f io.Writer) bool {
    var termios syscall.Termios
    switch v := f.(type) {
    case *os.File:
        _, _, errno := syscall.Syscall6(syscall.SYS_IOCTL, v.Fd(), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0) //nolint:gosec
        return errno == 0
    default:
        return false
    }
}

and calling it with os.Stdout.

I can make a PR for fixing this if it in fact hasn't been done yet. Please let me know.

Ah... I guess I gave the code for checking for the terminal before... sorry for repeating it.

It appears that all you really need to do is something like this right before entering the main run loop:

dispatch_async(dispatch_get_main_queue(), ^{
    [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
});

I'll see if I can find the relevant place in the Fyne source base to apply this and make a PR.

It will be some time before the fix you submitted is propagated up to us, so I have made a fork of the go-glfw and applied it just for us. So this is now fixed in the release/v1.4.x branch :)

Thanks for your help on this one @richardwilkes.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

HeyDon-Lee picture HeyDon-Lee  路  9Comments

lusingander picture lusingander  路  3Comments

hajimehoshi picture hajimehoshi  路  9Comments

semyon-dev picture semyon-dev  路  4Comments

andydotxyz picture andydotxyz  路  7Comments