-
Notifications
You must be signed in to change notification settings - Fork 76
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
Add decoration
parameter to Window
and DialogWindow
to control the thickness of the undecorated window resizers.
#1505
Add decoration
parameter to Window
and DialogWindow
to control the thickness of the undecorated window resizers.
#1505
Conversation
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.
Avoid implicit inputs provided via
CompositionLocal
We don't currently expose |
.../ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/UndecoratedWindowResizer.desktop.kt
Outdated
Show resolved
Hide resolved
7243da5
to
643529a
Compare
LocalUndecoratedWindowResizerBorderThickness
to control the thickness of the undecorated window resizers.decoration
parameter to Window
and DialogWindow
to control the thickness of the undecorated window resizers.
compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/Window.desktop.kt
Outdated
Show resolved
Hide resolved
/** | ||
* Defines the options for window decoration. | ||
*/ | ||
interface WindowDecoration { |
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.
interface WindowDecoration { | |
sealed class WindowDecoration { |
AOSP uses sealed class
in a case when it isn't possible to have custom implementation.
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 thought we didn't want to use sealed
or enum
classes because it can make it hard to provide backwards compatibility later when we want to add additional subtypes. For example, someone can write
when (decoration) {
is System -> ...
is Undecorated -> ...
}
and when we add another type, this will be broken.
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.
Right 🤔, let's keep interface
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.
Agree with @igordmn - it should be sealed
, but not class
, sealed interface
should work here. I guess it's covered by some policy - need to look for formal rule there, but the idea is to avoid implementation outside of our code. Explicit requirement in case of adding is pro, not cons
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.
Agree with @igordmn - it should be
sealed
, but notclass
,sealed interface
should work here. I guess it's covered by some policy - need to look for formal rule there, but the idea is to avoid implementation outside of our code. Explicit requirement in case of adding is pro, not cons
If we design this interface similar to TextFieldDecoration
and move the implementation of the Undecorated Resizer
to this part, it can be provided to users to achieve an immersive title bar application experience on Windows. This requires exposing the Window
to set window properties and exposing the HitTest
related interfaces for hit testing of controls within the title bar. You can refer to this existing implementation for specifics. Additionally, in the current Resizer implementation, if the user calls a Dialog
or Popup
, the Resizer response will be blocked and won’t respond . If we implement the Resizer through this new interface and always place the WindowDecoration
field above the ContentLayer
, can this solve the problem? Would this design make the Decoration API more user-friendly and extensible?
compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/WindowDecoration.desktop.kt
Outdated
Show resolved
Hide resolved
compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/window/WindowDecoration.desktop.kt
Outdated
Show resolved
Hide resolved
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.
Looks good 👍. Let's wait for the second approval.
/** | ||
* Defines the options for window decoration. | ||
*/ | ||
interface WindowDecoration { |
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.
Agree with @igordmn - it should be sealed
, but not class
, sealed interface
should work here. I guess it's covered by some policy - need to look for formal rule there, but the idea is to avoid implementation outside of our code. Explicit requirement in case of adding is pro, not cons
/** | ||
* The default thickness of the resizers in an undecorated window. | ||
*/ | ||
val DefaultWindowResizerThickness: Dp = 8.dp |
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'd move it from global scope to companion 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.
Agree with @igordmn - it should be sealed, but not class, sealed interface should work here. I guess it's covered by some policy - need to look for formal rule there, but the idea is to avoid implementation outside of our code. Explicit requirement in case of adding is pro, not cons
If we want a sealed
interface here, we need to hide the actual subtypes from the user, to make the when
scenario I mentioned impossible.
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'd move it from global scope to companion object
We can reuse the AOSP pattern:
object WindowDecorationDefaults {
val ResizerThickness: Dp = 8.dp
}
It is more preferable over companion object, because it will be consistent with AOSP
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.
On the other hand, it is only for Undecorated
.
I delegate the decision to @m-sasha
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.
we need to hide the actual subtypes from the user, to make the when scenario I mentioned impossible.
Why do we need to hide it? Why do we want to make such switch/when impossible?
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.
Explicit requirement in case of adding is pro, not cons
It's OK to require extra case handling in this case. It won't break binary compatibility that we have to maintain
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'd rather not dive into the exact semantics of what binary compatibility means.
De-facto, valid code that was written and compiled before the addition of another subtype will crash at runtime afterwards. That's breaking existing code.
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.
Yes, sure. But the policy for breaking source code compatibility is MUCH softer than for binary compatibility. The reason behind this is affecting 3rd party libraries that users cannot control.
It doesn't sound like a reason for avoid exposing subtypes at all
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.
It's not source compatibility that will be broken. Existing compiled code will throw an exception at runtime.
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.
All of it is about possibilities and potential changes. Not a blocker at the moment I guess, we can discuss it when we'll really need this
…ckness of the undecorated window resizers.
…coration.Undecorated`.
…logWindow` overloads.
2fa61e5
to
a86f773
Compare
The thickness of the undecorated window resizers is currently hardcoded to 8.dp. This PR adds a composition local,
LocalUndecoratedWindowResizerBorderThickness
to allow users to change it.Fixes JetBrains/compose-multiplatform#4574
Testing
Tested manually with:
It's difficult to write an automated test for this because
UndecoratedWindowResizer
relies onMouseInfo.getPointerInfo()
which can't be simulated from tests.Release Notes
Features - Desktop
The thickness of border resizers in undecorated windows and dialogs can now be controlled by passing a new
decoration
argument.