-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
Refactor MixxxMainWindow. #941
Conversation
This is step 2 (step 1 was WMainMenuBar) on a long-term refactor journey for me. I wrote down some of the goals in this design doc: |
I have just read the linked document and I like the underlying ideas. The multi-threading approach will help to utilize the n-cores of recent CPUs. However, I think it is not a good idea to present the GUI before Mixxx is ready to used. An other general thought is: Multitheading increased the complexity significant. If you aim to reduce the complexity this might be a bad deal. But we will see, when it comes to the implementation. |
src/main.cpp
Outdated
qDebug() << "Running Mixxx"; | ||
result = a.exec(); | ||
mixxx::Core::initializeStaticServices(); | ||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// scope for core
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done -- though this seems a bit obvious, no?
OK, I assume there where nothing changed in the business logic, only moving functions around, right? I have only added some minor nits. The other main issue is the release schedule. We have already published a release date for Mixxx 2.1 ( The alpha seams to be blocked by the broken windows build server though These planed refactorings will not have a user impact, but have some degree of regression risk. |
Yep, that's right. |
I agree this shouldn't go in 2.1. |
@rryan are you interested in picking this up again? Now would be the time to do it. Our startup time has gotten really bad. |
This pull request has not been updated in years so I am closing it to reduce the clutter of open PRs. If you solve the merge conflicts and would like to have it merged in the future, please reopen it. However, considering how many merge conflicts there are, it may be easier to start over from the current master branch. |
Yea, I am. I'll re-open when/if I get to it though. |
Re-based against master, tests are passing on macOS and no shared_ptr leaks occur. |
Thanks for picking up work on this again! |
19d9e56
to
e7bebe3
Compare
I think there will be a few small merge conflicts between this and #1705, but it looks like they will be easy to resolve. |
Splits MixxxMainWindow into two pieces: CoreServices and WMainWindow. This will allow us to iterate on new frontends that do not make use of QtWidgets / QtGui (such as an Android or iOS port) and generally enforces a cleaner separation between Mixxx services (provided by individual manager classes) and the Mixxx UI. This is also a step towards refactoring the bootup process (which prompted us to add a loading" launch screen because it's so slow). With a cleaner concept of "phases" of bootup (construction, initialize, configure, finalize, destruction) we can start the UI after construction/initialization and delay the longer tasks (e.g. connecting audio devices and controllers) or push them onto a different thread. Ideally all manager classes and CoreServices will remain buildable with the QtWidgets module disabled.
This adds safety against use-after-free to the interaction between EngineMaster, SoundManager, EngineSideChain, VinylControlProcessor, EngineDeck, EngineMicrophone, and EngineAux. Note that this effectively reverts db3b503. The reason this was done initially was to avoid coupling between SoundManager and EngineMaster. Ideally neither of them should know about each other, and they could communicate via interfaces alone. They are currently coupled (SoundManager has a reference to EngineMaster) because of the callback, but I've always wanted to remove that so they are totally independent. PlayerManager (which could have been named EngineManager) as I originally imagined it, is where EngineMaster and SoundManager are bound together, since PlayerManager has a reference to both; for example, when a deck is added, it's added to EngineMaster and registered with SoundManager in PlayerManager. That's why the logic to register EngineMaster's non-EngineChannel AudioInputs/AudioOutputs originally went in PlayerManager. Thinking of PlayerManager as EngineManager, this kind of makes sense. In this PR, the logic can no longer live in EngineMaster for the simple reason that EngineMaster does not have a shared_ptr to itself, and so it can't call SoundManager::registerXXX(..., this) anymore. We could plumb a shared_ptr into EngineMaster, but that creates a reference leak.
I think this is ready to go. It's a first step toward the plan for an init refactor that only moves code around without intentionally changing any logic. The ordering of some steps in bootup and shutdown have changed slightly, but it should only be incidental. Any comments? |
Yea, I tried to make this minimally invasive w.r.t. any changes made to the effects system or library. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for starting to clean this up!
void clearHelper(std::shared_ptr<T>& ref_ptr, const char* name) { | ||
std::weak_ptr<T> weak(ref_ptr); | ||
ref_ptr.reset(); | ||
if (auto shared = weak.lock()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DEBUG_ASSERT?
@@ -778,7 +397,7 @@ void MixxxMainWindow::initializeKeyboard() { | |||
m_pKeyboard = new KeyboardEventFilter(keyboardShortcutsEnabled ? m_pKbdConfig : m_pKbdConfigEmpty); | |||
} | |||
|
|||
QDialog::DialogCode MixxxMainWindow::soundDeviceErrorDlg( | |||
QDialog::DialogCode WMainWindow::soundDeviceErrorDlg( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This feels out of place in WMainWindow. Should it be moved into SoundManager?
namespace mixxx { | ||
|
||
class CoreServices : public QObject { | ||
Q_OBJECT |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this need to be a Q_OBJECT?
|
||
m_pGuiTick = std::make_shared<GuiTick>(); | ||
|
||
// TODO(rryan): Move this back into EngineMaster. The only reason it got |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I agree this should be moved back to EngineMaster. There some places throughout the code that rely on parsing strings to identify a channel. I think it would be better to make use of ChannelHandles more widely throughout Mixxx than confine them to EngineMaster.
m_pEffectsManager = std::make_shared<EffectsManager>(this, pConfig, m_pChannelHandleFactory); | ||
|
||
// Starting the master (mixing of the channels and effects): | ||
m_pEngine = std::make_shared<EngineMaster>( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we drop the "Master" from "EngineMaster"? Or maybe call it "EngineMixer"?
std::static_pointer_cast<GlobalTrackCacheSaver>(m_pLibrary)); | ||
|
||
// TODO(rryan): de-singleton | ||
// TODO(rryan): Where does this belong? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LibraryManager?
m_pPlayerManager->addSampler(); | ||
m_pPlayerManager->addPreviewDeck(); | ||
|
||
// TODO(rryan): Why is this here? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IIRC this has to be called after creating mics, aux channels, and samplers in case those are routed to any saved chains. (I could be wrong about that.)
auto core = std::make_shared<mixxx::CoreServices>(nullptr, app, args.getSettingsPath()); | ||
core->initialize(); | ||
{ // Scope for WMainWindow. | ||
WMainWindow window(app, core); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This introduces a regression. No GUI is shown for about 3 seconds, then when the main window is first shown, the loading progress bar is already over half way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ping. I propose moving the construction of services in the CoreServices class from the constructor to a new method that would get called by WMainWindow. Then have CoreServices emit a signal after each service is started that triggers a progress bar update in WMainWindow.
I would like to merge this relatively soon before more merge conflicts develop. |
@rryan will you have time to continue this soon? If not I might pick it up. |
This PR is marked as stale because it has been open 90 days with no activity. |
Superceeded by #3446 |
Splits MixxxMainWindow into two pieces: CoreServices and WMainWindow.
This will allow us to iterate on new frontends that do not make use of
QtWidgets / QtGui (such as an Android or iOS port) and generally
enforces a cleaner separation between Mixxx services (provided by
individual manager classes) and the Mixxx UI.
This is also a step towards refactoring the bootup process (which
prompted us to add a loading" launch screen because it's so
slow). With a cleaner concept of "phases" of bootup (construction,
initialize, configure, finalize, destruction) we can start the UI
after construction/initialization and delay the longer tasks
(e.g. connecting audio devices and controllers) or push them onto a
different thread.
Ideally all manager classes and Core will remain buildable with the
QtWidgets module disabled.