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

If "Allow multiple instances" disabled, then make it focus and visible if trying to start dublicate #145

Open
vini-nu opened this issue Jun 30, 2024 · 18 comments

Comments

@vini-nu
Copy link

vini-nu commented Jun 30, 2024

Very oftenly when I need calculator, I just press [Meta] and type "calc" and press Enter. I don't need multiple instances. But I don't close Qalculate either. If it was opened already and are minimized or behind other windows and I try to open Qalculate, it just ignores my command. Instead existing Qalculate instance could appear on top and on focus when I do that... Because that's exactly what this setting was suppost to do.


QT Qalculate, Arch, KDE Plasma 6.1, Wayland, Nvidia555

@hanna-kn
Copy link
Contributor

It seems to be a Wayland issue.

The code below is used and works elsewhere

setWindowState((windowState() & ~Qt::WindowMinimized) | Qt::WindowActive);
raise();
activateWindow();

@SanderBouwhuis
Copy link

SanderBouwhuis commented Nov 30, 2024

I have the same problem on Windows.
If Qalculate IS NOT started, then Qalculate ALWAYS opens BEHIND other windows (very confusing and annoying).
If Qalculate IS started, then Qalculate ALWAYS stays BEHIND other windows and does NOT activate.

SetForegroundWindow(hWnd) is the standard way of doing this in Win32 API.

@hanna-kn
Copy link
Contributor

I have the same problem on Windows. If Qalculate IS NOT started, then Qalculate ALWAYS opens BEHIND other windows (very confusing and annoying). If Qalculate IS started, then Qalculate ALWAYS stays BEHIND other windows and does NOT activate.

How do you launch Qalculate?
If you use a keyboard shortcut, how is it set?
Does it matter which application is opened (e.g. does it open behind File Explorer)?
Which version of Windows are you using?

@SanderBouwhuis
Copy link

SanderBouwhuis commented Nov 30, 2024

  1. I launch Qalculate with a shortcut key on my Microsoft Ergonomic Keyboard 2019.

  2. I launch Qalculate with the 'favorite 1' button, because overriding the calculator button with these registry keys doesn't work reliably:

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\AppKey\18]
"ShellExecute"="C:\Utilities\Qalculate\qalculate-qt.exe"

[HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\AppKey\18]
"ShellExecute"="C:\Utilities\Qalculate\qalculate-qt.exe"

Keyboard

  1. Regardless of which application currently has the focus, it always goes behind that window.
    Example:

Assume I have this z-order when I press the shortcut key:
desktop
application window 1
application window 2

Desktop has the focus:
desktop
Qalculate
application window 1
application window 2

application window 1 has the focus:
desktop
application window 2
Qalculate
application window 1

application window 2 has the focus:
desktop
application window 1
Qalculate
application window 2

  1. My computer:
    Computer

@hanna-kn
Copy link
Contributor

hanna-kn commented Dec 1, 2024

I launch Qalculate with a shortcut key on my Microsoft Ergonomic Keyboard 2019

I've not been able to replicate this issue using the software for my Logitech keyboard, using the WinHotKey program, or setting a shortcut key in the properties of the desktop icon.

Does qalculate-gtk behave in the same way?

A related issue: Qalculate/qalculate-gtk#347.

@SanderBouwhuis
Copy link

SanderBouwhuis commented Dec 1, 2024

I just tried it, and yes, the GTK version does the same thing. The only strange thing is that it opens in a 'random' position every time (I started it 3 times, and 3 times the window was placed somewhere else).
So, both of them place the window behind the currently active window, and above all other windows.

Is it really not possible to simply call the SetForegroundWindow() function? I have used that many times myself, and I've yet to see that fail. It is incredibly confusing as it is now, because you think Qalculate didn't actually start (making me press the button a few times and then thinking "ooooooooh yeah, I forgot").

If you want, you can send me a debug version which logs a ton of stuff. I can then send you the debug log. I have Visual Studio 2022 including all debug libraries on my computer, so a debug version may work out of the box for me.

@hanna-kn
Copy link
Contributor

hanna-kn commented Dec 1, 2024

I've compiled an executable which calls SetForegroundWindow((HWND) window()->winId()) two seconds after startup and when activated (in the latter case ((QWindow*) window())->requestActivate() is also called): https://github.com/Qalculate/qalculate-qt/releases/download/v5.4.0/qalculate-qt-setforegroundwindow-test.zip.

@SanderBouwhuis
Copy link

SanderBouwhuis commented Dec 1, 2024

Yep, it works.
Maybe you can reduce the two seconds to have it start up immediately?
Also, can I use this version like a normal version?

Edit:
Actually, you only fixed it in case Qalculate is not running.
If Qalculate is already running, then you don't bring it to the front. Could you also add the SetForegroundWindows() to that case?

@hanna-kn
Copy link
Contributor

hanna-kn commented Dec 1, 2024

Maybe you can reduce the two seconds to have it start up immediately?

Version without delay: https://github.com/Qalculate/qalculate-qt/releases/download/v5.4.0/qalculate-qt-setforegroundwindow-test-b.zip

Also, can I use this version like a normal version?

Yes, there are no differences (except a few minor fixes/improvements).

If Qalculate is already running, then you don't bring it to the front. Could you also add the SetForegroundWindows() to that case?

I did, and AllowSetForegroundWindow was already set before these changes.

@SanderBouwhuis
Copy link

SanderBouwhuis commented Dec 1, 2024

Ok, that is super weird.
Now both a newly started Qalculate AND an already running Qalculate don't come to the foreground.

So:
The "...test.zip" works for new instances, but not existing.
The "...testb.zip" does not work for new instances, and does not work for existing.

Edit:
Ah, shoot. You removed the "...test.zip". Now I can't revert to your semi-fixed version. Could you make it available again?

@hanna-kn
Copy link
Contributor

hanna-kn commented Dec 2, 2024

A final test with multiple executables with varied set foreground delays (milliseconds indicated in file name) for both new and existing instances:
https://github.com/Qalculate/qalculate-qt/releases/download/v5.4.0/qalculate-qt-setforegroundwindow-test-c.zip

Does other applications work as expected with the shortcut key?

@SanderBouwhuis
Copy link

SanderBouwhuis commented Dec 3, 2024

All of them fail.

I also notice that the Qalculate window never gets activated. Not when starting new, and not when it was already running. The focus remains on the application (or desktop) which had the focus when starting Qalculate with the shortcut key.

I tried Windows Explorer, and that fails (like Qalculate).
Then I tried one of my own applications, and that works correctly.

Here is the code I use when starting fresh:

// Has the window state been overridden on the command-line?
if(cmdLineParams.u8WindowState == SW_MINIMIZE  ||  cmdLineParams.u8WindowState == SW_MAXIMIZE)
{
  // Override the window state
  OutputDebugMessage(m_pWstrDebugLog, L"cmdLineParams.u8WindowState == %s\n", cmdLineParams.u8WindowState == SW_MINIMIZE ? L"SW_MINIMIZE" : L"SW_MAXIMIZE");
  ShowWindow(m_hWnd, cmdLineParams.u8WindowState);
}
else
  ShowWindow(m_hWnd, SW_SHOWNORMAL);

And here is my code when another instance is already running:

// Check whether Dms is already running
hMutex = CreateMutex(nullptr, true, L"DmsMutex");
if(GetLastError() == ERROR_ALREADY_EXISTS)
{
  #ifdef BUILD_NO_USER_INTERACTION
  {
    // Quit the current instance
    bResult = true;
  }
  #else
  {
    std::unique_ptr<CStringResource> pStrRes;

    // Initialize the language
    pStrRes = std::make_unique<CStringResource>(TranslateStrings_Launcher, gc_u8LanguageEnglish);

    // Ask the user whether to open a new instance
    if(MessageBox(nullptr, pStrRes->Get(L"Dms_already_running"), pStrRes->Get(L"Warning"), MB_YESNO | MB_ICONQUESTION) == IDNO)
    {
      HWND hWndPrevInst;

      // Bring our existing window to the front
      if((hWndPrevInst = FindWindow(L"CLauncher", nullptr)) != nullptr)
      {
        // Make sure the app is visible
        ShowWindow(hWndPrevInst, SW_RESTORE);
        SetForegroundWindow(hWndPrevInst);

        // Quit the current instance
        bResult = true;
      }
    }
  }
  #endif
}

Workaround

I found a workaround; if you set the Qalculate window 'always on top', then it actually does come to the front and correctly activates the window. But, then it is always over other windows, so this may not be what a user wants.

@hanna-kn
Copy link
Contributor

hanna-kn commented Dec 3, 2024

All of them fail.

That is odd considering that the first version (with 2 s delay) was a partial success.

I tried Windows Explorer, and that fails (like Qalculate).

This makes it obvious that the keyboard software (or something else on your system) is broken. Does it work properly if you assign a shortcut key to a link (e.g. a desktop icon) to qalculate-qt.exe.

@SanderBouwhuis
Copy link

SanderBouwhuis commented Dec 3, 2024

Ah yes, I forgot to mention that I indeed tried that. But, when I assign a shortcut in the favorite it is the same thing. Even when I set it to MAXIMIZE in the shortcut, it still doesn't active it.

Also, I only installed Windows 11 a few weeks ago on my new computer (I came from a Windows 10 computer). I recall there was a setting where you could turn off that the taskbar icons 'flashed' when they wanted your attention. I hate that, so I turned it off.
Maybe that has something to do with it.

Having said that, it doesn't explain why my own application works perfectly fine.
Can you re-upload that initial test? I'm beginning to suspect I may have tested it incorrectly, considering every single subsequent test failed.

@hanna-kn
Copy link
Contributor

hanna-kn commented Dec 4, 2024

Next attempt: https://github.com/Qalculate/qalculate-qt/releases/download/v5.4.0/qalculate-qt-setforegroundwindow-test-d.zip

Code on new instance:

	win->show();

#ifdef _WIN32
	HWND hwnd = FindWindowA(nullptr, "Qalculate!");
	if(hwnd == nullptr) hwnd = (HWND) win->window()->winId();
	if(hwnd != nullptr) {
		ShowWindow(hwnd, SW_SHOWNORMAL);
		SetForegroundWindow(hwnd);

	}
#endif

In my tests both methods for window handler retrieval returns the same valid pointer.

Code when another instance is already running:

if(settings->allow_multiple_instances <= 0) {
#ifdef _WIN32
	HWND hwnd = FindWindowA(nullptr, "Qalculate!");
	if(hwnd != nullptr) {
		ShowWindow(hwnd, SW_RESTORE);
		SetForegroundWindow(hwnd);
	}
	(...)

@SanderBouwhuis
Copy link

SanderBouwhuis commented Dec 5, 2024

No, no success.

It's so weird, because you are calling the right functions (the same I am). Maybe you are calling the functions too early. Are you calling these functions while the window itself hasn't been completely created? Don't handle this in the WM_CREATE message, but rather in the first WM_SHOWWINDOW message. Or maybe you can wait until your message pump is running, and then bring the window to the front?

Workaround:

I know that when I set the 'keep above other windows' to on, it works. I assume you are supplying the WS_EX_TOPMOST flag? Or else you are calling the SetWindowPos function with the HWND_TOPMOST flag.

So, when starting a new or existing instance, just pretend the 'keep above other windows' setting is on (for a moment), and then turn the setting off again.

After you are showing the Qalculate window, you can call this function to turn it off again (if needed):

SetWindowPos(hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);

@hanna-kn
Copy link
Contributor

hanna-kn commented Dec 5, 2024

With keep above other windows temporary enabled:
https://github.com/Qalculate/qalculate-qt/releases/download/v5.4.0/qalculate-qt-setforegroundwindow-test-e.zip
(contains two executables - one with a one second delay, resulting in the window flashing once, and one without any delay)

I assume you are supplying the WS_EX_TOPMOST flag? Or else you are calling the SetWindowPos function with the HWND_TOPMOST flag.

I use setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint).

It's so weird, because you are calling the right functions (the same I am). Maybe you are calling the functions too early. Are you calling these functions while the window itself hasn't been completely created? Don't handle this in the WM_CREATE message, but rather in the first WM_SHOWWINDOW message. Or maybe you can wait until your message pump is running, and then bring the window to the front?

I've confirmed that the new code, with the old code disabled, works for already running instances. The code for the new instance likely does not add anything to what is already done by Qt when a window is shown.

@SanderBouwhuis
Copy link

Ok, we are very close now!
Both versions properly bring Qalculate to the front of the Z-order.

But, you are somehow confusing Windows, because now two applications seem to have the focus (their titlebar is highlighted). But, unfortunately, it's still the originally activated window which is actually the activated one, because the keyboard focus is on the original window.

  1. Have an active Window (e.g., Firefox).
  2. Press the shortcut key to start Qalculate.
  3. Qalculate now opens on top of Firefox (good).
  4. Somehow Windows is confused, and now both windows show they are active (highlighted titlebar)
  5. When I type numbers, it is Firefox who gets the typed characters (bad).

Qalculate focus bug

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

No branches or pull requests

3 participants