godot icon indicating copy to clipboard operation
godot copied to clipboard

Implement extend to title for Windows and Linux

Open Hilderin opened this issue 1 year ago • 29 comments

  • Implements proposal https://github.com/godotengine/godot-proposals/issues/4846

This PR implements the EXTEND_TO_TITLE flag for Windows and Linux X11. Implementing this flag allows Windows and Linux to use the editor without the default title bar. Additionally, it makes it possible to use this flag in any Godot project outside the editor.

Since Windows and Linux don’t natively support this mode, it is "simulated" by providing a resizable borderless window with minimize, maximize, and close buttons rendered directly in the Window class. New properties were added to the Window Theme to define the button icons, positions, and styles.

Here’s a little demo:

Windows:

https://github.com/user-attachments/assets/520e4e41-4682-43b8-b307-26b0521cd5b3

Linux: image

image

Hilderin avatar Aug 30 '24 02:08 Hilderin

I'm not sure if we want a separate flag for it, might be better to merge it with FEATURE_EXTEND_TO_TITLE (it's the same, but OS draw the buttons) and move window min/max/close buttons from a separate controls to Window class (for non macOS).

bruvzg avatar Aug 30 '24 08:08 bruvzg

I've been working on the same feature for the past few days and have a few questions.

  1. I wonder if we really need to add a new flag instead of using the existing WINDOW_FLAG_EXTEND_TO_TITLE, which is already widely used in the MacOS implementation.
  2. As shown in the screenshot below, I believe your implementation may not work on Windows 7/10 when the editor is in windowed mode, as it could result in a white border around the window. You may need to leverage the DWM APIs to resolve this issue.
  3. Additionally, the project manager window should have the same no-title-bar appearance when the corresponding setting is enabled.

image

bughandler avatar Aug 30 '24 09:08 bughandler

I'm not sure if we want a separate flag for it, might be better to merge it with FEATURE_EXTEND_TO_TITLE (it's the same, but OS draw the buttons) and move window min/max/close buttons from a separate controls to Window class (for non macOS).

That's a interesting suggestion, I'll think about it. It should be easier to implement in the Project Manager or other windows in the future if the buttons are drawn directly in the Window class. I thought it could be interesting for games/app created with Godot to be able to create resizable without without the window min/max/close buttons. It could be added later.

Hilderin avatar Aug 30 '24 11:08 Hilderin

I wonder if we really need to add a new flag instead of using the existing WINDOW_FLAG_EXTEND_TO_TITLE, which is already widely used in the MacOS implementation.

I'll look into it, bruvzg made the same suggestion.

As shown in the screenshot below, I believe your implementation may not work on Windows 7/10 when the editor is in windowed mode, as it could result in a white border around the window. You may need to leverage the DWM APIs to resolve this issue.

I'm curious how you implemented it.

Additionally, the project manager window should have the same no-title-bar appearance when the corresponding setting is enabled.

Indeed.

Hilderin avatar Aug 30 '24 11:08 Hilderin

I'm curious how you implemented it.

FYI: https://learn.microsoft.com/en-us/windows/win32/dwm/customframe

The screenshot below shows the project manager window run in windowed mode on Windows 10, notice the shadow around the window. image

bughandler avatar Aug 31 '24 08:08 bughandler

I fixed the issue with the white border on top of the window on Windows 7/10. Thanks bughandler!

If you want to work on that together @bughandler, I'm available in the Godot Contributors Chat: https://chat.godotengine.org

Hilderin avatar Aug 31 '24 15:08 Hilderin

@bruvzg I was working on using the already existing flag WINDOW_FLAG_EXTEND_TO_TITLE and implementing the rendering of the window buttons directly in the Window class. I have no problem using this flag, but I'm concerned about rendering the buttons directly in the Window class.

Should I create a control for that and add it to the scene? That would be the easiest way, but my concern is that these controls would be present in the scene tree at runtime for any project that uses WINDOW_FLAG_EXTEND_TO_TITLE.

The other alternative could be to manage the rendering manually, like in Viewport::_sub_window_update, but that seems to be very complex, especially for handling mouse over, clicks, etc.

What’s the best approach?

Hilderin avatar Aug 31 '24 16:08 Hilderin

Added support for Linux x11...

image

image

Hilderin avatar Sep 08 '24 01:09 Hilderin

I can help with a Wayland port BTW ;)

I really hope that a good way is found for making CSDs global (or at least have some builtin fallback) as some Wayland desktop environments enforce them and we currently depend on libdecor which is quite unflexible.

deralmas avatar Sep 08 '24 17:09 deralmas

@Riteo I would certainly appreciate your contribution for the Wayland port!

For the CSDs, I'm currently tinkering with the idea to implement them directly into the Window class. I guess adding the title and options to move the window directly there for Wayland could be added afterward.

Hilderin avatar Sep 08 '24 18:09 Hilderin

After some work, I was able to put the rendering of the window buttons directly in the Window class. I added some properties to Window Theme to handle the styles and the position of the buttons. I reverted most of the modifications in EditorNode because Windows and Linux implementation are now closer to the macOS implementation. The method window_is_extend_to_title_show_window_buttons in DisplayServer is used to know if the windows buttons are rendered by the OS or if Godot needs to rendered them. Only DisplayServerMacOS::window_is_extend_to_title_show_window_buttons returns true.

Having a decoration_canvas now directly in the Window class could be used in the future to a full custom title bar for Wayland.

Here is a test project to test some Window settings at runtime: test-godot-window-different-types.zip

Hilderin avatar Sep 15 '24 22:09 Hilderin

This is amazing!

I can't see in the video, but I'm assuming the windows in play mode / exported game are draggable as well. Are they? By the "title" area or by the entire window? Only on empty space?


I'd also like to repeat my suggestion from before. This serves to not lose information in this mode, while still making the best use of the space:

Add the icon and project name (the part that would show on the titlebar) at the top-left: You could use the project name to replace the "Project" menu and show it before the other menus

So, ideally the menu part on the top left could be like this: 🟦 My Super Game ▼ | Scene | Debug | Editor | Help Using "My Super Game" as the project name, and 🟦 to represent either a Godot icon or the Project's icon.

There's no need to repeat the scene name and (*) dirty state that are already on the tabs. Merging the project name with the Project menu makes total sense, as long as you add a ▼ symbol to make it obvious that you can click it as a menu. It's also better to have it before the Scene menu, and you can then move the out-of-place Quit command to this Project menu, right below Quit to Project List where it belongs.

geekley avatar Sep 17 '24 03:09 geekley

Shouldn't buttons use the same color as background around them? Right now they oddly stand out.

KoBeWi avatar Sep 17 '24 13:09 KoBeWi

Shouldn't buttons use the same color as background around them? Right now they oddly stand out.

Yes, I think we could get rid of their background colors (when not hovered) too. This would better match Windows' UI appearance in particular.

Calinou avatar Sep 17 '24 13:09 Calinou

Thank you for implementing generic CSDs! I'm already concocting a Wayland port. Resizing was pretty easy (Wayland is built with CSDs in mind) but I'm having issues understanding how to move the window when dragging the "title bar". I can't catch events in a rect otherwise I'd be causing issues to all UI under it, so how am I supposed to catch empty the empty title bar space like in the video?

deralmas avatar Sep 17 '24 22:09 deralmas

In "Extend to ttitle" mode, the moving of the window when dragging the "title bar" is not done in the DisplayServer, it's done into the EditorTitleBar. Effectively, it's would be very difficult to know what is an "empty space" or not from the DisplayServer. If you are trying to implement a complete custom title bar while not in "Extend to title" mode, I guess you can catch the events in the rect corresponding to the size of the title bar.

Hilderin avatar Sep 17 '24 22:09 Hilderin

I can't see in the video, but I'm assuming the windows in play mode / exported game are draggable as well. Are they? By the "title" area or by the entire window? Only on empty space?

Like to comment just before, in the "Extend to title" mode, you will have to implement your own window move because it's impossible to tell exactly what is an empty space or not, also you could want to implement a full size draggable window if you want. It should be pretty say in GDScript to implement the window movement using mouse events.

So, ideally the menu part on the top left could be like this: 🟦 My Super Game ▼ | Scene | Debug | Editor | Help Using "My Super Game" as the project name, and 🟦 to represent either a Godot icon or the Project's icon.

I'm concerned with the compatibility when Godot is not in "Extend to title" mode. Also, it's not the way it works on macOS. I would like to know what others think about about.

Hilderin avatar Sep 17 '24 22:09 Hilderin

In "Extend to ttitle" mode, the moving of the window when dragging the "title bar" is not done in the DisplayServer, it's done into the EditorTitleBar.

Ooooh so it's already implemented. Gotcha. Too bad that this class won't work as-is on Wayland since it wants a "please start moving" command. We can't override the window position manually.

Not too much of an issue though, I don't think that anybody would be against a generic "start move operation" DS method or something like that. This can be improved or at least discussed later.

If you are trying to implement a complete custom title bar while not in "Extend to title" mode

I'm not yet digging into that but as you said the decoration canvas work is fundamental for "non-extend-to-title" decorations. I can give a stab at them later, even just implementing only this feature will be very nice for now.

I'll polish the thing up and send you a patch soon™. I'm a bit... chaotic.

I also found a weird bug: the decorations kinda distort when any form of pillar/letterboxing gets applied to the canvas. Just try setting "keep" to the "display/window/stretch/aspect" project setting.

deralmas avatar Sep 17 '24 22:09 deralmas

I'm concerned with the compatibility when Godot is not in "Extend to title" mode. Also, it's not the way it works on macOS. I would like to know what others think about about.

@Hilderin Ah, I'm making this suggestion not just for this mode, but in general, even when the normal OS titlebar is there. If it's implemented, it should look like that consistently. I don't use macOS, so I don't know the implications in this case.

geekley avatar Sep 17 '24 22:09 geekley

@Calinou I changed a bit the icons to be smaller and less "chunky" (1 pixel path width instead of 2 pixels). Now that the window icons are not aligned with the buttons in Godot, having a different style was essential because it look just not aligned. The buttons are now 32x32. It's like that in Steam, I personally like the smaller buttons, it saves a couple of pixels, but I can make them the same size as the default Windows 11 size. Also removed the background when not hover the buttons.

image

When maximized: image image

What do you think?

These changed are not pushed yet, I still need to fix the full screen mode, the margin to put the menu in the corner, the border in splash screen of the Project Manager, and the distorting bug when any form of pillar/letterboxing is applied.

Hilderin avatar Sep 23 '24 10:09 Hilderin

Made some fixes/adjustments:

  • Fixed fullscreen mode where the space for the buttons was left empty.
  • Fixed issue when exiting fullscreen mode where the buttons were not visible again.
  • Fixed Project Manager and Editor showing a border for a brief period during startup.
  • Made the icons for Minimize, Maximize, and Restore a bit smaller.
  • Adjusted the button size depending on spacing settings in the editor.
  • Fixed an empty line at the bottom when maximized at startup.
  • Fixed Right-To-Left layout.
  • Fixed stretch mode.

Default theme: image

Compact: image

No spacing at all: image

Fullscreen mode: image

Right-to-Left: image

@Calinou This should fix everything you mentioned in your previous post, except for moving the main menu to the top-left corner. There are already some settings in the editor to specify spacing, and the editor uses these to define the global margin. I'm not sure I want to change that behavior in this PR?!? image

Hilderin avatar Sep 24 '24 01:09 Hilderin

Hi, I finally have a patch for Wayland. You can find it in my branch: https://github.com/Riteo/godot/commit/wayland-no-title-bar/

I had trouble adding drawing tablet support on sway so I left that out for now.

Also keep note that if the backend detects and uses libdecor, our current "stopgap" decoration library, it won't be able to disable borders on natively decorated windows due to an upstream bug. #96825 would be useful in this case.

deralmas avatar Sep 25 '24 23:09 deralmas

Needs a rebase after #97333.

Geometror avatar Oct 04 '24 12:10 Geometror

Rebased to fix conflict with master and fix a transparent line at the bottom when starting in extend to title mode and maximized on Windows.

Hilderin avatar Oct 04 '24 15:10 Hilderin

@Geometror

While the project manager is working for me, opening a project results in a fully transparent window on Win11.

First, thanks for testing it! Second, that's weird ;) Can you share with me your editor_settings file, there's probably something that interfere. You can find it here: C:\Users[username]\AppData\Roaming\Godot\editor_settings-4.4.tres

Can you try restarting the editor after you move all the editor_settings*.tres somewhere else? Just to test if there's really a setting that causes the issue.

Another possibility could be a wrong settings in .godot\editor\editor_layout.cfg in your project folder. This is the file can keeps the position and the state of the last time the editor was used and Godot tries to reapply these settings on startup. Can you also share the with and retry if you move or rename this file?

Also, do you have multiple monitors??

Hilderin avatar Oct 04 '24 16:10 Hilderin

System info: Windows 10.0.22631(Windows 11 23H2) - Vulkan (Forward+) - dedicated NVIDIA GeForce RTX 3060 Laptop GPU (NVIDIA; 31.0.15.4692) - 12th Gen Intel(R) Core(TM) i7-12700H (20 Threads) Main screen: 2560x1600, 165Hz Second screen: 1920x1080, 60Hz

The problem persist even on a fresh config (removed C:\Users[username]\AppData\Roaming\Godot folder).

I have a monitor connected to my laptop right now, which seems to cause the issue: the editor becomes visible when I disconnect the monitor.

Geometror avatar Oct 04 '24 17:10 Geometror

Thanks a lot, that is very helpful, I'll look into it.

Hilderin avatar Oct 04 '24 17:10 Hilderin

Thanks for the review @Mickeon, I made the suggested modifications the best I can.

Hilderin avatar Oct 20 '24 23:10 Hilderin

The project manager that extends to titles is not a good experience under Linux X11:

  1. Moving the window and changing the window size will not trigger desktop effects, such as window shaking.
  2. Moving the window isn't smooth and the cursor style doesn't change.
  3. The delay in changing the window size is very high.

Maybe it should call the x11 start moving window and start resizing api, instead of directly setting the window position and size?

This pr:

https://github.com/user-attachments/assets/d04c8a6b-ebe5-4a3f-b4ee-b710f202408b

My experimental project:

https://github.com/user-attachments/assets/e8c99d41-454d-405d-9ad1-3649c9a7f069

My project code: 图片

scgm0 avatar Oct 21 '24 01:10 scgm0

Perhaps the window dragging and resizing in this pr can be replaced using the api provided by these two pr's? https://github.com/godotengine/godot/pull/100532 https://github.com/godotengine/godot/pull/100464

scgm0 avatar Dec 19 '24 17:12 scgm0