Skip to content

Change main screen plugins into docks - #113051

Open
KoBeWi wants to merge 1 commit into
godotengine:masterfrom
KoBeWi:is_this_possible_to_learn_this_power
Open

Change main screen plugins into docks#113051
KoBeWi wants to merge 1 commit into
godotengine:masterfrom
KoBeWi:is_this_possible_to_learn_this_power

Conversation

@KoBeWi

@KoBeWi KoBeWi commented Nov 22, 2025

Copy link
Copy Markdown
Member

As a continuation of the new dock system, this PR changes main screen editors into docks.

godot.windows.editor.dev.x86_64_bTnIQTeSQ3.mp4

As a result:

  • Main screen is registered as an available dock slot and dock layout
  • Main screen editors are no longer tied to a specific plugin, they are just regular EditorDocks
  • The old main screen plugin workflow is deprecated. It's still supported, but compatibility might be broken in some edge cases
  • Main screen docks have their own editor setting for tab style
  • All main screens can float*
    • *Except Game, which has a custom floating behavior with a very tightly integrated WindowWrapper that can't simply be removed
  • All main screens can be closed

_has_main_screen() still exists in EditorPlugin and plugins that have a main screen are still "separate". However I'm not sure how much difference does it make. Like, ideally the method should return true if the plugin has a dock located in the main screen (so not floating or moved elsewhere), but from my testing it does not really matter.

EDIT:
Closes godotengine/godot-proposals#14807

@KoBeWi KoBeWi added this to the 4.x milestone Nov 22, 2025
@Mickeon

Mickeon commented Nov 22, 2025

Copy link
Copy Markdown
Member

This would genuinely address many miscellaneous proposals and make the editor almost fully modular. Let's make it more than a proof-of-concept.

@davifoox

davifoox commented Nov 25, 2025

Copy link
Copy Markdown

I'm really looking forward to this!
Making "everything a dock" will improve workflow so much!

I think the positioning of the opened scenes tabs should be more like in this proposal: #12471

@KoBeWi
KoBeWi force-pushed the is_this_possible_to_learn_this_power branch from 0ff9f83 to b9a0b07 Compare December 8, 2025 16:34
@KoBeWi
KoBeWi force-pushed the is_this_possible_to_learn_this_power branch from b9a0b07 to 8a6d6c7 Compare December 12, 2025 15:34
@KoBeWi

KoBeWi commented Dec 12, 2025

Copy link
Copy Markdown
Member Author

I pushed compatibility code. It's somewhat awkward, because the usual workflow with main screens is that you add the dock as a child of a dedicated node and its data is available via virtual methods in EditorPlugin. I replaced that special control with a new one that intercepts added children and moves them to a dock. Unfortunately there are edge cases that are not 100% compatible:

  • You need to add the main screen control in plugin's _enter_tree() or related callback. This is usually a case, but I have a main screen plugin that waits one frame before adding. It broke xd
  • You can no longer remove the main screen control from the "dedicated main screen parent", because it's actually in a different parent. If any plugin does that, it will print an error. Although you can just do queue_free(), so probably not a problem.

@KoBeWi
KoBeWi force-pushed the is_this_possible_to_learn_this_power branch from 8a6d6c7 to 88d5118 Compare December 17, 2025 22:58
@KoBeWi

KoBeWi commented Dec 20, 2025

Copy link
Copy Markdown
Member Author

So after more changes there is yet another compatibility breakage, and this time a rather major one. Since the main screen docks are no longer associated with a specific plugin, changing main screen tab no longer calls make_visible() and selected_notify(). I can add some super very hacky code to handle it for legacy plugins, but I'm not sure if it's worth it. It would be very ugly.

@KoBeWi
KoBeWi force-pushed the is_this_possible_to_learn_this_power branch 2 times, most recently from c97df15 to bbcff61 Compare December 20, 2025 07:21
@KoBeWi
KoBeWi force-pushed the is_this_possible_to_learn_this_power branch from bbcff61 to 6aa1e6c Compare December 23, 2025 10:04
@KoBeWi
KoBeWi force-pushed the is_this_possible_to_learn_this_power branch 2 times, most recently from 5914a67 to a9afdc8 Compare February 7, 2026 23:02
@KoBeWi
KoBeWi force-pushed the is_this_possible_to_learn_this_power branch 6 times, most recently from cc303d3 to ab481c4 Compare February 18, 2026 12:24

@KoBeWi KoBeWi left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be finished now. This is definitely the most intrusive part of the dock rework (compared to bottom panel and other docks), but it also allowed to simplify some parts of the code, like the screens are no longer accessed by name or index, but directly as the docks.

Definitely needs testing, I'm not 100% sure that all signals and callbacks work the same as before (at least the exposed ones; some internals were changed and are expected to be different). There is some minor compatibility breakage, see my previous comment.

virtual String get_plugin_name() const override { return TTRC("2D"); }
bool has_main_screen() const override { return true; }
virtual String get_plugin_name() const override { return "2D"; }
bool has_main_screen() const override { return canvas_item_editor->get_current_layout() == EditorDock::DOCK_LAYOUT_MAIN_SCREEN; }

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure how much has_main_screen() is relevant anymore. There is some difference between main screen plugins and regular plugins, but I think it does not matter that much?

Comment thread editor/editor_main_screen.cpp Outdated
Button *button = Object::cast_to<Button>(button_hb->get_child(i));
if (button->get_text() == "Script") {
// Selected button is at or after the Script button.
// Only allow auto-switching if the selected tab is to the left of the Script tab.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code is so arbitrary and probably not relevant anymore, when you can reorder the tabs 🤔

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, The intent was to allow adding plugins that should switch in #104010, even though inserting them there wasn't completely supported.

There should be some kind of flag on the dock can_auto_switch or something that is true for 2D/3D and false for others.
Though its only used when its in the main screen.

}
if (button->get_text() == selected_plugin->get_plugin_name()) {
// Selected button is before the Script button.
if (dock->get_display_title() == selected_plugin->get_plugin_name()) {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not really true anymore .-. (although happens to work for the default main screens)

virtual void set_plugin_version(const String &p_version);
virtual bool has_main_screen() const;
virtual void make_visible(bool p_visible);
virtual void selected_notify() {} //notify that it was raised by the user, not the editor

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can't be reasonably called anymore.
Also the comment wasn't really true I think. I used make_visible() instead.

@KoBeWi
KoBeWi marked this pull request as ready for review February 18, 2026 13:26
@KoBeWi
KoBeWi requested a review from a team as a code owner February 18, 2026 13:26
@KoBeWi
KoBeWi force-pushed the is_this_possible_to_learn_this_power branch from 2dab5ca to f2da3f5 Compare August 17, 2026 10:41

@AdriaandeJongh AdriaandeJongh left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The last remaining issue I had was fixed! This PR looks good from a usability standpoint:

  • If you close a main dock, then you can reopen it using the Editor > Editor Docks menu.
  • If the Game dock is set to float on run, you can leave it out of the tabs at the top. Nice and clean.
  • Ability to reordering the main docks is nice.

Very soon, users will want to be able to split the main dock..... 😏

In my review, I didn't look at the code. I also didn't look at how backward compatibility is maintained for plugins, and I suspect that'll be important with this PR.

@KoBeWi

KoBeWi commented Aug 18, 2026

Copy link
Copy Markdown
Member Author

Apparently we have a tutorial for main screen plugins: https://docs.godotengine.org/en/stable/tutorials/plugins/editor/making_main_screen_plugins.html

It's going to be outdated once this PR is merged.

@bruvzg bruvzg left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Breaks window dragging on macOS:

Image

Previously red areas were usable as title bar to drag window, with this PR, only green part can be used. The rest is likely covered by tab control.

@KoBeWi

KoBeWi commented Aug 18, 2026

Copy link
Copy Markdown
Member Author

Would it work if the mouse filter of the TabBar was set to PASS?

@AdriaandeJongh

AdriaandeJongh commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Would it work if the mouse filter of the TabBar was set to PASS?

No, because then you drag the window and the tab at the same time, which is totally borked behavior.

@kitbdev kitbdev left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ScriptEditor and AssetStore need margins. (only when not floating)

Image

If 2D and 3D is closed then switching to a scene with a 2d root node causes errors like:

  ERROR: Node not found: "/root/@EditorNode@20438/@Panel@14/@Control@67/2D/@VBoxContainer@9920/@VSplitContainer@9925/@HSplitContainer@9927/@HSplitContainer@9929/@Control@9930/@SubViewportContainer@9931/@SubViewport@9932/Node2D" (absolute path attempted from "/root/@EditorNode@20438/@Panel@14/@VBoxContainer@16/DockVSplitMain/DockHSplitMain/DockVSplitLeftR/DockSlotLeftUR/Scene/@VBoxContainer@5305/@MarginContainer@5368/@SceneTreeEditor@5412").

When reloading the editor and the open scene has a 2d/3d root node, the 2d/3d editor gets opened even if a different one was last open.

Comment thread doc/classes/EditorInterface.xml Outdated
Comment thread editor/script/script_editor_plugin.cpp
Comment thread editor/run/game_view_plugin.cpp Outdated
Comment thread editor/docks/inspector_dock.cpp Outdated
Comment thread editor/script/script_editor_plugin.cpp

@DaveTheEggman DaveTheEggman left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few nitpicks, will try to review the implementation & test it later on

Comment thread doc/classes/EditorDock.xml Outdated
Comment thread editor/docks/editor_dock.cpp
@bruvzg

bruvzg commented Aug 19, 2026

Copy link
Copy Markdown
Member

Would it work if the mouse filter of the TabBar was set to PASS?

It will work if TabBar is modified to consume left click events on buttons.

diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 1383c6a314..96b2e6b8c1 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -8913,6 +8913,7 @@ EditorNode::EditorNode() {
        editor_main_screen = memnew(EditorMainScreen);
        srt->add_child(editor_main_screen);
        title_bar->set_center_control(editor_main_screen->get_internal_container());
+       editor_main_screen->get_tab_bar()->set_mouse_filter(Control::MOUSE_FILTER_PASS);

        editor_dock_manager->register_dock_slot(editor_main_screen);

diff --git a/scene/gui/tab_bar.cpp b/scene/gui/tab_bar.cpp
index 17f7cdff87..e447ac975c 100644
--- a/scene/gui/tab_bar.cpp
+++ b/scene/gui/tab_bar.cpp
@@ -220,6 +220,10 @@ void TabBar::gui_input(const Ref<InputEvent> &p_event) {
                        }
                }

+               if (hover != -1 && mb->get_button_index() == MouseButton::LEFT) {
+                       accept_event();
+               }
+
                if (rb_pressing && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
                        if (rb_hover != -1) {
                                emit_signal(SNAME("tab_button_pressed"), rb_hover);

@KoBeWi
KoBeWi force-pushed the is_this_possible_to_learn_this_power branch from f2da3f5 to 2e57c61 Compare August 19, 2026 11:59
@KoBeWi KoBeWi modified the milestones: 4.x, 4.8 Aug 19, 2026

@YeldhamDev YeldhamDev left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems that everything is working fine.

Shader editor also has this button, despite being a dock. I think it's because they got unified. I can remove it.

It would be for the better.

@kitbdev kitbdev left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clicking on a script error in the Output dock does not switch to or focus the ScriptEditor (even if it isn't floating).

Multiple more places don't focus the ScriptEditor when it is floating, previously they did.
Opening a script from the filesystem or scene dock.
Clicking on debugger breakpoint, or from breakpoint hit when running.
Or EditorInterface.set_main_screen_editor("Script").

Comment thread editor/script/script_editor_plugin.cpp Outdated
Comment thread editor/script/script_editor_plugin.cpp Outdated
Comment thread editor/script/script_editor_plugin.cpp
Comment thread editor/asset_library/asset_library_editor_plugin.cpp
Comment thread editor/script/script_editor_plugin.cpp
@KoBeWi

KoBeWi commented Aug 20, 2026

Copy link
Copy Markdown
Member Author

Multiple more places don't focus the ScriptEditor when it is floating, previously they did.

Should be fixed now.

@kitbdev kitbdev left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trying to open ProjectManager crashes.

Comment thread editor/editor_log.cpp Outdated
@Saul2022

Copy link
Copy Markdown

Looking like a great change ,though weirdly enough while the latest merged pr ( specular directional lightmap) works, i can't seem to be able to open godot with this pr in both mac and in the android editor ( i am using the artifacts from the check tab). It might not be this pr's fault , but it's weird that the master branch opens correctly.

Comment thread doc/classes/EditorInterface.xml Outdated
Comment thread editor/asset_library/asset_library_editor_plugin.cpp Outdated
Comment thread editor/script/script_editor_plugin.cpp Outdated
Comment thread editor/editor_main_screen.cpp Outdated
Comment thread doc/classes/EditorInterface.xml Outdated
Comment thread editor/script/script_editor_plugin.cpp Outdated
Comment on lines -178 to 189
if (selected_plugin == new_editor) {
void EditorMainScreen::select_next() {
if (get_tab_count() == 0) {
return;

@kitbdev kitbdev Aug 21, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The auto switch isn't working, clicking 2D and 3D nodes doesn't switch between 2D and 3D on default layout. It seems like it is only working for tabs after Script.
I think the "before script" thing can be dropped, it should be based on the type of editor not the current order. And any plugins that used it would have inserted it as a button or something that won't work now anyway.

Edit: Github doesn't like commenting in this file or something, I meant this to be on EditorMainScreen::can_auto_switch_screens.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The return value for was_script_tab was reversed.

it should be based on the type of editor not the current order.

How would that work?
I think this hack is fine for now, as it's closest to the previous behavior. It can be tweaked later; it sounds like something more involved. There is also https://github.com/godotengine/godot/pull/113051/changes#r2821748038

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now all tabs can auto switch except for Script.
Sure, it can be fixed later.

I was thinking EditorDock would have a bool for it, false for everything but 2D and 3D.
Not sure if it needs to be exposed immediately.

@kitbdev kitbdev left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested, looks good.

@syntaxerror247 syntaxerror247 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TitleBar is still broken in Android editor.

Image

@KoBeWi

KoBeWi commented Aug 22, 2026

Copy link
Copy Markdown
Member Author

Try now. I couldn't reproduce it, but I changed the TabBar centering to be more independent of the layout. macOS may need re-testing too.

@syntaxerror247

Copy link
Copy Markdown
Member

Try now. I couldn't reproduce it, but I changed the TabBar centering to be more independent of the layout. macOS may need re-testing too.

TitleBar looks good now but Game button is missing. On Android, we don't show the default Game window but still use that button to show the Android's Game window implementation. Needs to bring back that Game button.

@KoBeWi

KoBeWi commented Aug 22, 2026

Copy link
Copy Markdown
Member Author

Android's Game window implementation

What is that exactly?

The docks are in a TabContainer, so floating or closed docks are not going to show. You can open such docks from Editor > Docks menu. If it really has to be a tab, and the dock can't be added to TabContainer, then it needs some fake dock that makes the actual Game screen appear. Or it can be part of touch actions panel, idk.

EDIT:
Ok I checked it with the Android artifacts. Seems like the dock is not even registered, so it does not appear in Docks menu. This makes adding a fake dock easier, so guess I'll do that.

@syntaxerror247

Copy link
Copy Markdown
Member

Android's Game window implementation

What is that exactly?

It's a panel rendered using Android views.

Screenshot_20260823_140904

The docks are in a TabContainer, so floating or closed docks are not going to show. You can open such docks from Editor > Docks menu. If it really has to be a tab, and the dock can't be added to TabContainer, then it needs some fake dock that makes the actual Game screen appear. Or it can be part of touch actions panel, idk.

EDIT: Ok I checked it with the Android artifacts. Seems like the dock is not even registered, so it does not appear in Docks menu. This makes adding a fake dock easier, so guess I'll do that.

Yeah, creating a fake dock sounds good to me. We just need main_screen_changed signal when Game tab is pressed.

Co-authored-by: =?UTF-8?q?Pa=CC=84vels=20Nadtoc=CC=8Cajevs?=
 <7645683+bruvzg@users.noreply.github.com>
@KoBeWi

KoBeWi commented Aug 23, 2026

Copy link
Copy Markdown
Member Author

Ok, added the fake dock. The implementation might not be the best, but it works.

@syntaxerror247 syntaxerror247 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good now!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: For team assessment

Development

Successfully merging this pull request may close these issues.

Add an option to customise the style of Main Screen Buttons