mu icon indicating copy to clipboard operation
mu copied to clipboard

Single instance application

Open carlosperate opened this issue 8 years ago • 16 comments

We need to consider if this is something we should enforce with Mu. As discussed in https://github.com/mu-editor/mu/issues/268 several instances of the editor would be using the same config file and log.

The easiest solution would be to set the application to be single-instance only, so that would be my vote. But it'd be good to check if this is also the best solution for the Mu target audience, does anybody have an insight in this area?

carlosperate avatar Jun 22 '17 16:06 carlosperate

I have absolutely no insight into this, nor do I know how to enforce single instance. Any idea how this would work? (I believe single instance is probably a helpful thing to do given the context you describe @carlosperate).

ntoll avatar Jun 04 '18 20:06 ntoll

I think we already have this?

EDIT I lied

QApplication != GApplication

ZanderBrown avatar Jun 04 '18 21:06 ZanderBrown

So in the Qt world the answer seems to be that it's doable but harder than it should be

ZanderBrown avatar Jun 04 '18 22:06 ZanderBrown

Originally I was probably hopefull that this could be provided by PyInstaller, but since we are using 3 different packaging methods (Windows, macOS and pip), I'm not really sure how this can be achieved.

carlosperate avatar Jun 05 '18 08:06 carlosperate

The conventional approach is to attempt to acquire a mutex of some sort and, on failure, switch focus to the already-activated version of the app.

Trying to activate an existing app can be tricky, so an alternative to transparent activation of the existing instance is to force failure by putting up a modal dialog warning that an instance is already running.

The second is the less complex option, but even so I don't know whether it's necessary in comparison to the small risk of a session file being unexpectedly overwritten.

tjguk avatar Jun 05 '18 08:06 tjguk

Alternatively, we can ignore the single-instance notion and work harder to merge session files when saving. Again, I don't know if this complexity outweighs the risk.

tjguk avatar Jun 05 '18 09:06 tjguk

This is why GApplication is so nice, I'd have thought everyone would have these niceties by now but it seems QApplication is relatively "dumb" in this area

Either solution is going to be complex but the current state of affairs isn't great either (especially as we are an 'open with' target now)

ZanderBrown avatar Jun 05 '18 10:06 ZanderBrown

Maybe we can use this: https://github.com/IARI/alsa_jack_gui/blob/master/qtsingleapplication.py

carlosperate avatar Jun 05 '18 10:06 carlosperate

That's basically technique (1) for my post above. And it's good to have something already written and working. But it does complicate the startup of the app and leaves the door open for odd problems.

tjguk avatar Jun 05 '18 10:06 tjguk

OK... so there's a thing in Qt called QLockFile... see: http://blog.aeguana.com/2015/10/15/how-to-run-a-single-app-instance-in-qt/ and https://doc.qt.io/qt-5/qlockfile.html

We'd just need to do:

from PyQt5.QtCore import QLockFile

Check/create lock file and if there's a problem complain with a modal error box. This feels the simplest solution.

ntoll avatar Jun 05 '18 11:06 ntoll

There is no danger when the app crashes, because the lock will be destroyed with the app instance.

Okay, that's good. Main reason I've never suggested lock files is because I cannot count the number of times I had to manually remove these when apps crash (I'm looking at you Eclipse....)

carlosperate avatar Jun 05 '18 11:06 carlosperate

Quite... it appears the QLockFile is exactly what we're looking for.

ntoll avatar Jun 05 '18 11:06 ntoll

This is also relevant: https://stackoverflow.com/questions/8786136/pyqt-how-to-detect-and-close-ui-if-its-already-running

carlosperate avatar Aug 17 '21 11:08 carlosperate

After working on #2386 to resolve some issues I ran into with the approach taken in #2297 (using QSharedMemory) and to add code to handle clean up for the app-crashed case, QLockFile seems like it might be a better approach since we'd basically have to do the same kind of "stale" flagging for the shared memory block as QLockFile is already doing on disk to avoid the user having to restart in order to run Mu again if the app crashes. At least that's how it looks to me.

QLockFile docs

haikusw avatar Jan 03 '23 08:01 haikusw

Having a quick look at those docs, this seems like a deal breaker to me:

Note: On Windows, this class has problems detecting a stale lock if the machine’s hostname contains characters outside the US-ASCII character set.

We've had quite a few issues encoding and decoding paths on Windows when users have different languages configured, so the chances of somebody having a non ASCII hostname are high enough to worry about this. And compared with the shared memory approach (on which worse-case-scenario a stale lock gets resolved after a restart), a user hitting this issue with QLockFile will never be able to recover without manually deleting the file.

Another reason why we are a bit apprehensive with using files is that we've also encountered a few issues with antiviruses locking newly created files and then the application crashing when access to the file they just created is denied. In this particular case the file should be so small that I would assume any antivirus would take almost not time to scan it, but trying to avoid this kind of risk would have had an effect on the decision between the different approaches.

carlosperate avatar Jan 13 '23 13:01 carlosperate

Hi @carlosperate Thanks for the information. Very unfortunate Windows behavior for QLockFile is so flawed. Strong reason to not use it (hopefully someone with a Windows dev setup can look into fixing that upstream in PyQt or QT).

Surprising about the anti-virus glitch, but also compelling.

Ok. Where does that leave us in regards to #2386? 🤔

Seems like that conversation belongs there.

haikusw avatar Jan 13 '23 19:01 haikusw