-
Notifications
You must be signed in to change notification settings - Fork 2.5k
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
Multi Window support (Floating windows) #10526
Comments
I'm very much in favor of this feature - it would be a vast improvement over the current system, which requires you either to stretch your window to compare code side by side at reasonable sizes, or open multiple instances. The proof of concept is very impressive work. I would suggest that as a first step, we identify the areas of the code that make single-window assumptions and begin the process of refactoring those. That should allow us to validate some of the ideas that we'll need to implement the feature fully at very low risk. |
Thank you very much for your kind feedback, @colin-grant-work. We are currently working with different interested parties to gather enough resources to be able to get this going. |
@colin-grant-work The plan is that we collaborate with @koegel and @sdirix to work on getting phosphor.js out of Theia. We are hoping others will join in to continue the feature as the tech debt is being removed. |
MVP ProposalTo facilitate the development process we analyzed the proposal and distilled a MVP for the multi-window feature which requires significantly less effort than developing the feature in one go. ConceptFor the MVP we suggest to reduce the initial feature set via two measures:
Via the opt-in approach we lay the groundwork to ease the transition for Theia extensions views. They can be polished and enabled step by step. For example the Theia Terminal is a very good candidate for an "MVP++" as it's already managing its styling (almost) completely by itself, and therefore requires minimal adaptions to work in secondary windows. Development TasksStylingAlmost all styling tasks of the original proposal can be skipped for the MVP. For example we don't need to export CSS, neither solve the theme and color syncing (including Monaco services) nor fix other problems present in the PoC. The tasks for the MVP are:
Theia Base FrameworkSome architecture tasks remain for the overall framework, however we don't need to walk through the whole code base to check every view interaction for compatibility with the secondary window approach. The remaining tasks are:
These changes were already partially performed within the PoC and were sufficient to properly support web views. The opt-in mechanism could for example be realized via a TabBar action which is shown for extractable views. Platform specificsThese tasks mostly remain the same:
PhosphorJSBy reducing the scope of secondary windows to only host single views PhosphorJS is almost completely bypassed. By extracting views via a separate action and closing them via the The main remaining task is to modify the Webpack build to disable the document check when attaching Widgets to secondary windows. MonacoMonaco does not need to be touched at all for the MVP, removing a large risk factor. SummaryThis MVP for multi-window support only adds support for web views instead of "Theia views". This is obviously vastly reduced in scope, however in practice Theia based applications often use quite a number of VS Code extensions including web views. We think this would be a great first step to bring the feature to life. Especially as we estimate the effort for the MVP at roughly 20-25 person days with a low to medium amount of risk. Compare this to the 150 person days for the full feature, including some parts which were identified as medium to high risk or which are somewhat blocked (PhosphorJS). A good next step after the MVP could be to opt-in the Theia Terminal. It is architecturally relatively encapsulated and already works pretty well in the PoC. |
Update: We will soon open a PR with an implementation of the MVP as proposed by Stefan earlier. |
Just an FYI, the Arduino IDE v2 uses the Eclipse-Theia platform and a few people have asked for undocking the serial monitor for display on a 2nd monitor. Currently the only solution is opening a 2nd IDE window and opening the serial monitor in that instance. A way to undock would be more elegant. |
@dlarue Implementing this should be fairly straightforward. Adopters need to implement the |
Thanks @msujew , I'll pass this on to the Arduino devs. |
Hello @dlarue,
The full list of secondary window related issues can be found via the secondary-window label. As the contributor of the initial multi window support POC, you can gladly tag me in further questions you have or ask me directly :) |
Is there a way to test this with e.g. theia-blueprint? |
Hello @trozen ,
|
This is no longer a proposal but a reality. We have secondary window support for web views, terminals and now editors. This overarching issue can therefore be closed and remaining functionality gaps be handled in separate tickets. |
Summary
We would like to have fully featured multi window, a.k.a. floating window support in Theia. This issue proposes a specific approach and may serve as the
Epic
to implement this feature in full.We evaluated the approach with a PoC and created an initial list of development tasks. Also we added a rough risk assessment for each of the determined challenges.
We are looking for feedback in regards to the suggested approach and the overall assessments. Feel free to add suggestions on how to solve the determined challenges and please notify us when we missed a whole concept or even only a minor detail.
Goal
Status Quo
Theia offers a "New Window" action which opens an additional window. In this window a complete new Theia frontend is instantiated, including, among others, the inversify container, frontend application and application shell.
The diagram above shows this case in a simplified way. The result is two completely separated frontend instances which do not share the same "UX context", e.g. they don't share a common selection or debugging state. They don't even share the same plugin process on the backend. They almost behave like two completely different instances of the same Theia application, with the difference that they share some singletons via the backend. For example the "running task" list is synchronized between these two frontends via the backend.
Downsides of Status Quo
Overall it resembles a multi instance rather than a multi window approach
Comparison to other frameworks
A good implementation of multi window support can be found in Eclipse RCP.
Here the user is able to detach windows from the main window into (one or more) secondary windows. These share the same context as the main window. In the screenshot above you can see the detached console and debug view which share the same state with the main window. Ideally we would like to see similar behavior in Theia.
Looking at VS Code, multi window support is one of the most requested features for years.
Web technology
The reason why it's non trivial to support this for Theia and why VS Code does not yet offer this feature is the underlying tech stack. By relying on web technologies we also inherit their security model. Windows are almost completely isolated from each other.
By default the only way to communicate between windows is to send messages, either directly between them or via the Theia backend. This means that any shareable state needs to be fully serializable and a synchronization mechanism must be in place. Any functional callback must also be handled via messaging and corresponding proxy handlers.
This requires major architectural changes and influences the whole framework. Therefore a lot of effort is required to get this to work.
Alternative approaches
Before we settled on the suggested approach described below we also discussed alternative approaches.
Expand for more details
DOM Streaming
First on our list was to check whether there exists some DOM streaming techniques by which we would render the views in an invisible way within the main window and just project the results into the secondary windows.
However this was quickly aborted after we did not find a library or existing applications which use such a technique. Additionally there are some conceptual issues regarding the integration of user interaction. Also these might not even be possible for elements like canvas.
Multi window concept as a first citizen
Another more obvious approach is to enrich Theia in generally with the concept of multi window support. As the windows can only communicate via serialized messages, this concept must be baked in for every single window, service and use case handled by Theia.
Moving a widget between windows then requires to close said widget and reinstating the same in the secondary window. Each service the widget consumes, for example a selection service, but also any 3rd-party service must also be provided in the secondary window and behave the same in the secondary window as in the main window.
Conceptually there are then no more "real" singleton injections (each window has it's own Inversify container). A consequence could be that singletons exists in both windows and need to know how to share state. Questions like how to share a dynamically registered callback must then be answered. Another solution could be a parent-child concept for them by which for example only the "child" variant is injected in secondary windows. Depending on the use case this might not be possible transparently and consuming widgets might need to handle both "real" / "parent" and "proxy" / "child" injections.
Use cases need to be adjusted for multi windows too. For example switching the workspace of the main window should also update the workspace of the second window. The same is true for the debugging state, theming etc.. Each use case must be evaluated on their own what it means for them to be distributed over multiple windows and act accordingly.
Very likely this then requires developing not only a main frontend but also a secondary frontend with a reduced application shell and differently registered contributions. These different frontend instances should also use the same plugin host in the backend, to make sure the plugin views and other integrations like LSPs also behave the same between windows. It's also unclear how well the Monaco services can be synced.
Overall we had the impression that this approach requires so many changes to the overall framework that even producing a non-trivial PoC with views which consume at least some services is a huge undertaking. Therefore we went for the suggested approach discussed below.
Suggested approach
Browsers and Electron allow to create new windows which are controlled by the parent. Therefore we can access and manipulate the DOM of the secondary window from the main window.
We suggest to use this feature to render Widgets into secondary windows. Any interactions is automatically handled via the main window and therefore is executed in the same context.
Using this approach allows us to reduce multi window support to a UI problem instead of elevating it to a core principle of the whole Theia framework. There are no additional services or frameworks involved. Most of the existing code doesn't need to be touched and many views work out of the box.
Proof of concept
We developed a proof of concept based on our suggested approach to check its feasibility and to identify challenges and risks and come up with an overall estimation of effort.
The proof of concept is available on branch "multi-window-poc" in our Theia fork. Please see the readme for instructions on how to build and run the PoC.
It showcases multi window support in the Electron example app. Views can be moved into a secondary window via the
Sample menu > Move currently active view to new window
action.The PoC is not particularly polished but shows the feasibility of the suggested approach.
Identified challenges
PhosphorJS
For the PoC we removed a single line check in PhosphorJS
Styling
For the PoC we modified the frontend build one time to extract all CSS into a standalone stylesheet. This stylesheet is then loaded in secondary windows. We also execute Monaco loading in the second window to get the Monaco CSS.
Javascript Global Access
Theia code often makes use of Javascript globals like
window
anddocument
. This may break functionality in secondary windows.For example let's say a Widget renders a
Button
and some other element like aSearchbar
. On click theSearchbar
shall be cleared. As the callback code in the widget does not have direct access to the Searchbar the access may have been implemented by using thedocument
global like this:This breaks with our suggested approach, as the
document
of the Main window actually does not contain theSearchbar
. Instead it's rendered in the DOM of the secondary window. We can't do any tricks here like extending the behavior ofdocument
, as these global variables are especially protected and can't be modified.Code like this needs to be refactored for the suggested approach to work. In general, and especially when using React, it should be avoided to manipulate DOM elements directly.
However there might be cases where this is required or it would afford a lot of effort to be refactored. Luckily most code can also be adjusted by avoiding the global access, for example like this:
By using
this.node.ownerDocument
instead ofdocument
within a widget the code can be generalized. Of course this fix might not apply to all situations, for example when accessing the DOM outside of a widget, but similar workarounds could be implemented.In the PoC we added this fix for the searchbar clear button in the preferences widget
Views contributed by Plugins (VS Code extensions)
Conceptually these are the easiest views as they are completely encapsulated already anyway. To get them to work in secondary windows they just need to be connected properly.
Main window and the webview host (this is not the plugin host!) communicate via Window messages. These messages must be relayed between the main window and second window.
In the PoC we added a simple broadcasting in which all messages are relayed to all secondary windows and back to the main window
Monaco Editor
In the PoC: Moving a Monaco editor into a secondary window results in non-highlighted text which does not allow modifications.
window
,document
andmonaco
globals.Development Tasks
This sections lists a non-exhaustive list of development tasks for each of the overall topics
Styling
Theia Base Framework
ApplicationShell
with the notion of widgets residing in secondary windowsPlatform specifics
PhosphorJS
As an additional challenge we can't just upstream PhosphorJS changes as the project is archived and no longer under development. A workaround could be source level adaptions during the webpack build however this is probably not ideal on the long run.
Monaco
Background: Monaco is not built for the use case of rendering within a secondary DOM
In the PoC Monaco editors are rendered read only and permanently show an insert mouse icon on hover
Risk assessment
We don't expect any conceptual problems in regards to the development topics Styling, Theia Base Framework and Platform specifics.
There is medium risk in regards to PhosphorJS as we don't know about unknowns within Phosphor which could increase the effort for a polished experience by a lot and we need some solution to its development situation.
It's unclear how much effort would be needed to generalize Monaco and get it to work in secondary Theia windows. It's also unclear whether Microsoft would even accept these changes. Maybe there are alternative approaches with secondary Monaco instances in secondary windows to solve this problem differently which could also be evaluated. Therefore there is a high risk for a lot of effort which is currently hard to estimate.
There is a low risk of the Window API being modified in Chrome or other Browsers to disallow the amount of access we need to successfully use this feature. The API exists for a very long time and is similar to the one of IFrames. Removing the Window API would break a lot of web pages, however certainly not the majority. Therefore this risk can't be discarded completely.
Summary
Implementing multi window support with the suggested approach requires some work. However, except for Monaco, most of the work seems to have no conceptual risk and "just needs to be done". Overall the approach of implementing multi window support via the UI seems to encapsulate it rather well and does not require major architectural refactorings of the Theia framework.
Monaco is the most risky part however it's also the only one which could be considered optional. Having a polished multi-window feature without being able to place Monaco based views in secondary windows is already very useful.
We roughly estimated the effort to implement this in full in a clean and secure way to be in order of magnitude of 150 person days. However the work can be parallelized to a high degree and the feature could be released in an iterative manner, reducing the amount of work for the first iterations.
Going forward
We are looking for feedback in regards to the suggested approach and the overall assessments. Feel free to add suggestions on how to solve the determined challenges and please notify us when we missed a whole concept or even only a minor detail.
We also can't stem the work on this feature on our own and are therefore looking for volunteers to take over parts of the work. From our point of view implementing this feature would add a lot of value to the Theia framework and many adopters would benefit from it.
The text was updated successfully, but these errors were encountered: