Open bkunda opened 2 years ago
The multiple app icons are forced by the multi-instances thing. One instance of MuseScore can currently open only one file at a time, and almost everything relies on the assumption that there will always be zero or one files open at a time.
It is not possible to have multiple instances of an app but show only one app icon. Running multiple instances of one application is totally against the principles of macOS and thus not supported by Apple, and thus it affects the UX quite badly (multiple Dock icons, multiple icons in the app switcher, the shortcut to switch between windows not working...).
So, as far as I can see, the only way to fix this, is to rewrite significant portions of code so that the app can also handle multiple files within the same instance. (For Windows, we may still need the inter-process communication system, because on Windows it is apparently much more common that multiple app windows live in multiple processes.) I don't think it's realistic that this will be fixed before the release of 4.0.
This is the reason that I've always been silently frustrated by the whole multi-instances thing, but because so far I seemed to be the only one who cares about it, I didn't make a lot of noise about it.
Aha, so @cbjeukendrup is the reason that apps, like Logic and Pages in macOS, succeed in having only one icon in the dock (with multiple files open simultaneously) because they are running "multiple files within the same instance", as opposed to "multiple instances of the one application"?
FWIW this design was actually based on the UX of these two Apple apps, but I wasn't aware that something more fundamental under the hood was the reason our app behaved differently.
If it does require a significant rewrite of code, then I worry this may need to be bumped to 4.x. ☹️
I wasn't aware that "single instance, multiple windows" was a possibility. Perhaps it only works on macOS? Anyway, I think the current multi-instance approach was adopted partly because the new playback system wouldn't work otherwise, or it would require constantly loading and unloaded samples as you switch between scores. I'll be curious to see how that particular problem will be handled if we go back to using a single instance.
I thought "single instance, multiple windows" is a very normal thing and as far as I know, it can work on any OS (and should even be doable with QML). Anyway, on macOS, using a single instance is "the only correct way" to do it.
I've also always heard that the main reason for using multiple instances is something with playback, but I don't know anything more specific than that. Actually, at a first glance, the playback system seems already capable of handling multiple scores, because it works with independent "track sequences".
I think the real difficulty will be UI state handling; some state needs to be handled within individual windows, other things need to be coordinated app-wide. For example, palettes and toolbars would need to be synced between windows. I estimate that it is not really difficult to do, but just requires time to get it right, and it is guaranteed to introduce new bugs. Therefore my feeling is to delay this to 4.x, not just post beta 1. It's regrettable if it causes macOS users to be unhappy with 4.0, but even more delay + a lot of bugs is still more regrettable.
By now I've seen enough remarks/complaints from users to say that the change in behavior has been voiced for the other platforms as well.
@jeetee, is it just that users miss having tabs for different scores in the same app window, or does the technicality of having multiple instances cause problems on other platforms besides macOS? (What are those problems?)
It's (for the other OSes) definitely all about the single windows vs multi-window. I don't think most users out there are even aware of the difference between multi-instance-single-window-single-score and single-instance-multi-window-single-score.
It was more of a statement that (since topic title here mentions MacOS) doing this with the MacOS issues as driving factor will help alleviate some of the complaints about single-vs-multi-window (not necessarily instance, apologies) on the other systems.
Ok right. To be clear, even if we fix the multi-instance problem, it's not certain that we will go back to using a single window with tabs for every opened score. That's more of a design decision rather than a technical problem like this one, so it ought to have its own issue really.
I couldn't easily find a reference in the Human Interface guidelines, although CNET mentions it: On a Mac you never have multiple instances of an app. One instance runs all the windows.
FWIW, the multiple tabs in Musescore 3 is a PITA. The normal Mac way is to have multiple windows. The system will handle you putting them in tabs in a single window automatically.
Personally, the tabs have been useful for doing transposition work and keeping charts in order. I don't know how much work it would take to implement, but IMHO it should be an option to open scores in either a new window or a new tab, depending on what workflow works best for the composer/arranger. That said, even a fix on the multiple instances would be a massive help.
If you'd like to see tabs for score projects back then please open a new issue for it. This issue is about multi-instances.
Tabs come for free with the MacOS, so if you can fix the multi-instance problem, it will fix the tabs at the same time.
Tabs come for free with the MacOS, so if you can fix the multi-instance problem, it will fix the tabs at the same time.
Not in a Qt app, which MuseScore is. At least not in a sensible way. It will look very awful and work badly, because macOS doesn't know about the design and color scheme of MuseScore, and MuseScore can't know when the user presses the "new tab" button that macOS generates, and can't know what to do when the user presses it.
Anyway, please do open a new issue about tabs. From a technical point of view, it's a separate task.
I don't care if it's tabs or windows: the multiple icons in the Cmd-TAB switcher is unlike every other application. That really needs to go. It feels like a bug, not a feature. Or maybe: an implementation detail that should not concern the user suddenly becoming visible to the user.
I'm curious if this is going to be addressed soon? I'm still using MS3 mainly for this reason on my Mac.
Not in 4.1. Hopefully in 4.2.
That's too bad it's not sooner. I appreciate the update though. Thanks!
I've done some reading into how Chrome handles it's processes, and while we have some different challenges (due to Qt only having one renderThread per QApplication), I believe we could attempt a similar approach in having one Launcher process (with the ipc server) and have every other (GUI)-instance be raised as a child process into it.
Working on a small proof of concept application (without the full burden of porting and refactoring the mu::ipc usage) which hopefully might give us the insight in how to alleviate this Mac annoyance.
See https://github.com/jeetee/Qt_ProcessTree_ipc for the launcher process test project. I'm not too optimistic, as on windows the child processes all do show up as separate top level entries in the task manager, but you never know..
@cbjeukendrup would be nice if you can have a local test build going on somewhere during this or next week. At best, we'll have a fairly limited refactor to fix the dock effect; at worst, we'll at least be aware that a more profound refactoring is necessary.
@jeetee Thanks very much for your efforts! But unfortunately, I have bad news: it still produces multiple Dock icons on macOS. So I think that what needs to be done is that there is always only one QApplication instance, and all QWindows live in the same process as that instance. As long as we do that, we can apply whatever sub-process magic we want, with separate audio rendering processes for example... (like Dorico, by the way) But I'm afraid the conclusion is: a complex refactor will have to be done, regardless of whether we just try to do everything in the same process or use separate processes for audio rendering.
See https://github.com/jeetee/Qt_ProcessTree_ipc for the launcher process test project. I'm not too optimistic, as on windows the child processes all do show up as separate top level entries in the task manager, but you never know..
@cbjeukendrup would be nice if you can have a local test build going on somewhere during this or next week. At best, we'll have a fairly limited refactor to fix the dock effect; at worst, we'll at least be aware that a more profound refactoring is necessary.
The Chrome way is the right way : users are free to use tabs or different windows, and a tab can be simply dragged and dropped in its window. That's the best of both world. I wouldn't worry about each tab appearing as its own process in task manager, that's expected.
I think Chrome deliberately uses separate processes so that if one tab crashes it doesn't bring down the entire program (at least that's how it works in theory...). But it sounds like that approach wouldn't work for us anyway.
I think Chrome deliberately uses separate processes so that if one tab crashes it doesn't bring down the entire program (at least that's how it works in theory...). But it sounds like that approach wouldn't work for us anyway.
Yes that's true, but how wouldn't that work for you? I thought having separate processes was a req for you to manage different sounds? It is a genuine question I'm a IT dev and would like to help if something is doable with my capacity.
I wouldn't worry about each tab appearing as its own process in task manager, that's expected.
It's not about the process appearing, it's about them not appearing as children (even when they are). Take note that if you look at the current MuseScore process, you'll already notice that the crashpad handler exists as it's child process (and is listed as such).
The difficulty here (and why casper and myself were/are testing out some approaches) is to make Q(Gui)Application instances behave according to the Chrome model. If you'll run through the linked test project, you'll notice when running/debugging it already is one top level process with everything else as a child (or child of child) under it. However, due to how QGuiApplications register themselves with the different OSses, each of the initial child processes is still regarded as "top level" by windows (task manager) and MacOS (multiple dock icons, instead of one).
The additional challenge posed (for the "big refactor", which seems a more likely requirement for every other failed path attempt) is that Qt only allows for a single UI renderThread for a topLevel QApplication. This would mean that we'd probably need to come up with an implementation to support multiple renderThreads to re-enable a multidocument interface without making it slower than the current MuseScore implementation. Most likely this means a change to how the ScoreView is implemented to allow it to do buffered rendering instead of inside an existing QML component and then transfer that buffer via Shared Memory to the actual UI renderThread.
Another question that is yet to be answered, is whether the cause of the multiple top-level entries is the presence of multiple Q(Gui)Applications (more likely) or the fact that they each spawn their own QMainWindow (less likely). Though still allowing multiple QMainWindows in a single multi-processed QGuiApplication might still mess with MacOS's unified menubar behavior. If it does, then aside from ScoreView, the normal MainWindow rendering and how palettes/mixer etc are drawn within it will also require an architectural review.
I think the possibilities research can now be pretty much concluded after diving into some more topics around this; with a fairly decent summary in this topic around PyQt and multithreading. I'll summarize the most important takeaways relating to MuseScore here:
A process can have only one QCoreApplication or derivative (QApplication/QGuiApplication) of it.
The QCoreApplication object must be the 1st QObject created on the "main thread". The "main thread" according to Qt is the first thread that creates a QObject (even if it's not the QCoreApplication). This does not have to coincide with the actual application thread running the main function. Consequence: You can't use a QThread to run a QCoreApplication, as QThread itself is already a QObject.
Due to thread affinity of QObjects, the UI really should run within the eventloop of the QCoreApplication. As such there should be only one UI thread and it will be the "main thread".
(At least on Windows) Spawning multiple QMainWindows is just fine and likely doesn't enforce multi-dock-behavior on MacOS.
The child processes showing up as top level processes in the windows task manager in the ProcessTree test project from above are indeed due to violating the "single QCoreApplication" rule. The way QCoreApplication handles registering itself to the OS enforces them as seperate toplevel processes (but with child-linkage).
It is possible to perform (part of) the drawing in a separate thread and doing so in shared memory if that drawing is computationally intensive (see the Qt Mandelbrot Example). Whether or not this is something we'd want to use for ScoreView or not remains to be seen and subject of further analysis (by "someone"). It might already suffice to perform our layoutcalculations on a worker thread while leaving the drawing based on the resulting values within the UI thread.
I'll have a go at working these conclusions (aside from the renderthread approach) into a new version of the ProcessTree repo so we can confirm that his method of single-instance running will address the MacOS docking problem.
Finally got around to updating the example project to be a single (gui) instance build. For which Casper could confirm the desired dock icon behavior on MacOS.
Next steps: Figure out which modules can be loaded/linked to the Single GUI Instance (settings/workspaces come immediately to mind, avoiding the synchronization mess we currently have on them) and which modules are MainWindow-specific (notationcontroller etc).
This does not yet begin to investigate a possible tabbed multi-document single-window approach. Only looking into single instance, multi window to limit/minimize the changes needed for MuseScore.
I'll probably halt development on the separate test project unless something specific needs additional attention and start moving into a MuseScore branch for the bulk of those changes; so we can account for the MuseScore specific interactions and architecture.
I'm having a (slow!) go at trying to modify MuseScore on the main/app/appshell level over at https://github.com/jeetee/MuseScore/tree/12647-single-instance-model . As always, anyone with time is free to pick this up as I can't guarantee free time.
And for those following along in hopes of seeing this fix. What I'm doing now is only the starting step; it'll enforce single instance and multi window behavior. But as many things now assume single instance usage, I'm expecting a lot of things will need further updates/fixing after the initial structural changes.
Two ideas.
or 3: actually do run a single UI instance?
or 3: actually do run a single UI instance?
I see several problems with this:
@igorkorsukov Both options seem a no-go.
Such thing doesn't exist on macOS. Grouping of dock icons is not possible. You could say each dock icon corresponds to a NSApplication instance, so there should be only one of those (and thus only one process that creates a QApplication).
This hack doesn't really solve the problem. You would still see multiple icons in the App Switcher, and OS-wide shortcuts like Cmd+Tab and Cmd+` don't work. There is simply a whole stack of problems that are either unfixable or require even more ugly hacks. This is not sustainable.
It's strange to make these complications due to a limitation of one of the platforms
You could say just as well: when building an app for macOS, it's weird if we don't follow the correct architecture of a macOS app. Literally all macOS apps use one main process.
There are two things that are fine:
One more remark: the multiinstances architecture is very limiting. For example, "unroll repeats" can't really be implemented now: it should create a score in memory based on the current score in its current state, and open that. That's impossible with the multiinstances thing: you'd need to write the generated score to disk, then create a new instance and tell it to open that score and treat it as a special newly created score. This involves the addition of even more "private" command line options that you actually don't want to exist. Or what about the extensions framework, where users will expect the possibility to do something similar to "unroll repeats", or wants to perform some action for all open scores (including ones in different instances). Or what about the Split View feature, that lets you open two scores side by side in one window, or in multiple tabs? This seems simply impossible with the current architecture.
Oh, and there is performance and memory usage. Opening a score doesn't take long usually, but starting up a new instance does take very long (sometimes even more than 20 seconds!). And everything is duplicated in memory for every score that's open (for example Qt libraries that are loaded, and even the executable itself, and boilerplate stuff like the NSApplication instance).
My conclusion: both options have different pros and cons, but the current option is absolutely not that much better than the "proper" way. The proper way has the advantage of being ehm... proper, and gives more possibilities for multi-score features. I'm not too convinced about the "a crash would affect only one window" argument: in the first place, there should not be any crashes, and in the second place, that's what AutoSave and session restore are for. (Incidentally, the "restore session" feature is basically broken by multiinstances.)
Yes, state management is more difficult with multiple scores in one instance. But I think that's just part of our job. I'd rather work two months on a solution that we can be proud of than two weeks on a workaround that only replaces the problem with 5 other problems.
I don't agree with these arguments, but I need to think and investigate ) Are all large applications that are not specific to MacOS, for example Photoshop, AutoCAD, MS Office, etc., running many windows in one process..?
Are all large applications that are not specific to MacOS, for example Photoshop, AutoCAD, MS Office, etc., running many windows in one process..?
Every app does this on MacOS.
Every app does this on MacOS.
And all these programs support multi-window on MacOS?
Help me figure it out. For example, I have some Sql Manager, it opens one database. I want to open another database. I click on the Sql Manager launcher and the previous instance opens with the database already open. How can I open another database on MacOS?
I don’t know about Sql Manager, but most apps you could choose File->Open, or drop the file on the app icon and it will open in a new window.
On 3 May 2024, at 18:09, Igor Korsukov @.***> wrote:
Every app does this on MacOS.
And all these programs support multi-window on MacOS?
Help me figure it out. For example, I have some Sql Manager, it opens one database. I want to open another base. I click on the Sql Manager launcher and the previous instance opens with the database already open. How can I open another database on MacOS?
— Reply to this email directly, view it on GitHub https://github.com/musescore/MuseScore/issues/12647#issuecomment-2092520321, or unsubscribe https://github.com/notifications/unsubscribe-auth/AJDBQLQM5NLZEBDNBLOKWMLZANA2JAVCNFSM55LL3HM2U5DIOJSWCZC7NNSXTN2JONZXKZKDN5WW2ZLOOQ5TEMBZGI2TEMBTGIYQ. You are receiving this because you commented.
There are of course apps that support only one open file at a time, because the developer did not take the effort to implement multifile support. But even the most complicated apps (Dorico, Sibelius, Logic Pro, Xcode) support multiple windows with multiple projects, all within one (main) process.
Chrome has a separate process for each tab and each extension, plus a single process for all GPU rendering. Though there is probably still a single main process on macOS that communicates with the subprocesses somehow.
Of course Chrome is also known for being a memory hog, but other Chromium-based browsers don't seem to have that problem.
I made sure that a single instance of multi-window is what works on MacOS. I don’t think this is a good decision by the MacOS developers; perhaps they made their life easier, but they made life more difficult for millions of other developers. And I don’t think that this is a good solution for users, yes, we can say “there shouldn’t be bugs” but they have and will always be, we can deny this reality, but it will remain a reality. So, isolated processes are more preferable.
But these are, of course, philosophical thoughts... and everyone has their own arguments.
I'll start investigate how to turn MuseScore into a single-application multi-window
Task description
This task proposes a revision to the way MuseScore currently handles multiple open projects in MacOS.
Currently, a new app icon appears in the dock for each opened project window.
This is generally inconsistent with other MacOS apps that also use separate windows for each opened file, and generates both confusing UX and a cluttered UI in the dock.
Please see this design spec for an illustration of how an alternate approach might work for MuseScore 4:
Design-Spec_New-Project-Windows_2Aug22.pdf
Let me know if there are any questions or comments! Bradley