Replace TerminalSettings runtimeclasses with interfaces only #1200

Closed
opened 2026-01-30 22:18:57 +00:00 by claunia · 10 comments
Owner

Originally created by @DHowett-MSFT on GitHub (May 17, 2019).

Originally assigned to: @carlos-zamora on GitHub.

TerminalSettings.dll exists because it is difficult to coerce the C++/WinRT build infrastructure to produce a type library and a set of headers without either statically linking (which rolls up the generated types into the consuming project) or dynamically linking (which forces us to put a DLL on disk).

I posit that the ideal representation of settings is the ICoreSettings and IControlSettings interfaces only. No classes need to be implemented in TerminalSettings.dll, because all they'd do is ferry data back and forth.

By dropping the classes and switching to the interfaces, we can remove the setters from the interfaces, and remove the runtime classes completely. Cascadia (or TerminalApp::<something>) can implement ICoreSettings and IControlSettings as views over existing profile data.

This will reduce both the number of runtime hops required for loading and saving settings and the number of code authoring hops required for adding new settings.

Approach

  • #7139: Introduce/Move TerminalApp bridge
    • Move TerminalSettings::TerminalSettings to TerminalApp::TerminalSettings
  • #7140: Move TerminalSettings interfaces
    • Move TerminalSettings::ICoreSettings to TerminalControl project
    • Move TerminalSettings::IControlSettings to TerminalControl project
  • #7141: Transform TerminalApp settings objects into WinRT objects
    • Profile
    • ColorScheme
    • GlobalSettings
    • Keybindings (this may be moved out to be its own PR)
  • Move the new WinRT settings objects into TerminalSettings project
    • I'll close the scenario when this is complete
Originally created by @DHowett-MSFT on GitHub (May 17, 2019). Originally assigned to: @carlos-zamora on GitHub. **TerminalSettings.dll** exists because it is difficult to coerce the C++/WinRT build infrastructure to produce a _type library_ and a set of headers without either statically linking (which rolls up the generated types into the consuming project) or dynamically linking (which forces us to put a DLL on disk). I posit that the ideal representation of settings is the `ICoreSettings` and `IControlSettings` interfaces _only_. No classes need to be implemented in TerminalSettings.dll, because all they'd do is ferry data back and forth. By dropping the classes and switching to the interfaces, we can remove the setters from the interfaces, and remove the runtime classes completely. Cascadia (or `TerminalApp::<something>`) can implement `ICoreSettings` and `IControlSettings` as views over existing profile data. This will reduce both the number of runtime hops required for loading and saving settings and the number of code authoring hops required for adding new settings. ## Approach - [x] #7139: Introduce/Move TerminalApp bridge - Move `TerminalSettings::TerminalSettings` to `TerminalApp::TerminalSettings` - [x] #7140: Move `TerminalSettings` interfaces - Move `TerminalSettings::ICoreSettings` to TerminalControl project - Move `TerminalSettings::IControlSettings` to TerminalControl project - [ ] #7141: Transform TerminalApp settings objects into WinRT objects - Profile - ColorScheme - GlobalSettings - Keybindings (this may be moved out to be its own PR) - [ ] Move the new WinRT settings objects into TerminalSettings project - I'll close the scenario when this is complete
Author
Owner

@zadjii-msft commented on GitHub (May 17, 2019):

So that's what I tried initially. However, the TerminalCore project is a non-cppwinrt static lib. This was done to avoid having dll hops between TerminalCore and TerminalControl, which I believed would be frequent. Because TerminalCore wasn't a cppwinrt project, it couldn't generate a winmd/header pair for the idl.

Trying to make it a cppwinrt static library also introduced it's own insanity of build errors, where sometimes the winmd would be double included, or not included at all.

You also can't have a cppwinrt project that only has interface definitions without defining at least one type. I don't know if that was resolved in cppwinrt 2.0 or not. I tried this initially by making a TerminalSettings project that only included two idl files, but somewhere up the tree, msbuild was not be happy about the fact that the project didn't generate a dll (since it had no code, it didn't build a dll).

@zadjii-msft commented on GitHub (May 17, 2019): So that's what I tried initially. However, the `TerminalCore` project is a non-cppwinrt static lib. This was done to avoid having dll hops between TerminalCore and TerminalControl, which I believed would be frequent. Because TerminalCore wasn't a cppwinrt project, it couldn't generate a winmd/header pair for the idl. Trying to make it a cppwinrt static library also introduced it's own insanity of build errors, where sometimes the winmd would be double included, or not included at all. You also can't have a cppwinrt project that only has interface definitions without defining at least one type. I don't know if that was resolved in cppwinrt 2.0 or not. I tried this initially by making a TerminalSettings project that only included two idl files, but somewhere up the tree, msbuild was not be happy about the fact that the project didn't generate a dll (since it had no code, it didn't build a dll).
Author
Owner

@DHowett-MSFT commented on GitHub (May 17, 2019):

Indeed. I'll mark this help-wanted; I know that it's possible to have a project that only produces a type library, we just might need to dig deep on build system arcana.

@DHowett-MSFT commented on GitHub (May 17, 2019): Indeed. I'll mark this `help-wanted`; I know that it's possible to have a project that only produces a type library, we just might need to dig deep on build system arcana.
Author
Owner

@DHowett-MSFT commented on GitHub (May 17, 2019):

Notes: I think it's okay that TerminalCore wouldn't be a C++/WinRT project. Since it does live on the "fully C++" side of the world, it wouldn't be unreasonable for it to use wil::com_ptr over the raw interface types in the ::ABI namespace that MIDL generates. It might even be preferable... the annoying thing is unpacking HSTRINGs, but even that really isn't all that bad.

It can also become a C++/WinRT consumer very easily. It's significantly cheaper than authoring components, and it is the recommended way to consume all WinRT APIs in all C++ code.

@DHowett-MSFT commented on GitHub (May 17, 2019): *Notes:* I think it's okay that `TerminalCore` wouldn't be a C++/WinRT project. Since it does live on the "fully C++" side of the world, it wouldn't be unreasonable for it to use `wil::com_ptr` over the raw interface types in the `::ABI` namespace that MIDL generates. It might even be preferable... the annoying thing is unpacking `HSTRING`s, but even that really isn't all that bad. It can also _become_ a C++/WinRT consumer very easily. It's significantly cheaper than authoring components, and it is the recommended way to consume all WinRT APIs in all C++ code.
Author
Owner

@dlong11 commented on GitHub (May 19, 2019):

@zadjii-msft - First I am no expert on this and I am just starting to read up on WinRT. Plus - I don't think I 100% understand the issue, but the discussion helps me learn. So please ignore if this isn't helpful.

You also can't have a cppwinrt project that only has interface definitions without defining at least one type. I don't know if that was resolved in cppwinrt 2.0 or not. I tried this initially by making a TerminalSettings project that only included two idl files, but somewhere up the tree, msbuild was not be happy about the fact that the project didn't generate a dll (since it had no code, it didn't build a dll).

Instead of doing a project for this, could you use the command line and build step? Use midl.exe and compile the idl files then combine them. Then use cppwinrt.exe to generate the headers.

If I understand the issue correctly it appears this will work.

Docs that I have been reading on this.
midl command line
cppwinrt example

@dlong11 commented on GitHub (May 19, 2019): @zadjii-msft - First I am no expert on this and I am just starting to read up on WinRT. Plus - I don't think I 100% understand the issue, but the discussion helps me learn. So please ignore if this isn't helpful. > You also can't have a cppwinrt project that only has interface definitions without defining at least one type. I don't know if that was resolved in cppwinrt 2.0 or not. I tried this initially by making a TerminalSettings project that only included two idl files, but somewhere up the tree, msbuild was not be happy about the fact that the project didn't generate a dll (since it had no code, it didn't build a dll). Instead of doing a project for this, could you use the command line and build step? Use midl.exe and compile the idl files then combine them. Then use cppwinrt.exe to generate the headers. If I understand the issue correctly it appears this will work. Docs that I have been reading on this. [midl command line](https://docs.microsoft.com/en-us/uwp/midl-3/intro#declaration-structure-and-calling-midlexe-from-the-command-line) [cppwinrt](https://docs.microsoft.com/en-us/windows/uwp/cpp-and-winrt-apis/intro-to-using-cpp-with-winrt#visual-studio-support-for-cwinrt-xaml-the-vsix-extension-and-the-nuget-package) example
Author
Owner

@zadjii-msft commented on GitHub (May 20, 2019):

That's certainly an idea. I'd be wary to make sure that the build artifacts are included correctly in all the consuming projects, but it's certainly something worth trying.

@zadjii-msft commented on GitHub (May 20, 2019): That's certainly an idea. I'd be wary to make sure that the build artifacts are included correctly in all the consuming projects, but it's certainly something worth trying.
Author
Owner

@simonbuchan commented on GitHub (May 22, 2019):

Huh, I was assuming TerminalSettings was a WinRT dll so you could eventually have your own app hosting TerminalControl load the user's default settings using the same logic and hand them off to as much of the other packages as you were using...

Basically, would it make sense to just move the parsing code into TerminalSettings and actually have a .dll on disk?

@simonbuchan commented on GitHub (May 22, 2019): Huh, I was assuming `TerminalSettings` was a WinRT dll so you could eventually have your own app hosting `TerminalControl` load the user's default settings using the same logic and hand them off to as much of the other packages as you were using... Basically, would it make sense to just move the parsing code into `TerminalSettings` and actually have a `.dll` on disk?
Author
Owner

@zadjii-msft commented on GitHub (May 22, 2019):

I certainly considered that. I was thinking about something like Visual Studio, which could host a version of the control (or something using the core at least). They however probably want to use their own settings serialization and settings structure. They probably don't have any notion of profiles or anything like that, and they probably want to store the settings as XML. So, I wanted TerminalSettings to be application-independent, so any app could implement settings however they like, so long as they pass a common settings structure to the terminal itself.

@zadjii-msft commented on GitHub (May 22, 2019): I certainly considered that. I was thinking about something like Visual Studio, which could host a version of the control (or something using the core at least). They however probably want to use their own settings serialization and settings structure. They probably don't have any notion of profiles or anything like that, and they probably want to store the settings as XML. So, I wanted `TerminalSettings` to be application-independent, so any app could implement settings however they like, so long as they pass a common settings structure to the terminal itself.
Author
Owner

@DHowett-MSFT commented on GitHub (Jan 7, 2020):

Note to whoever follows up:

5119ed1645/src/cascadia/TerminalSettings/TerminalSettings.cpp (L125-L129)

TerminalSettings is no longer a "dumb data carrier", and this logic will need to be moved to wherever it ends up living.

(/cc @hannesne)

@DHowett-MSFT commented on GitHub (Jan 7, 2020): Note to whoever follows up: https://github.com/microsoft/terminal/blob/5119ed1645d9606254ad3bdfb028bade55873086/src/cascadia/TerminalSettings/TerminalSettings.cpp#L125-L129 TerminalSettings is no longer a "dumb data carrier", and this logic will need to be moved to wherever it ends up living. (/cc @hannesne)
Author
Owner

@carlos-zamora commented on GitHub (Jul 31, 2020):

Promoting this issue to be an epic. I'll copy the checkboxes below into the main description of this header.

This plan is largely based on #6904 and they'll be less risky than doing it all at once.

  • Introduce/Move TerminalApp bridge
    • Move TerminalSettings::TerminalSettings to TerminalApp::TerminalSettings
  • Move TerminalSettings interfaces
    • Move TerminalSettings::ICoreSettings to TerminalControl project
    • Move TerminalSettings::IControlSettings to TerminalControl project
  • Transform TerminalApp settings objects into WinRT objects
    • Profile
    • ColorScheme
    • GlobalSettings
    • Keybindings (this may be moved out to be its own PR)
  • Move the new WinRT settings objects into TerminalSettings
@carlos-zamora commented on GitHub (Jul 31, 2020): Promoting this issue to be an epic. I'll copy the checkboxes below into the main description of this header. This plan is largely based on #6904 and they'll be less risky than doing it all at once. - [x] Introduce/Move TerminalApp bridge - Move `TerminalSettings::TerminalSettings` to `TerminalApp::TerminalSettings` - [x] Move `TerminalSettings` interfaces - Move `TerminalSettings::ICoreSettings` to TerminalControl project - Move `TerminalSettings::IControlSettings` to TerminalControl project - [ ] Transform TerminalApp settings objects into WinRT objects - Profile - ColorScheme - GlobalSettings - Keybindings (this may be moved out to be its own PR) - [ ] Move the new WinRT settings objects into TerminalSettings
Author
Owner

@ghost commented on GitHub (Nov 11, 2020):

:tada:This issue was addressed in #7667, which has now been successfully released as Windows Terminal Preview v1.5.3142.0.🎉

Handy links:

@ghost commented on GitHub (Nov 11, 2020): :tada:This issue was addressed in #7667, which has now been successfully released as `Windows Terminal Preview v1.5.3142.0`.:tada: Handy links: * [Release Notes](https://github.com/microsoft/terminal/releases/tag/v1.5.3142.0) * [Store Download](https://www.microsoft.com/store/apps/9n8g5rfz9xk3?cid=storebadge&ocid=badge)
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/terminal#1200