-
- true
- true
- false
-
-
-
\ No newline at end of file
diff --git a/README.md b/README.md
index 5de89917d2..f3aa404906 100644
--- a/README.md
+++ b/README.md
@@ -1,367 +1,7 @@
-[![JetBrains incubator](https://img.shields.io/badge/JetBrains-incubator-yellow?logo=data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMzIuMDAwMDEiIHZpZXdCb3g9IjAgMCAzMiAzMi4wMDAwMSIgd2lkdGg9IjMyIj48c2NyaXB0IHhtbG5zPSIiLz48cGF0aCBkPSJtMCAwaDMydjMyLjAwMDAxaC0zMnoiLz48cGF0aCBkPSJtNCAyNi4wMDAwMWgxMnYyaC0xMnoiIGZpbGw9IiNmZmYiLz48L3N2Zz4=)](https://github.com/JetBrains#jetbrains-on-github) [![CI checks](https://img.shields.io/github/actions/workflow/status/JetBrains/jewel/build.yml?logo=github)](https://github.com/JetBrains/jewel/actions/workflows/build.yml) [![Licensed under Apache 2.0](https://img.shields.io/github/license/JetBrains/jewel?logo=data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHN0cm9rZT0iI0ZGRiIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZS13aWR0aD0iMiIgZD0ibTMgNiAzIDFtMCAwLTMgOWE1LjAwMiA1LjAwMiAwIDAgMCA2LjAwMSAwTTYgN2wzIDlNNiA3bDYtMm02IDIgMy0xbS0zIDEtMyA5YTUuMDAyIDUuMDAyIDAgMCAwIDYuMDAxIDBNMTggN2wzIDltLTMtOS02LTJtMC0ydjJtMCAxNlY1bTAgMTZIOW0zIDBoMyIvPjwvc3ZnPg==)](https://github.com/JetBrains/jewel/blob/main/LICENSE) [![Latest release](https://img.shields.io/github/v/release/JetBrains/jewel?include_prereleases&label=Latest%20Release&logo=github)](https://github.com/JetBrains/jewel/releases/latest) ![Compose for Desktop version](https://img.shields.io/badge/Compose%20for%20Desktop-1.6.0-dev1369?logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB2aWV3Qm94PSIwIDAgNjcgNzQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI%2BPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0zNS45OTkgMi42NjNhNS4wMSA1LjAxIDAgMCAwLTQuOTk4IDBsLTI2LjUgMTUuMjUzYTQuOTk0IDQuOTk0IDAgMCAwLTEuMTk4Ljk2MmwxMS4xMDggNi4zNjZjLjI2OC0uMjkuNTgtLjU0LjkzMS0uNzQ0bDE2LjE1Ni05LjM0MmE0IDQgMCAwIDEgNC4wMDQgMEw1MS42NTcgMjQuNWMuMzUxLjIwMy42NjQuNDU1LjkzMi43NDRsMTEuMTA4LTYuMzY2YTQuOTkxIDQuOTkxIDAgMCAwLTEuMTk4LS45NjJsLTI2LjUtMTUuMjUzWm0yOC43MjMgMTcuOTMzLTExLjE4MyA2LjQwOGMuMDc2LjMxLjExNi42MzIuMTE2Ljk1OXYxNy43OTRhNCA0IDAgMCAxLTEuOTU4IDMuNDRsLTE2LjIzNSA5LjYzOGEzLjk5OCAzLjk5OCAwIDAgMS0uOTYyLjQxMnYxMi42M2E1LjAwNSA1LjAwNSAwIDAgMCAxLjQyOC0uNTY5bDI2LjYyLTE1LjczQTQuOTg2IDQuOTg2IDAgMCAwIDY1IDUxLjI4NFYyMi4yMzdjMC0uNTY3LS4wOTctMS4xMi0uMjc4LTEuNjRaTTIgMjIuMjM3YzAtLjU2Ny4wOTctMS4xMi4yNzgtMS42NGwxMS4xODMgNi40MDdjLS4wNzYuMzEtLjExNi42MzItLjExNi45NTl2MTguNjMzYTQgNCAwIDAgMCAyLjA4IDMuNTA5bDE2LjA3NCA4LjhjLjMyLjE3NC42NTYuMzAyIDEuMDAxLjM4NHYxMi42MzhhNS4wMDUgNS4wMDUgMCAwIDEtMS41MTctLjUzM0w0LjYwMyA1Ny4wMkE0Ljk4NyA0Ljk4NyAwIDAgMSAyIDUyLjY0MlYyMi4yMzdaTTMwLjAwMi45MzVhNy4wMTQgNy4wMTQgMCAwIDEgNi45OTYgMGwyNi41IDE1LjI1M0E2Ljk4IDYuOTggMCAwIDEgNjcgMjIuMjM4djI5LjA0N2E2Ljk4IDYuOTggMCAwIDEtMy40MzMgNi4wMDlsLTI2LjYyIDE1LjczMWE3LjAxNCA3LjAxNCAwIDAgMS02LjkyMy4xMkwzLjY0NCA1OC43NzFBNi45ODEgNi45ODEgMCAwIDEgMCA1Mi42NDFWMjIuMjM4YTYuOTggNi45OCAwIDAgMSAzLjUwMi02LjA1TDMwLjAwMi45MzZabS04LjYwNCAyNy41NTIgMTAuNTgyLTYuMTFjLjk0LS41NDIgMi4xLS41NDIgMy4wNCAwbDEwLjU4MiA2LjExYTIuOTk2IDIuOTk2IDAgMCAxIDEuNTAzIDIuNTkzdjExLjY1M2MwIDEuMDU2LS41NiAyLjAzNC0xLjQ3MyAyLjU3NmwtMTAuNjQzIDYuMzA4YTMuMDQ0IDMuMDQ0IDAgMCAxLTMuMDA5LjA1MmwtMTAuNTItNS43NWEyLjk5NiAyLjk5NiAwIDAgMS0xLjU2NS0yLjYyN1YzMS4wOGMwLTEuMDY4LjU3My0yLjA1NiAxLjUwMy0yLjU5M1oiIGZpbGw9IiNmZmYiLz48L3N2Zz4%3D)
-
# Jewel: a Compose for Desktop theme
-Jewel aims at recreating the IntelliJ Platform's _New UI_ Swing Look and Feel in Compose for Desktop, providing a
-desktop-optimized theme and set of components.
-
-> [!WARNING]
->
-> This project is in active development, and caution is advised when considering it for production uses. You _can_ use
-> it, but you should expect APIs to change often, things to move around and/or break, and all that jazz. Binary
-> compatibility is not guaranteed across releases, and APIs are still in flux and subject to change.
->
-> Writing 3rd party IntelliJ Plugins in Compose for Desktop is currently **not officially supported** by the IntelliJ
-> Platform. It should work, but your mileage may vary, and if things break you're on your own.
->
-> Use at your own risk!
-
-Jewel provides an implementation of the IntelliJ Platform themes that can be used in any Compose for Desktop
-application. Additionally, it has a Swing LaF Bridge that only works in the IntelliJ Platform (i.e., used to create IDE
-plugins), but automatically mirrors the current Swing LaF into Compose for a native-looking, consistent UI.
-
-## Getting started
-
-To use Jewel in your app, you only need to add the relevant dependency. There are two scenarios: standalone Compose for
-Desktop app, and IntelliJ Platform plugin.
-
-For now, Jewel artifacts aren't available on Maven Central. You need to add a custom Maven repository to your build:
-
-```kotlin
-repositories {
- maven("https://packages.jetbrains.team/maven/p/kpm/public/")
- // Any other repositories you need (e.g., mavenCentral())
-}
-```
-
-If you're writing a **standalone app**, then you should depend on the `int-ui-standalone` artifact:
-
-```kotlin
-dependencies {
- implementation("org.jetbrains.jewel:jewel-int-ui-standalone:[jewel version]")
-
- // Optional, for custom decorated windows:
- implementation("org.jetbrains.jewel:jewel-int-ui-decorated-window:[jewel version]")
-}
-```
-
-For an **IntelliJ Platform plugin**, then you should depend on the appropriate `ide-laf-bridge` artifact:
-
-```kotlin
-dependencies {
- // The platform version is a supported major IJP version (e.g., 232 or 233 for 2023.2 and 2023.3 respectively)
- implementation("org.jetbrains.jewel:jewel-ide-laf-bridge-[platform version]:[jewel version]")
-}
-```
-
-
-
-> [!TIP]
->
->
->
->
-> If you want to learn more about Jewel and Compose for Desktop and why they're a great, modern solution for your
-> desktop
-> UI needs, check out [this talk](https://www.droidcon.com/2023/11/15/meet-jewelcreate-ide-plugins-in-compose/) by Jewel
-> contributors Sebastiano and Chris.
->
-> It covers why Compose is a viable choice, and an overview of the Jewel project, plus
-> some real-life use cases.
-
-
-
-## Project structure
-
-The project is split in modules:
-
-1. `buildSrc` contains the build logic, including:
- * The `jewel` and `jewel-publish` configuration plugins
- * The `jewel-check-public-api` and `jewel-linting` configuration plugins
- * The Theme Palette generator plugin
- * The Studio Releases generator plugin
-2. `foundation` contains the foundational Jewel functionality:
- * Basic components without strong styling (e.g., `SelectableLazyColumn`, `BasicLazyTree`)
- * The `JewelTheme` interface with a few basic composition locals
- * The state management primitives
- * The Jewel annotations
- * A few other primitives
-3. `ui` contains all the styled components and custom painters logic
-4. `decorated-window` contains basic, unstyled functionality to have custom window decoration on the JetBrains Runtime
-5. `int-ui` contains two modules:
- * `int-ui-standalone` has a standalone version of the Int UI styling values that can be used in any Compose for
- Desktop app
- * `int-ui-decorated-window` has a standalone version of the Int UI styling values for the custom window decoration
- that can be used in any Compose for Desktop app
-6. `ide-laf-bridge` contains the Swing LaF bridge to use in IntelliJ Platform plugins (see more below)
-7. `markdown` contains a few modules:
- * `core` the core logic for parsing and rendering Markdown documents with Jewel, using GitHub-like styling
- * `extensions` contains several extensions to the base CommonMark specs that can be used to add more features
-8. `samples` contains the example apps, which showcase the available components:
- * `standalone` is a regular CfD app, using the standalone theme definitions and custom window decoration
- * `ide-plugin` is an IntelliJ plugin that showcases the use of the Swing Bridge
-
-## Branching strategy and IJ Platforms
-
-Code on the main branch is developed and tested against the current latest IntelliJ Platform version.
-
-When the EAP for a new major version starts, we cut a `releases/xxx` release branch, where `xxx` is the tracked major
-IJP version. At that point, the main branch starts tracking the latest available major IJP version, and changes are
-cherry-picked into each release branch as needed. All active release branches have the same functionality (where
-supported by the corresponding IJP version), but might differ in platform version-specific fixes and internals.
-
-The standalone Int UI theme will always work the same way as the latest major IJP version; release branches will not
-include the `int-ui` module, which is always released from the main branch.
-
-Releases of Jewel are always cut from a tag on the main branch; the HEAD of each `releases/xxx` branch is then tagged
-as `[mainTag]-xxx`, and used to publish the artifacts for that major IJP version.
-
-> ![IMPORTANT]
-> We only support the latest build of IJP for each major IJP version. If the latest 233 version is 2023.3.3, for
-> example, we will only guarantee that Jewel works on that. Versions 2023.3.0–2023.3.2 might or might not work.
-
-### Int UI Standalone theme
-
-The standalone theme can be used in any Compose for Desktop app. You use it as a normal theme, and you can customise it
-to your heart's content. By default, it matches the official Int UI specs.
-
-For an example on how to set up a standalone app, you can refer to
-the [`standalone` sample](samples/standalone/build.gradle.kts).
-
-> [!WARNING]
-> Note that Jewel **requires** the JetBrains Runtime to work correctly. Some features like font loading depend on it,
-> as it has extra features and patches for UI functionalities that aren't available in other JDKs.
-> We **do not support** running Jewel on any other JDK.
-
-To use Jewel components in a non-IntelliJ Platform environment, you need to wrap your UI hierarchy in a `IntUiTheme`
-composable:
-
-```kotlin
-IntUiTheme(isDark = false) {
- // ...
-}
-```
-
-If you want more control over the theming, you can use other `IntUiTheme` overloads, like the standalone sample does.
-
-#### Custom window decoration
-
-The JetBrains Runtime allows windows to have a custom decoration instead of the regular title bar.
-
-![A screenshot of the custom window decoration in the standalone sample](art/docs/custom-chrome.png)
-
-The standalone sample app shows how to easily get something that looks like a JetBrains IDE; if you want to go _very_
-custom, you only need to depend on the `decorated-window` module, which contains all the required primitives, but not
-the Int UI styling.
-
-To get an IntelliJ-like custom title bar, you need to pass the window decoration styling to your theme call, and add the
-`DecoratedWindow` composable at the top level of the theme:
-
-```kotlin
-IntUiTheme(
- themeDefinition,
- componentStyling = {
- themeDefinition.decoratedWindowComponentStyling(
- titleBarStyle = TitleBarStyle.light()
- )
- },
-) {
- DecoratedWindow(
- onCloseRequest = { exitApplication() },
- ) {
- // ...
- }
-}
-```
-
-### Running on the IntelliJ Platform: the Swing bridge
-
-Jewel includes a crucial element for proper integration with the IDE: a bridge between the Swing components — theme
-and LaF — and the Compose world.
-
-This bridge ensures that we pick up the colours, typography, metrics, and images as defined in the current IntelliJ
-theme, and apply them to the Compose components as well. This means Jewel will automatically adapt to IntelliJ Platform
-themes that use the [standard theming](https://plugins.jetbrains.com/docs/intellij/themes-getting-started.html)
-mechanisms.
-
-> [!NOTE]
-> IntelliJ themes that use non-standard mechanisms (such as providing custom UI implementations for Swing components)
-> are not, and can never, be supported.
-
-If you're writing an IntelliJ Platform plugin, you should use the `SwingBridgeTheme` instead of the standalone theme:
-
-```kotlin
-SwingBridgeTheme {
- // ...
-}
-```
-
-#### Supported IntelliJ Platform versions
-
-To use Jewel in the IntelliJ Platform, you should depend on the appropriate `jewel-ide-laf-bridge-*` artifact, which
-will bring in the necessary transitive dependencies. These are the currently supported versions of the IntelliJ Platform
-and the branch on which the corresponding bridge code lives:
-
-| IntelliJ Platform version(s) | Branch to use |
- |------------------------------|-------------------|
-| 2024.1 (EAP 3+) | `main` |
-| 2023.3 | `releases/233` |
-| 2023.2 | `releases/232` |
-| 2023.1 or older | **Not supported** |
-
-For an example on how to set up an IntelliJ Plugin, you can refer to
-the [`ide-plugin` sample](samples/ide-plugin/build.gradle.kts).
-
-#### Accessing icons
-
-When you want to draw an icon from the resources, you can either use the `Icon` composable and pass it the resource path
-and the corresponding class to look up the classpath from, or go one lever deeper and use the lower level,
-`Painter`-based API.
-
-The `Icon` approach looks like this:
-
-```kotlin
-// Load the "close" icon from the IDE's AllIcons class
-Icon(
- "actions/close.svg",
- iconClass = AllIcons::class.java,
- contentDescription = "Close",
-)
-```
-
-To obtain a `Painter`, instead, you'd use:
-
-```kotlin
-val painterProvider = rememberResourcePainterProvider(
- path = "actions/close.svg",
- iconClass = AllIcons::class.java
-)
-val painter by painterProvider.getPainter()
-```
-
-#### Icon runtime patching
-
-Jewel emulates the under-the-hood machinations that happen in the IntelliJ Platform when loading icons. Specifically,
-the resource will be subject to some transformations before being loaded.
-
-For example, in the IDE, if New UI is active, the icon path may be replaced with a different one. Some key colors in SVG
-icons will also be replaced based on the current theme. See
-[the docs](https://plugins.jetbrains.com/docs/intellij/work-with-icons-and-images.html#new-ui-icons).
-
-Beyond that, even in standalone, Jewel will pick up icons with the appropriate dark/light variant for the current theme,
-and for bitmap icons it will try to pick the 2x variants based on the `LocalDensity`.
-
-If you have a _stateful_ icon, that is if you need to display different icons based on some state, you can use the
-`PainterProvider.getPainter(PainterHint...)` overload. You can then use one of the state-mapping `PainterHint` to let
-Jewel load the appropriate icon automatically:
-
-```kotlin
-// myState implements SelectableComponentState and has a ToggleableState property
-val myPainter by myPainterProvider.getPainter(
- if (myState.toggleableState == ToggleableState.Indeterminate) {
- IndeterminateHint
- } else {
- PainterHint.None
- },
- Selected(myState),
- Stateful(myState),
-)
-```
-
-Where the `IndeterminateHint` looks like this:
-
-```kotlin
-private object IndeterminateHint : PainterSuffixHint() {
- override fun suffix(): String = "Indeterminate"
-}
-```
-
-Assuming the PainterProvider has a base path of `components/myIcon.svg`, Jewel will automatically translate it to the
-right path based on the state. If you want to learn more about this system, look at the `PainterHint` interface and its
-implementations.
-
-### Fonts
-
-To load a system font, you can obtain it by its family name:
-
-```kotlin
-val myFamily = FontFamily("My Family")
-```
-
-If you want to use a font embedded in the JetBrains Runtime, you can use the `EmbeddedFontFamily` API instead:
-
-```kotlin
-import javax.swing.text.StyledEditorKit.FontFamilyAction
-
-// Will return null if no matching font family exists in the JBR
-val myEmbeddedFamily = EmbeddedFontFamily("Embedded family")
-
-// It's recommended to load a fallback family when dealing with embedded familes
-val myFamily = myEmbeddedFamily ?: FontFamily("Fallback family")
-```
-
-You can obtain a `FontFamily` from any `java.awt.Font` — including from `JBFont`s — by using the `asComposeFontFamily()`
-API:
-
-```kotlin
-val myAwtFamily = myFont.asComposeFontFamily()
-
-// This will attempt to resolve the logical AWT font
-val myLogicalFamily = Font("Dialog").asComposeFontFamily()
-
-// This only works in the IntelliJ Platform,
-// since JBFont is only available there
-val myLabelFamily = JBFont.label().asComposeFontFamily()
-```
-
-### Swing interoperability
-
-As this is Compose for Desktop, you get a good degree of interoperability with Swing. To avoid glitches and z-order
-issues, you should enable the
-[experimental Swing rendering pipeline](https://blog.jetbrains.com/kotlin/2023/08/compose-multiplatform-1-5-0-release/#enhanced-swing-interop)
-before you initialize Compose content.
-
-The `ToolWindow.addComposeTab()` extension function provided by the `ide-laf-bridge` module will take care of that for
-you. However, if you want to also enable it in other scenarios and in standalone applications, you can call the
-`enableNewSwingCompositing()` function in your Compose entry points (that is, right before creating a `ComposePanel`).
-
-> [!NOTE]
-> The new Swing rendering pipeline is experimental and may have performance repercussions when using infinitely
-> repeating animations. This is a known issue by the Compose Multiplatform team, that requires changes in the Java
-> runtime to fix. Once the required changes are made in the JetBrains Runtime, we'll remove this notice.
-
-## Written with Jewel
-
-Here is a small selection of projects that use Compose for Desktop and Jewel:
-
-* [Package Search](https://github.com/JetBrains/package-search-intellij-plugin) (IntelliJ Platform plugin)
-* [Kotlin Explorer](https://github.com/romainguy/kotlin-explorer) (standalone app)
-* ...and more to come!
-
-## Need help?
-
-You can find help on the [`#jewel`](https://app.slack.com/client/T09229ZC6/C05T8U2C31T) channel on the Kotlin Slack.
-If you don't already have access to the Kotlin Slack, you can request it
-[here](https://surveys.jetbrains.com/s3/kotlin-slack-sign-up).
-
-## License
-
-Jewel is licensed under the [Apache 2.0 license](https://github.com/JetBrains/jewel/blob/main/LICENSE).
-
-```
-Copyright 2022–4 JetBrains s.r.o.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
+Please refer to the readme file on the `main` branch for further information.
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-```
+**This is the build for the IntelliJ Platform 23.2**
diff --git a/build.gradle.kts b/build.gradle.kts
index f12d5bc141..8dd7c47bb7 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -4,15 +4,11 @@ plugins {
}
dependencies {
- sarif(projects.decoratedWindow)
sarif(projects.foundation)
sarif(projects.ideLafBridge)
- sarif(projects.intUi.intUiDecoratedWindow)
- sarif(projects.intUi.intUiStandalone)
sarif(projects.markdown.core)
sarif(projects.markdown.extensionGfmAlerts)
sarif(projects.samples.idePlugin)
- sarif(projects.samples.standalone)
sarif(projects.ui)
}
diff --git a/decorated-window/api/decorated-window.api b/decorated-window/api/decorated-window.api
deleted file mode 100644
index 7e0cdd28f9..0000000000
--- a/decorated-window/api/decorated-window.api
+++ /dev/null
@@ -1,252 +0,0 @@
-public abstract interface class com/jetbrains/DesktopActions {
- public abstract fun setHandler (Lcom/jetbrains/DesktopActions$Handler;)V
-}
-
-public abstract interface class com/jetbrains/DesktopActions$Handler {
- public fun browse (Ljava/net/URI;)V
- public fun edit (Ljava/io/File;)V
- public fun mail (Ljava/net/URI;)V
- public fun open (Ljava/io/File;)V
- public fun print (Ljava/io/File;)V
-}
-
-public class com/jetbrains/JBR {
- public static fun getApiVersion ()Ljava/lang/String;
- public static fun getDesktopActions ()Lcom/jetbrains/DesktopActions;
- public static fun getRoundedCornersManager ()Lcom/jetbrains/RoundedCornersManager;
- public static fun getWindowDecorations ()Lcom/jetbrains/WindowDecorations;
- public static fun getWindowMove ()Lcom/jetbrains/WindowMove;
- public static fun isAvailable ()Z
- public static fun isDesktopActionsSupported ()Z
- public static fun isRoundedCornersManagerSupported ()Z
- public static fun isWindowDecorationsSupported ()Z
- public static fun isWindowMoveSupported ()Z
-}
-
-public abstract interface class com/jetbrains/RoundedCornersManager {
- public abstract fun setRoundedCorners (Ljava/awt/Window;Ljava/lang/Object;)V
-}
-
-public abstract interface class com/jetbrains/WindowDecorations {
- public abstract fun createCustomTitleBar ()Lcom/jetbrains/WindowDecorations$CustomTitleBar;
- public abstract fun setCustomTitleBar (Ljava/awt/Dialog;Lcom/jetbrains/WindowDecorations$CustomTitleBar;)V
- public abstract fun setCustomTitleBar (Ljava/awt/Frame;Lcom/jetbrains/WindowDecorations$CustomTitleBar;)V
-}
-
-public abstract interface class com/jetbrains/WindowDecorations$CustomTitleBar {
- public abstract fun forceHitTest (Z)V
- public abstract fun getContainingWindow ()Ljava/awt/Window;
- public abstract fun getHeight ()F
- public abstract fun getLeftInset ()F
- public abstract fun getProperties ()Ljava/util/Map;
- public abstract fun getRightInset ()F
- public abstract fun putProperties (Ljava/util/Map;)V
- public abstract fun putProperty (Ljava/lang/String;Ljava/lang/Object;)V
- public abstract fun setHeight (F)V
-}
-
-public abstract interface class com/jetbrains/WindowMove {
- public abstract fun startMovingTogetherWithMouse (Ljava/awt/Window;I)V
-}
-
-public final class org/jetbrains/jewel/window/DecoratedWindowKt {
- public static final fun DecoratedWindow (Lkotlin/jvm/functions/Function0;Landroidx/compose/ui/window/WindowState;ZLjava/lang/String;Landroidx/compose/ui/graphics/painter/Painter;ZZZZLkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lorg/jetbrains/jewel/window/styling/DecoratedWindowStyle;Lkotlin/jvm/functions/Function3;Landroidx/compose/runtime/Composer;III)V
-}
-
-public abstract interface class org/jetbrains/jewel/window/DecoratedWindowScope : androidx/compose/ui/window/FrameWindowScope {
- public abstract fun getState-VA8cQZQ ()J
- public abstract fun getWindow ()Landroidx/compose/ui/awt/ComposeWindow;
-}
-
-public final class org/jetbrains/jewel/window/DecoratedWindowState {
- public static final field Companion Lorg/jetbrains/jewel/window/DecoratedWindowState$Companion;
- public static final synthetic fun box-impl (J)Lorg/jetbrains/jewel/window/DecoratedWindowState;
- public static fun constructor-impl (J)J
- public static final fun copy-zAQEbgo (JZZZZ)J
- public static synthetic fun copy-zAQEbgo$default (JZZZZILjava/lang/Object;)J
- public fun equals (Ljava/lang/Object;)Z
- public static fun equals-impl (JLjava/lang/Object;)Z
- public static final fun equals-impl0 (JJ)Z
- public final fun getState-s-VKNKU ()J
- public fun hashCode ()I
- public static fun hashCode-impl (J)I
- public static final fun isActive-impl (J)Z
- public static final fun isFullscreen-impl (J)Z
- public static final fun isMaximized-impl (J)Z
- public static final fun isMinimized-impl (J)Z
- public fun toString ()Ljava/lang/String;
- public static fun toString-impl (J)Ljava/lang/String;
- public final synthetic fun unbox-impl ()J
-}
-
-public final class org/jetbrains/jewel/window/DecoratedWindowState$Companion {
- public final fun getActive-s-VKNKU ()J
- public final fun getFullscreen-s-VKNKU ()J
- public final fun getMaximize-s-VKNKU ()J
- public final fun getMinimize-s-VKNKU ()J
- public final fun of-LPCgXDc (Landroidx/compose/ui/awt/ComposeWindow;)J
- public final fun of-zAQEbgo (ZZZZ)J
- public static synthetic fun of-zAQEbgo$default (Lorg/jetbrains/jewel/window/DecoratedWindowState$Companion;ZZZZILjava/lang/Object;)J
-}
-
-public final class org/jetbrains/jewel/window/ThemeKt {
- public static final fun getDefaultDecoratedWindowStyle (Lorg/jetbrains/jewel/foundation/theme/JewelTheme$Companion;Landroidx/compose/runtime/Composer;I)Lorg/jetbrains/jewel/window/styling/DecoratedWindowStyle;
- public static final fun getDefaultTitleBarStyle (Lorg/jetbrains/jewel/foundation/theme/JewelTheme$Companion;Landroidx/compose/runtime/Composer;I)Lorg/jetbrains/jewel/window/styling/TitleBarStyle;
-}
-
-public final class org/jetbrains/jewel/window/TitleBarKt {
- public static final fun TitleBar-T042LqI (Lorg/jetbrains/jewel/window/DecoratedWindowScope;Landroidx/compose/ui/Modifier;JLorg/jetbrains/jewel/window/styling/TitleBarStyle;Lkotlin/jvm/functions/Function4;Landroidx/compose/runtime/Composer;II)V
-}
-
-public abstract interface class org/jetbrains/jewel/window/TitleBarScope {
- public abstract fun align (Landroidx/compose/ui/Modifier;Landroidx/compose/ui/Alignment$Horizontal;)Landroidx/compose/ui/Modifier;
- public abstract fun getIcon ()Landroidx/compose/ui/graphics/painter/Painter;
- public abstract fun getTitle ()Ljava/lang/String;
-}
-
-public final class org/jetbrains/jewel/window/TitleBar_MacOSKt {
- public static final fun newFullscreenControls (Landroidx/compose/ui/Modifier;Z)Landroidx/compose/ui/Modifier;
- public static synthetic fun newFullscreenControls$default (Landroidx/compose/ui/Modifier;ZILjava/lang/Object;)Landroidx/compose/ui/Modifier;
-}
-
-public final class org/jetbrains/jewel/window/styling/DecoratedWindowColors {
- public static final field $stable I
- public static final field Companion Lorg/jetbrains/jewel/window/styling/DecoratedWindowColors$Companion;
- public synthetic fun (JJLkotlin/jvm/internal/DefaultConstructorMarker;)V
- public final fun borderFor-3hEOMOc (JLandroidx/compose/runtime/Composer;I)Landroidx/compose/runtime/State;
- public fun equals (Ljava/lang/Object;)Z
- public final fun getBorder-0d7_KjU ()J
- public final fun getBorderInactive-0d7_KjU ()J
- public fun hashCode ()I
- public fun toString ()Ljava/lang/String;
-}
-
-public final class org/jetbrains/jewel/window/styling/DecoratedWindowColors$Companion {
-}
-
-public final class org/jetbrains/jewel/window/styling/DecoratedWindowMetrics {
- public static final field $stable I
- public static final field Companion Lorg/jetbrains/jewel/window/styling/DecoratedWindowMetrics$Companion;
- public synthetic fun (FLkotlin/jvm/internal/DefaultConstructorMarker;)V
- public fun equals (Ljava/lang/Object;)Z
- public final fun getBorderWidth-D9Ej5fM ()F
- public fun hashCode ()I
- public fun toString ()Ljava/lang/String;
-}
-
-public final class org/jetbrains/jewel/window/styling/DecoratedWindowMetrics$Companion {
-}
-
-public final class org/jetbrains/jewel/window/styling/DecoratedWindowStyle {
- public static final field $stable I
- public static final field Companion Lorg/jetbrains/jewel/window/styling/DecoratedWindowStyle$Companion;
- public fun (Lorg/jetbrains/jewel/window/styling/DecoratedWindowColors;Lorg/jetbrains/jewel/window/styling/DecoratedWindowMetrics;)V
- public fun equals (Ljava/lang/Object;)Z
- public final fun getColors ()Lorg/jetbrains/jewel/window/styling/DecoratedWindowColors;
- public final fun getMetrics ()Lorg/jetbrains/jewel/window/styling/DecoratedWindowMetrics;
- public fun hashCode ()I
- public fun toString ()Ljava/lang/String;
-}
-
-public final class org/jetbrains/jewel/window/styling/DecoratedWindowStyle$Companion {
-}
-
-public final class org/jetbrains/jewel/window/styling/DecoratedWindowStylingKt {
- public static final fun getLocalDecoratedWindowStyle ()Landroidx/compose/runtime/ProvidableCompositionLocal;
-}
-
-public final class org/jetbrains/jewel/window/styling/TitleBarColors {
- public static final field $stable I
- public static final field Companion Lorg/jetbrains/jewel/window/styling/TitleBarColors$Companion;
- public synthetic fun (JJJJJJJJJJJJJLkotlin/jvm/internal/DefaultConstructorMarker;)V
- public final fun backgroundFor-3hEOMOc (JLandroidx/compose/runtime/Composer;I)Landroidx/compose/runtime/State;
- public fun equals (Ljava/lang/Object;)Z
- public final fun getBackground-0d7_KjU ()J
- public final fun getBorder-0d7_KjU ()J
- public final fun getContent-0d7_KjU ()J
- public final fun getDropdownHoveredBackground-0d7_KjU ()J
- public final fun getDropdownPressedBackground-0d7_KjU ()J
- public final fun getFullscreenControlButtonsBackground-0d7_KjU ()J
- public final fun getIconButtonHoveredBackground-0d7_KjU ()J
- public final fun getIconButtonPressedBackground-0d7_KjU ()J
- public final fun getInactiveBackground-0d7_KjU ()J
- public final fun getTitlePaneButtonHoveredBackground-0d7_KjU ()J
- public final fun getTitlePaneButtonPressedBackground-0d7_KjU ()J
- public final fun getTitlePaneCloseButtonHoveredBackground-0d7_KjU ()J
- public final fun getTitlePaneCloseButtonPressedBackground-0d7_KjU ()J
- public fun hashCode ()I
- public fun toString ()Ljava/lang/String;
-}
-
-public final class org/jetbrains/jewel/window/styling/TitleBarColors$Companion {
-}
-
-public final class org/jetbrains/jewel/window/styling/TitleBarIcons {
- public static final field $stable I
- public static final field Companion Lorg/jetbrains/jewel/window/styling/TitleBarIcons$Companion;
- public fun (Lorg/jetbrains/jewel/ui/painter/PainterProvider;Lorg/jetbrains/jewel/ui/painter/PainterProvider;Lorg/jetbrains/jewel/ui/painter/PainterProvider;Lorg/jetbrains/jewel/ui/painter/PainterProvider;)V
- public fun equals (Ljava/lang/Object;)Z
- public final fun getCloseButton ()Lorg/jetbrains/jewel/ui/painter/PainterProvider;
- public final fun getMaximizeButton ()Lorg/jetbrains/jewel/ui/painter/PainterProvider;
- public final fun getMinimizeButton ()Lorg/jetbrains/jewel/ui/painter/PainterProvider;
- public final fun getRestoreButton ()Lorg/jetbrains/jewel/ui/painter/PainterProvider;
- public fun hashCode ()I
- public fun toString ()Ljava/lang/String;
-}
-
-public final class org/jetbrains/jewel/window/styling/TitleBarIcons$Companion {
-}
-
-public final class org/jetbrains/jewel/window/styling/TitleBarMetrics {
- public static final field $stable I
- public static final field Companion Lorg/jetbrains/jewel/window/styling/TitleBarMetrics$Companion;
- public synthetic fun (FFFJLkotlin/jvm/internal/DefaultConstructorMarker;)V
- public fun equals (Ljava/lang/Object;)Z
- public final fun getGradientEndX-D9Ej5fM ()F
- public final fun getGradientStartX-D9Ej5fM ()F
- public final fun getHeight-D9Ej5fM ()F
- public final fun getTitlePaneButtonSize-MYxV2XQ ()J
- public fun hashCode ()I
- public fun toString ()Ljava/lang/String;
-}
-
-public final class org/jetbrains/jewel/window/styling/TitleBarMetrics$Companion {
-}
-
-public final class org/jetbrains/jewel/window/styling/TitleBarStyle {
- public static final field $stable I
- public static final field Companion Lorg/jetbrains/jewel/window/styling/TitleBarStyle$Companion;
- public fun (Lorg/jetbrains/jewel/window/styling/TitleBarColors;Lorg/jetbrains/jewel/window/styling/TitleBarMetrics;Lorg/jetbrains/jewel/window/styling/TitleBarIcons;Lorg/jetbrains/jewel/ui/component/styling/DropdownStyle;Lorg/jetbrains/jewel/ui/component/styling/IconButtonStyle;Lorg/jetbrains/jewel/ui/component/styling/IconButtonStyle;Lorg/jetbrains/jewel/ui/component/styling/IconButtonStyle;)V
- public fun equals (Ljava/lang/Object;)Z
- public final fun getColors ()Lorg/jetbrains/jewel/window/styling/TitleBarColors;
- public final fun getDropdownStyle ()Lorg/jetbrains/jewel/ui/component/styling/DropdownStyle;
- public final fun getIconButtonStyle ()Lorg/jetbrains/jewel/ui/component/styling/IconButtonStyle;
- public final fun getIcons ()Lorg/jetbrains/jewel/window/styling/TitleBarIcons;
- public final fun getMetrics ()Lorg/jetbrains/jewel/window/styling/TitleBarMetrics;
- public final fun getPaneButtonStyle ()Lorg/jetbrains/jewel/ui/component/styling/IconButtonStyle;
- public final fun getPaneCloseButtonStyle ()Lorg/jetbrains/jewel/ui/component/styling/IconButtonStyle;
- public fun hashCode ()I
- public fun toString ()Ljava/lang/String;
-}
-
-public final class org/jetbrains/jewel/window/styling/TitleBarStyle$Companion {
-}
-
-public final class org/jetbrains/jewel/window/styling/TitleBarStylingKt {
- public static final fun getLocalTitleBarStyle ()Landroidx/compose/runtime/ProvidableCompositionLocal;
-}
-
-public final class org/jetbrains/jewel/window/utils/DesktopPlatform : java/lang/Enum {
- public static final field Companion Lorg/jetbrains/jewel/window/utils/DesktopPlatform$Companion;
- public static final field Linux Lorg/jetbrains/jewel/window/utils/DesktopPlatform;
- public static final field MacOS Lorg/jetbrains/jewel/window/utils/DesktopPlatform;
- public static final field Unknown Lorg/jetbrains/jewel/window/utils/DesktopPlatform;
- public static final field Windows Lorg/jetbrains/jewel/window/utils/DesktopPlatform;
- public static fun valueOf (Ljava/lang/String;)Lorg/jetbrains/jewel/window/utils/DesktopPlatform;
- public static fun values ()[Lorg/jetbrains/jewel/window/utils/DesktopPlatform;
-}
-
-public final class org/jetbrains/jewel/window/utils/DesktopPlatform$Companion {
- public final fun getCurrent ()Lorg/jetbrains/jewel/window/utils/DesktopPlatform;
-}
-
diff --git a/decorated-window/build.gradle.kts b/decorated-window/build.gradle.kts
deleted file mode 100644
index 02e83d703a..0000000000
--- a/decorated-window/build.gradle.kts
+++ /dev/null
@@ -1,17 +0,0 @@
-import org.jetbrains.compose.ComposeBuildConfig
-
-plugins {
- jewel
- `jewel-publish`
- `jewel-check-public-api`
- alias(libs.plugins.composeDesktop)
-}
-
-private val composeVersion
- get() = ComposeBuildConfig.composeVersion
-
-dependencies {
- api("org.jetbrains.compose.foundation:foundation-desktop:$composeVersion")
- api(projects.ui)
- implementation(libs.jna.core)
-}
diff --git a/decorated-window/src/main/java/com/jetbrains/DesktopActions.java b/decorated-window/src/main/java/com/jetbrains/DesktopActions.java
deleted file mode 100644
index f2efcb477a..0000000000
--- a/decorated-window/src/main/java/com/jetbrains/DesktopActions.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2000-2022 JetBrains s.r.o.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package com.jetbrains;
-
-import java.io.File;
-import java.io.IOException;
-import java.net.URI;
-
-public interface DesktopActions {
-
- void setHandler(Handler handler);
-
- interface Handler {
- default void open(File file) throws IOException { throw new UnsupportedOperationException(); }
- default void edit(File file) throws IOException { throw new UnsupportedOperationException(); }
- default void print(File file) throws IOException { throw new UnsupportedOperationException(); }
- default void mail(URI mailtoURL) throws IOException { throw new UnsupportedOperationException(); }
- default void browse(URI uri) throws IOException { throw new UnsupportedOperationException(); }
- }
-
-}
diff --git a/decorated-window/src/main/java/com/jetbrains/JBR.java b/decorated-window/src/main/java/com/jetbrains/JBR.java
deleted file mode 100644
index 0f5f04505e..0000000000
--- a/decorated-window/src/main/java/com/jetbrains/JBR.java
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * Copyright 2000-2023 JetBrains s.r.o.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package com.jetbrains;
-
-import java.lang.invoke.MethodHandles;
-import java.lang.reflect.InvocationTargetException;
-
-/**
- * This class is an entry point into JBR API.
- * JBR API is a collection of services, classes, interfaces, etc.,
- * which require tight interaction with JRE and therefore are implemented inside JBR.
- *
JBR API consists of two parts:
- *
- *
Client side - {@code jetbrains.api} module, mostly containing interfaces
- *
JBR side - actual implementation code inside JBR
- *
- * Client and JBR side are linked dynamically at runtime and do not have to be of the same version.
- * In some cases (e.g. running on different JRE or old JBR) system will not be able to find
- * implementation for some services, so you'll need a fallback behavior for that case.
- *
- *
- * @implNote JBR API is initialized on first access to this class (in static initializer).
- * Actual implementation is linked on demand, when corresponding service is requested by client.
- */
-public class JBR {
-
- private static final ServiceApi api;
- private static final Exception bootstrapException;
-
- static {
- ServiceApi a = null;
- Exception exception = null;
- try {
- a = (ServiceApi) Class.forName("com.jetbrains.bootstrap.JBRApiBootstrap")
- .getMethod("bootstrap", MethodHandles.Lookup.class)
- .invoke(null, MethodHandles.lookup());
- } catch (InvocationTargetException e) {
- Throwable t = e.getCause();
- if (t instanceof Error error) throw error;
- else throw new Error(t);
- } catch (IllegalAccessException | NoSuchMethodException | ClassNotFoundException e) {
- exception = e;
- }
- api = a;
- bootstrapException = exception;
- }
-
- private JBR() {
- }
-
- private static T getService(Class interFace, FallbackSupplier fallback) {
- T service = getService(interFace);
- try {
- return service != null ? service : fallback != null ? fallback.get() : null;
- } catch (Throwable ignore) {
- return null;
- }
- }
-
- static T getService(Class interFace) {
- return api == null ? null : api.getService(interFace);
- }
-
- /**
- * @return true when running on JBR which implements JBR API
- */
- public static boolean isAvailable() {
- return api != null;
- }
-
- /**
- * @return JBR API version in form {@code JBR.MAJOR.MINOR.PATCH}
- * @implNote This is an API version, which comes with client application,
- * it has nothing to do with JRE it runs on.
- */
- public static String getApiVersion() {
- return "17.0.8.1b1070.2.1.9.0";
- }
-
- /**
- * Internal API interface, contains most basic methods for communication between client and JBR.
- */
- private interface ServiceApi {
-
- T getService(Class interFace);
- }
-
- @FunctionalInterface
- private interface FallbackSupplier {
- T get() throws Throwable;
- }
-
- // ========================== Generated metadata ==========================
-
- /**
- * Generated client-side metadata, needed by JBR when linking the implementation.
- */
- private static final class Metadata {
- private static final String[] KNOWN_SERVICES = {"com.jetbrains.ExtendedGlyphCache", "com.jetbrains.DesktopActions", "com.jetbrains.CustomWindowDecoration", "com.jetbrains.ProjectorUtils", "com.jetbrains.FontExtensions", "com.jetbrains.RoundedCornersManager", "com.jetbrains.GraphicsUtils", "com.jetbrains.WindowDecorations", "com.jetbrains.JBRFileDialogService", "com.jetbrains.AccessibleAnnouncer", "com.jetbrains.JBR$ServiceApi", "com.jetbrains.Jstack", "com.jetbrains.WindowMove"};
- private static final String[] KNOWN_PROXIES = {"com.jetbrains.JBRFileDialog", "com.jetbrains.WindowDecorations$CustomTitleBar"};
- }
-
- // ======================= Generated static methods =======================
-
- private static class DesktopActions__Holder {
- private static final DesktopActions INSTANCE = getService(DesktopActions.class, null);
- }
-
- /**
- * @return true if current runtime has implementation for all methods in {@link DesktopActions}
- * and its dependencies (can fully implement given service).
- * @see #getDesktopActions()
- */
- public static boolean isDesktopActionsSupported() {
- return DesktopActions__Holder.INSTANCE != null;
- }
-
- /**
- * @return full implementation of {@link DesktopActions} service if any, or {@code null} otherwise
- */
- public static DesktopActions getDesktopActions() {
- return DesktopActions__Holder.INSTANCE;
- }
-
- private static class RoundedCornersManager__Holder {
- private static final RoundedCornersManager INSTANCE = getService(RoundedCornersManager.class, null);
- }
-
- /**
- * @return true if current runtime has implementation for all methods in {@link RoundedCornersManager}
- * and its dependencies (can fully implement given service).
- * @see #getRoundedCornersManager()
- */
- public static boolean isRoundedCornersManagerSupported() {
- return RoundedCornersManager__Holder.INSTANCE != null;
- }
-
- /**
- * This manager allows decorate awt Window with rounded corners.
- * Appearance depends from operating system.
- *
- * @return full implementation of {@link RoundedCornersManager} service if any, or {@code null} otherwise
- */
- public static RoundedCornersManager getRoundedCornersManager() {
- return RoundedCornersManager__Holder.INSTANCE;
- }
-
- private static class WindowDecorations__Holder {
- private static final WindowDecorations INSTANCE = getService(WindowDecorations.class, null);
- }
-
- /**
- * @return true if current runtime has implementation for all methods in {@link WindowDecorations}
- * and its dependencies (can fully implement given service).
- * @see #getWindowDecorations()
- */
- public static boolean isWindowDecorationsSupported() {
- return WindowDecorations__Holder.INSTANCE != null;
- }
-
- /**
- * Window decorations consist of title bar, window controls and border.
- *
- * @return full implementation of {@link WindowDecorations} service if any, or {@code null} otherwise
- * @see WindowDecorations.CustomTitleBar
- */
- public static WindowDecorations getWindowDecorations() {
- return WindowDecorations__Holder.INSTANCE;
- }
-
- private static class WindowMove__Holder {
- private static final WindowMove INSTANCE = getService(WindowMove.class, null);
- }
-
- /**
- * @return true if current runtime has implementation for all methods in {@link WindowMove}
- * and its dependencies (can fully implement given service).
- * @see #getWindowMove()
- */
- public static boolean isWindowMoveSupported() {
- return WindowMove__Holder.INSTANCE != null;
- }
-
- /**
- * @return full implementation of {@link WindowMove} service if any, or {@code null} otherwise
- */
- public static WindowMove getWindowMove() {
- return WindowMove__Holder.INSTANCE;
- }
-}
diff --git a/decorated-window/src/main/java/com/jetbrains/RoundedCornersManager.java b/decorated-window/src/main/java/com/jetbrains/RoundedCornersManager.java
deleted file mode 100644
index 424e03feda..0000000000
--- a/decorated-window/src/main/java/com/jetbrains/RoundedCornersManager.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright 2000-2023 JetBrains s.r.o.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package com.jetbrains;
-
-import java.awt.*;
-
-/**
- * This manager allows decorate awt Window with rounded corners.
- * Appearance depends from operating system.
- */
-public interface RoundedCornersManager {
- /**
- * @param params for macOS is Float object with radius or
- * Array with {Float for radius, Integer for border width, java.awt.Color for border color}.
- *
- * @param params for Windows 11 is String with values:
- * "default" - let the system decide whether or not to round window corners,
- * "none" - never round window corners,
- * "full" - round the corners if appropriate,
- * "small" - round the corners if appropriate, with a small radius.
- */
- void setRoundedCorners(Window window, Object params);
-}
diff --git a/decorated-window/src/main/java/com/jetbrains/WindowDecorations.java b/decorated-window/src/main/java/com/jetbrains/WindowDecorations.java
deleted file mode 100644
index fc0144fa7c..0000000000
--- a/decorated-window/src/main/java/com/jetbrains/WindowDecorations.java
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright 2023 JetBrains s.r.o.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package com.jetbrains;
-
-import java.awt.*;
-import java.util.Map;
-
-/**
- * Window decorations consist of title bar, window controls and border.
- * @see CustomTitleBar
- */
-public interface WindowDecorations {
-
- /**
- * If {@code customTitleBar} is not null, system-provided title bar is removed and client area is extended to the
- * top of the frame with window controls painted over the client area.
- * {@code customTitleBar=null} resets to the default appearance with system-provided title bar.
- * @see CustomTitleBar
- * @see #createCustomTitleBar()
- */
- void setCustomTitleBar(Frame frame, CustomTitleBar customTitleBar);
-
- /**
- * If {@code customTitleBar} is not null, system-provided title bar is removed and client area is extended to the
- * top of the dialog with window controls painted over the client area.
- * {@code customTitleBar=null} resets to the default appearance with system-provided title bar.
- * @see CustomTitleBar
- * @see #createCustomTitleBar()
- */
- void setCustomTitleBar(Dialog dialog, CustomTitleBar customTitleBar);
-
- /**
- * You must {@linkplain CustomTitleBar#setHeight(float) set title bar height} before adding it to a window.
- * @see CustomTitleBar
- * @see #setCustomTitleBar(Frame, CustomTitleBar)
- * @see #setCustomTitleBar(Dialog, CustomTitleBar)
- */
- CustomTitleBar createCustomTitleBar();
-
- /**
- * Custom title bar allows merging of window content with native title bar,
- * which is done by treating title bar as part of client area, but with some
- * special behavior like dragging or maximizing on double click.
- * Custom title bar has {@linkplain CustomTitleBar#getHeight() height} and controls.
- * @implNote Behavior is platform-dependent, only macOS and Windows are supported.
- * @see #setCustomTitleBar(Frame, CustomTitleBar)
- */
- interface CustomTitleBar {
-
- /**
- * @return title bar height, measured in pixels from the top of client area, i.e. excluding top frame border.
- */
- float getHeight();
-
- /**
- * @param height title bar height, measured in pixels from the top of client area,
- * i.e. excluding top frame border. Must be > 0.
- */
- void setHeight(float height);
-
- /**
- * @see #putProperty(String, Object)
- */
- Map getProperties();
-
- /**
- * @see #putProperty(String, Object)
- */
- void putProperties(Map m);
-
- /**
- * Windows & macOS properties:
- *
- *
{@code controls.visible} : {@link Boolean} - whether title bar controls
- * (minimize/maximize/close buttons) are visible, default = true.
- *
- * Windows properties:
- *
- *
{@code controls.width} : {@link Number} - width of block of buttons (not individual buttons).
- * Note that dialogs have only one button, while frames usually have 3 of them.
- *
{@code controls.dark} : {@link Boolean} - whether to use dark or light color theme
- * (light or dark icons respectively).
- *
{@code controls..} : {@link Color} - precise control over button colors,
- * where {@code } is one of:
- *
{@code foreground}
{@code background}
- * and {@code } is one of:
- *
- *
{@code normal}
- *
{@code hovered}
- *
{@code pressed}
- *
{@code disabled}
- *
{@code inactive}
- *
- *
- */
- void putProperty(String key, Object value);
-
- /**
- * @return space occupied by title bar controls on the left (px)
- */
- float getLeftInset();
- /**
- * @return space occupied by title bar controls on the right (px)
- */
- float getRightInset();
-
- /**
- * By default, any component which has no cursor or mouse event listeners set is considered transparent for
- * native title bar actions. That is, dragging simple JPanel in title bar area will drag the
- * window, but dragging a JButton will not. Adding mouse listener to a component will prevent any native actions
- * inside bounds of that component.
- *
- * This method gives you precise control of whether to allow native title bar actions or not.
- *
- *
{@code client=true} means that mouse is currently over a client area. Native title bar behavior is disabled.
- *
{@code client=false} means that mouse is currently over a non-client area. Native title bar behavior is enabled.
- *
- * Intended usage:
- *
- *
This method must be called in response to all {@linkplain java.awt.event.MouseEvent mouse events}
- * except {@link java.awt.event.MouseEvent#MOUSE_EXITED} and {@link java.awt.event.MouseEvent#MOUSE_WHEEL}.
- *
This method is called per-event, i.e. when component has multiple listeners, you only need to call it once.
- *
If this method hadn't been called, title bar behavior is reverted back to default upon processing the event.
- *
- * Note that hit test value is relevant only for title bar area, e.g. calling
- * {@code forceHitTest(false)} will not make window draggable via non-title bar area.
- *
- *
Example:
- * Suppose you have a {@code JPanel} in the title bar area. You want it to respond to right-click for
- * some popup menu, but also retain native drag and double-click behavior.
- *
- */
- void forceHitTest(boolean client);
-
- Window getContainingWindow();
- }
-}
diff --git a/decorated-window/src/main/java/com/jetbrains/WindowMove.java b/decorated-window/src/main/java/com/jetbrains/WindowMove.java
deleted file mode 100644
index 5f241303c0..0000000000
--- a/decorated-window/src/main/java/com/jetbrains/WindowMove.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright 2000-2023 JetBrains s.r.o.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package com.jetbrains;
-
-import java.awt.*;
-
-public interface WindowMove {
- /**
- * Starts moving the top-level parent window of the given window together with the mouse pointer.
- * The intended use is to facilitate the implementation of window management similar to the way
- * it is done natively on the platform.
- *
- * Preconditions for calling this method:
- *
- *
WM supports _NET_WM_MOVE_RESIZE (this is checked automatically when an implementation
- * of this interface is obtained).
- *
Mouse pointer is within this window's bounds.
- *
The mouse button specified by {@code mouseButton} is pressed.
- *
- *
- * Calling this method will make the window start moving together with the mouse pointer until
- * the specified mouse button is released or Esc is pressed. The conditions for cancelling
- * the move may differ between WMs.
- *
- * @param mouseButton indicates the mouse button that was pressed to start moving the window;
- * must be one of {@code MouseEvent.BUTTON1}, {@code MouseEvent.BUTTON2},
- * or {@code MouseEvent.BUTTON3}.
- */
- void startMovingTogetherWithMouse(Window window, int mouseButton);
-}
diff --git a/decorated-window/src/main/kotlin/org/jetbrains/jewel/window/DecoratedWindow.kt b/decorated-window/src/main/kotlin/org/jetbrains/jewel/window/DecoratedWindow.kt
deleted file mode 100644
index 6abc043863..0000000000
--- a/decorated-window/src/main/kotlin/org/jetbrains/jewel/window/DecoratedWindow.kt
+++ /dev/null
@@ -1,289 +0,0 @@
-package org.jetbrains.jewel.window
-
-import androidx.compose.foundation.layout.padding
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.CompositionLocalProvider
-import androidx.compose.runtime.DisposableEffect
-import androidx.compose.runtime.Immutable
-import androidx.compose.runtime.ProvidableCompositionLocal
-import androidx.compose.runtime.Stable
-import androidx.compose.runtime.compositionLocalOf
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.runtime.setValue
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.awt.ComposeWindow
-import androidx.compose.ui.graphics.RectangleShape
-import androidx.compose.ui.graphics.painter.Painter
-import androidx.compose.ui.input.key.KeyEvent
-import androidx.compose.ui.layout.Layout
-import androidx.compose.ui.layout.Measurable
-import androidx.compose.ui.layout.MeasurePolicy
-import androidx.compose.ui.layout.MeasureResult
-import androidx.compose.ui.layout.MeasureScope
-import androidx.compose.ui.layout.Placeable
-import androidx.compose.ui.layout.layoutId
-import androidx.compose.ui.unit.Constraints
-import androidx.compose.ui.unit.offset
-import androidx.compose.ui.window.FrameWindowScope
-import androidx.compose.ui.window.Window
-import androidx.compose.ui.window.WindowPlacement
-import androidx.compose.ui.window.WindowState
-import androidx.compose.ui.window.rememberWindowState
-import com.jetbrains.JBR
-import org.jetbrains.jewel.foundation.Stroke
-import org.jetbrains.jewel.foundation.modifier.border
-import org.jetbrains.jewel.foundation.modifier.trackWindowActivation
-import org.jetbrains.jewel.foundation.theme.JewelTheme
-import org.jetbrains.jewel.window.styling.DecoratedWindowStyle
-import org.jetbrains.jewel.window.utils.DesktopPlatform
-import java.awt.event.ComponentEvent
-import java.awt.event.ComponentListener
-import java.awt.event.WindowAdapter
-import java.awt.event.WindowEvent
-
-@Composable
-public fun DecoratedWindow(
- onCloseRequest: () -> Unit,
- state: WindowState = rememberWindowState(),
- visible: Boolean = true,
- title: String = "",
- icon: Painter? = null,
- resizable: Boolean = true,
- enabled: Boolean = true,
- focusable: Boolean = true,
- alwaysOnTop: Boolean = false,
- onPreviewKeyEvent: (KeyEvent) -> Boolean = { false },
- onKeyEvent: (KeyEvent) -> Boolean = { false },
- style: DecoratedWindowStyle = JewelTheme.defaultDecoratedWindowStyle,
- content: @Composable DecoratedWindowScope.() -> Unit,
-) {
- remember {
- if (!JBR.isAvailable()) {
- error(
- "DecoratedWindow can only be used on JetBrainsRuntime(JBR) platform, " +
- "please check the document https://github.com/JetBrains/jewel#int-ui-standalone-theme",
- )
- }
- }
-
- // Using undecorated window for linux
- val undecorated = DesktopPlatform.Linux == DesktopPlatform.Current
-
- Window(
- onCloseRequest,
- state,
- visible,
- title,
- icon,
- undecorated,
- transparent = false,
- resizable,
- enabled,
- focusable,
- alwaysOnTop,
- onPreviewKeyEvent,
- onKeyEvent,
- ) {
- var decoratedWindowState by remember { mutableStateOf(DecoratedWindowState.of(window)) }
-
- DisposableEffect(window) {
- val adapter = object : WindowAdapter(), ComponentListener {
- override fun windowActivated(e: WindowEvent?) {
- decoratedWindowState = DecoratedWindowState.of(window)
- }
-
- override fun windowDeactivated(e: WindowEvent?) {
- decoratedWindowState = DecoratedWindowState.of(window)
- }
-
- override fun windowIconified(e: WindowEvent?) {
- decoratedWindowState = DecoratedWindowState.of(window)
- }
-
- override fun windowDeiconified(e: WindowEvent?) {
- decoratedWindowState = DecoratedWindowState.of(window)
- }
-
- override fun windowStateChanged(e: WindowEvent) {
- decoratedWindowState = DecoratedWindowState.of(window)
- }
-
- override fun componentResized(e: ComponentEvent?) {
- decoratedWindowState = DecoratedWindowState.of(window)
- }
-
- override fun componentMoved(e: ComponentEvent?) {
- // Empty
- }
-
- override fun componentShown(e: ComponentEvent?) {
- // Empty
- }
-
- override fun componentHidden(e: ComponentEvent?) {
- // Empty
- }
- }
-
- window.addWindowListener(adapter)
- window.addWindowStateListener(adapter)
- window.addComponentListener(adapter)
-
- onDispose {
- window.removeWindowListener(adapter)
- window.removeWindowStateListener(adapter)
- window.removeComponentListener(adapter)
- }
- }
-
- val undecoratedWindowBorder =
- if (undecorated && !decoratedWindowState.isMaximized) {
- Modifier.border(
- Stroke.Alignment.Inside,
- style.metrics.borderWidth,
- style.colors.borderFor(decoratedWindowState).value,
- RectangleShape,
- ).padding(style.metrics.borderWidth)
- } else {
- Modifier
- }
-
- CompositionLocalProvider(
- LocalTitleBarInfo provides TitleBarInfo(title, icon),
- ) {
- Layout(
- content = {
- val scope = object : DecoratedWindowScope {
- override val state: DecoratedWindowState
- get() = decoratedWindowState
-
- override val window: ComposeWindow
- get() = this@Window.window
- }
- scope.content()
- },
- modifier = undecoratedWindowBorder.trackWindowActivation(window),
- measurePolicy = DecoratedWindowMeasurePolicy,
- )
- }
- }
-}
-
-@Stable
-public interface DecoratedWindowScope : FrameWindowScope {
-
- override val window: ComposeWindow
-
- public val state: DecoratedWindowState
-}
-
-private object DecoratedWindowMeasurePolicy : MeasurePolicy {
-
- override fun MeasureScope.measure(measurables: List, constraints: Constraints): MeasureResult {
- if (measurables.isEmpty()) {
- return layout(width = constraints.minWidth, height = constraints.minHeight) {}
- }
-
- val titleBars = measurables.filter { it.layoutId == TITLE_BAR_LAYOUT_ID }
- if (titleBars.size > 1) {
- error("Window just can have only one title bar")
- }
- val titleBar = titleBars.firstOrNull()
- val titleBarBorder = measurables.firstOrNull { it.layoutId == TITLE_BAR_BORDER_LAYOUT_ID }
-
- val contentConstraints = constraints.copy(minWidth = 0, minHeight = 0)
-
- val titleBarPlaceable = titleBar?.measure(contentConstraints)
- val titleBarHeight = titleBarPlaceable?.height ?: 0
-
- val titleBarBorderPlaceable = titleBarBorder?.measure(contentConstraints)
- val titleBarBorderHeight = titleBarBorderPlaceable?.height ?: 0
-
- val measuredPlaceable = mutableListOf()
-
- for (it in measurables) {
- if (it.layoutId.toString().startsWith(TITLE_BAR_COMPONENT_LAYOUT_ID_PREFIX)) continue
- val offsetConstraints = contentConstraints.offset(vertical = -titleBarHeight - titleBarBorderHeight)
- val placeable = it.measure(offsetConstraints)
- measuredPlaceable += placeable
- }
-
- return layout(constraints.maxWidth, constraints.maxHeight) {
- titleBarPlaceable?.placeRelative(0, 0)
- titleBarBorderPlaceable?.placeRelative(0, titleBarHeight)
-
- measuredPlaceable.forEach { it.placeRelative(0, titleBarHeight + titleBarBorderHeight) }
- }
- }
-}
-
-@Immutable
-@JvmInline
-public value class DecoratedWindowState(public val state: ULong) {
-
- public val isActive: Boolean
- get() = state and Active != 0UL
-
- public val isFullscreen: Boolean
- get() = state and Fullscreen != 0UL
-
- public val isMinimized: Boolean
- get() = state and Minimize != 0UL
-
- public val isMaximized: Boolean
- get() = state and Maximize != 0UL
-
- public fun copy(
- fullscreen: Boolean = isFullscreen,
- minimized: Boolean = isMinimized,
- maximized: Boolean = isMaximized,
- active: Boolean = isActive,
- ): DecoratedWindowState =
- of(
- fullscreen = fullscreen,
- minimized = minimized,
- maximized = maximized,
- active = active,
- )
-
- override fun toString(): String =
- "${javaClass.simpleName}(isFullscreen=$isFullscreen, isActive=$isActive)"
-
- public companion object {
-
- public val Active: ULong = 1UL shl 0
- public val Fullscreen: ULong = 1UL shl 1
- public val Minimize: ULong = 1UL shl 2
- public val Maximize: ULong = 1UL shl 3
-
- public fun of(
- fullscreen: Boolean = false,
- minimized: Boolean = false,
- maximized: Boolean = false,
- active: Boolean = true,
- ): DecoratedWindowState =
- DecoratedWindowState(
- (if (fullscreen) Fullscreen else 0UL) or
- (if (minimized) Minimize else 0UL) or
- (if (maximized) Maximize else 0UL) or
- (if (active) Active else 0UL),
- )
-
- public fun of(window: ComposeWindow): DecoratedWindowState =
- of(
- fullscreen = window.placement == WindowPlacement.Fullscreen,
- minimized = window.isMinimized,
- maximized = window.placement == WindowPlacement.Maximized,
- active = window.isActive,
- )
- }
-}
-
-internal data class TitleBarInfo(val title: String, val icon: Painter?)
-
-internal val LocalTitleBarInfo: ProvidableCompositionLocal =
- compositionLocalOf {
- error("LocalTitleBarInfo not provided, TitleBar must be used in DecoratedWindow")
- }
diff --git a/decorated-window/src/main/kotlin/org/jetbrains/jewel/window/Theme.kt b/decorated-window/src/main/kotlin/org/jetbrains/jewel/window/Theme.kt
deleted file mode 100644
index 93d672e515..0000000000
--- a/decorated-window/src/main/kotlin/org/jetbrains/jewel/window/Theme.kt
+++ /dev/null
@@ -1,17 +0,0 @@
-package org.jetbrains.jewel.window
-
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.ReadOnlyComposable
-import org.jetbrains.jewel.foundation.theme.JewelTheme
-import org.jetbrains.jewel.window.styling.DecoratedWindowStyle
-import org.jetbrains.jewel.window.styling.LocalDecoratedWindowStyle
-import org.jetbrains.jewel.window.styling.LocalTitleBarStyle
-import org.jetbrains.jewel.window.styling.TitleBarStyle
-
-public val JewelTheme.Companion.defaultTitleBarStyle: TitleBarStyle
- @Composable @ReadOnlyComposable
- get() = LocalTitleBarStyle.current
-
-public val JewelTheme.Companion.defaultDecoratedWindowStyle: DecoratedWindowStyle
- @Composable @ReadOnlyComposable
- get() = LocalDecoratedWindowStyle.current
diff --git a/decorated-window/src/main/kotlin/org/jetbrains/jewel/window/TitleBar.Linux.kt b/decorated-window/src/main/kotlin/org/jetbrains/jewel/window/TitleBar.Linux.kt
deleted file mode 100644
index 04e50248a1..0000000000
--- a/decorated-window/src/main/kotlin/org/jetbrains/jewel/window/TitleBar.Linux.kt
+++ /dev/null
@@ -1,134 +0,0 @@
-package org.jetbrains.jewel.window
-
-import androidx.compose.foundation.focusable
-import androidx.compose.foundation.layout.PaddingValues
-import androidx.compose.foundation.layout.size
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.input.pointer.PointerButton
-import androidx.compose.ui.input.pointer.PointerEventPass
-import androidx.compose.ui.input.pointer.PointerEventType
-import androidx.compose.ui.input.pointer.onPointerEvent
-import androidx.compose.ui.platform.LocalViewConfiguration
-import androidx.compose.ui.unit.dp
-import com.jetbrains.JBR
-import org.jetbrains.jewel.foundation.theme.JewelTheme
-import org.jetbrains.jewel.ui.component.Icon
-import org.jetbrains.jewel.ui.component.IconButton
-import org.jetbrains.jewel.ui.component.styling.IconButtonStyle
-import org.jetbrains.jewel.ui.painter.PainterHint
-import org.jetbrains.jewel.ui.painter.PainterProvider
-import org.jetbrains.jewel.ui.painter.PainterProviderScope
-import org.jetbrains.jewel.ui.painter.PainterSuffixHint
-import org.jetbrains.jewel.window.styling.TitleBarStyle
-import java.awt.Frame
-import java.awt.event.MouseEvent
-import java.awt.event.WindowEvent
-
-@Composable
-internal fun DecoratedWindowScope.TitleBarOnLinux(
- modifier: Modifier = Modifier,
- gradientStartColor: Color = Color.Unspecified,
- style: TitleBarStyle = JewelTheme.defaultTitleBarStyle,
- content: @Composable TitleBarScope.(DecoratedWindowState) -> Unit,
-) {
- var lastPress = 0L
- val viewConfig = LocalViewConfiguration.current
- TitleBarImpl(
- modifier.onPointerEvent(PointerEventType.Press, PointerEventPass.Main) {
- if (this.currentEvent.button == PointerButton.Primary &&
- this.currentEvent.changes.any { changed -> !changed.isConsumed }
- ) {
- JBR.getWindowMove()?.startMovingTogetherWithMouse(window, MouseEvent.BUTTON1)
- if (System.currentTimeMillis() - lastPress in
- viewConfig.doubleTapMinTimeMillis..viewConfig.doubleTapTimeoutMillis
- ) {
- if (state.isMaximized) {
- window.extendedState = Frame.NORMAL
- } else {
- window.extendedState = Frame.MAXIMIZED_BOTH
- }
- }
- lastPress = System.currentTimeMillis()
- }
- },
- gradientStartColor,
- style,
- { _, _ -> PaddingValues(0.dp) },
- ) { state ->
- CloseButton(
- { window.dispatchEvent(WindowEvent(window, WindowEvent.WINDOW_CLOSING)) },
- state,
- style,
- )
-
- if (state.isMaximized) {
- ControlButton(
- { window.extendedState = Frame.NORMAL },
- state,
- style.icons.restoreButton,
- "Restore",
- )
- } else {
- ControlButton(
- { window.extendedState = Frame.MAXIMIZED_BOTH },
- state,
- style.icons.maximizeButton,
- "Maximize",
- )
- }
- ControlButton(
- { window.extendedState = Frame.ICONIFIED },
- state,
- style.icons.minimizeButton,
- "Minimize",
- )
- content(state)
- }
-}
-
-@Composable
-private fun TitleBarScope.CloseButton(
- onClick: () -> Unit,
- state: DecoratedWindowState,
- style: TitleBarStyle = JewelTheme.defaultTitleBarStyle,
-) {
- ControlButton(
- onClick,
- state,
- style.icons.closeButton,
- "Close",
- style,
- style.paneCloseButtonStyle,
- )
-}
-
-@Composable
-private fun TitleBarScope.ControlButton(
- onClick: () -> Unit,
- state: DecoratedWindowState,
- painterProvider: PainterProvider,
- description: String,
- style: TitleBarStyle = JewelTheme.defaultTitleBarStyle,
- iconButtonStyle: IconButtonStyle = style.paneButtonStyle,
-) {
- IconButton(
- onClick,
- Modifier.align(Alignment.End).focusable(false).size(style.metrics.titlePaneButtonSize),
- style = iconButtonStyle,
- ) {
- Icon(
- painterProvider.getPainter(if (state.isActive) PainterHint else Inactive).value,
- description,
- )
- }
-}
-
-private object Inactive : PainterSuffixHint() {
-
- override fun PainterProviderScope.suffix(): String = "Inactive"
-
- override fun toString(): String = "Inactive"
-}
diff --git a/decorated-window/src/main/kotlin/org/jetbrains/jewel/window/TitleBar.MacOS.kt b/decorated-window/src/main/kotlin/org/jetbrains/jewel/window/TitleBar.MacOS.kt
deleted file mode 100644
index 63475e2d14..0000000000
--- a/decorated-window/src/main/kotlin/org/jetbrains/jewel/window/TitleBar.MacOS.kt
+++ /dev/null
@@ -1,103 +0,0 @@
-package org.jetbrains.jewel.window
-
-import androidx.compose.foundation.layout.PaddingValues
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.remember
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.toArgb
-import androidx.compose.ui.node.ModifierNodeElement
-import androidx.compose.ui.platform.InspectorInfo
-import androidx.compose.ui.platform.debugInspectorInfo
-import androidx.compose.ui.unit.dp
-import com.jetbrains.JBR
-import org.jetbrains.jewel.foundation.theme.JewelTheme
-import org.jetbrains.jewel.window.styling.TitleBarStyle
-import org.jetbrains.jewel.window.utils.macos.MacUtil
-
-public fun Modifier.newFullscreenControls(newControls: Boolean = true): Modifier =
- this then NewFullscreenControlsElement(
- newControls,
- debugInspectorInfo {
- name = "newFullscreenControls"
- value = newControls
- },
- )
-
-private class NewFullscreenControlsElement(
- val newControls: Boolean,
- val inspectorInfo: InspectorInfo.() -> Unit,
-) : ModifierNodeElement() {
-
- override fun create(): NewFullscreenControlsNode =
- NewFullscreenControlsNode(newControls)
-
- override fun equals(other: Any?): Boolean {
- if (this === other) return true
- val otherModifier = other as? NewFullscreenControlsElement
- ?: return false
- return newControls == otherModifier.newControls
- }
-
- override fun hashCode(): Int = newControls.hashCode()
-
- override fun InspectorInfo.inspectableProperties() {
- inspectorInfo()
- }
-
- override fun update(node: NewFullscreenControlsNode) {
- node.newControls = newControls
- }
-}
-
-private class NewFullscreenControlsNode(var newControls: Boolean) : Modifier.Node()
-
-@Composable
-internal fun DecoratedWindowScope.TitleBarOnMacOs(
- modifier: Modifier = Modifier,
- gradientStartColor: Color = Color.Unspecified,
- style: TitleBarStyle = JewelTheme.defaultTitleBarStyle,
- content: @Composable TitleBarScope.(DecoratedWindowState) -> Unit,
-) {
- val newFullscreenControls = modifier.foldOut(false) { e, r ->
- if (e is NewFullscreenControlsElement) {
- e.newControls
- } else {
- r
- }
- }
-
- if (newFullscreenControls) {
- System.setProperty("apple.awt.newFullScreeControls", true.toString())
- System.setProperty(
- "apple.awt.newFullScreeControls.background",
- "${style.colors.fullscreenControlButtonsBackground.toArgb()}",
- )
- MacUtil.updateColors(window)
- } else {
- System.clearProperty("apple.awt.newFullScreeControls")
- System.clearProperty("apple.awt.newFullScreeControls.background")
- }
-
- val titleBar = remember { JBR.getWindowDecorations().createCustomTitleBar() }
-
- TitleBarImpl(
- modifier = modifier.customTitleBarMouseEventHandler(titleBar),
- gradientStartColor = gradientStartColor,
- style = style,
- applyTitleBar = { height, state ->
- if (state.isFullscreen) {
- MacUtil.updateFullScreenButtons(window)
- }
- titleBar.height = height.value
- JBR.getWindowDecorations().setCustomTitleBar(window, titleBar)
-
- if (state.isFullscreen && newFullscreenControls) {
- PaddingValues(start = 80.dp)
- } else {
- PaddingValues(start = titleBar.leftInset.dp, end = titleBar.rightInset.dp)
- }
- },
- content = content,
- )
-}
diff --git a/decorated-window/src/main/kotlin/org/jetbrains/jewel/window/TitleBar.Windows.kt b/decorated-window/src/main/kotlin/org/jetbrains/jewel/window/TitleBar.Windows.kt
deleted file mode 100644
index e342f36bae..0000000000
--- a/decorated-window/src/main/kotlin/org/jetbrains/jewel/window/TitleBar.Windows.kt
+++ /dev/null
@@ -1,65 +0,0 @@
-package org.jetbrains.jewel.window
-
-import androidx.compose.foundation.layout.PaddingValues
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.remember
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.input.pointer.PointerEventPass
-import androidx.compose.ui.input.pointer.PointerEventType
-import androidx.compose.ui.input.pointer.pointerInput
-import androidx.compose.ui.unit.dp
-import com.jetbrains.JBR
-import com.jetbrains.WindowDecorations.CustomTitleBar
-import kotlinx.coroutines.currentCoroutineContext
-import kotlinx.coroutines.isActive
-import org.jetbrains.jewel.foundation.theme.JewelTheme
-import org.jetbrains.jewel.ui.util.isDark
-import org.jetbrains.jewel.window.styling.TitleBarStyle
-
-@Composable
-internal fun DecoratedWindowScope.TitleBarOnWindows(
- modifier: Modifier = Modifier,
- gradientStartColor: Color = Color.Unspecified,
- style: TitleBarStyle = JewelTheme.defaultTitleBarStyle,
- content: @Composable TitleBarScope.(DecoratedWindowState) -> Unit,
-) {
- val titleBar = remember { JBR.getWindowDecorations().createCustomTitleBar() }
-
- TitleBarImpl(
- modifier = modifier.customTitleBarMouseEventHandler(titleBar),
- gradientStartColor = gradientStartColor,
- style = style,
- applyTitleBar = { height, _ ->
- titleBar.height = height.value
- titleBar.putProperty("controls.dark", style.colors.background.isDark())
- JBR.getWindowDecorations().setCustomTitleBar(window, titleBar)
- PaddingValues(start = titleBar.leftInset.dp, end = titleBar.rightInset.dp)
- },
- content = content,
- )
-}
-
-internal fun Modifier.customTitleBarMouseEventHandler(titleBar: CustomTitleBar): Modifier =
- pointerInput(Unit) {
- val currentContext = currentCoroutineContext()
- awaitPointerEventScope {
- var inUserControl = false
- while (currentContext.isActive) {
- val event = awaitPointerEvent(PointerEventPass.Main)
- event.changes.forEach {
- if (!it.isConsumed && !inUserControl) {
- titleBar.forceHitTest(false)
- } else {
- if (event.type == PointerEventType.Press) {
- inUserControl = true
- }
- if (event.type == PointerEventType.Release) {
- inUserControl = false
- }
- titleBar.forceHitTest(true)
- }
- }
- }
- }
- }
diff --git a/decorated-window/src/main/kotlin/org/jetbrains/jewel/window/TitleBar.kt b/decorated-window/src/main/kotlin/org/jetbrains/jewel/window/TitleBar.kt
deleted file mode 100644
index acd1218ff1..0000000000
--- a/decorated-window/src/main/kotlin/org/jetbrains/jewel/window/TitleBar.kt
+++ /dev/null
@@ -1,294 +0,0 @@
-package org.jetbrains.jewel.window
-
-import androidx.compose.foundation.background
-import androidx.compose.foundation.layout.PaddingValues
-import androidx.compose.foundation.layout.Spacer
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.height
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.CompositionLocalProvider
-import androidx.compose.runtime.Stable
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.remember
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.focus.focusProperties
-import androidx.compose.ui.graphics.Brush
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.SolidColor
-import androidx.compose.ui.graphics.isUnspecified
-import androidx.compose.ui.graphics.painter.Painter
-import androidx.compose.ui.layout.Layout
-import androidx.compose.ui.layout.Measurable
-import androidx.compose.ui.layout.MeasurePolicy
-import androidx.compose.ui.layout.MeasureResult
-import androidx.compose.ui.layout.MeasureScope
-import androidx.compose.ui.layout.Placeable
-import androidx.compose.ui.layout.layoutId
-import androidx.compose.ui.layout.onSizeChanged
-import androidx.compose.ui.node.ModifierNodeElement
-import androidx.compose.ui.node.ParentDataModifierNode
-import androidx.compose.ui.platform.InspectableValue
-import androidx.compose.ui.platform.InspectorInfo
-import androidx.compose.ui.platform.LocalDensity
-import androidx.compose.ui.platform.NoInspectorInfo
-import androidx.compose.ui.platform.debugInspectorInfo
-import androidx.compose.ui.unit.Constraints
-import androidx.compose.ui.unit.Density
-import androidx.compose.ui.unit.Dp
-import androidx.compose.ui.unit.dp
-import androidx.compose.ui.unit.offset
-import org.jetbrains.jewel.foundation.theme.JewelTheme
-import org.jetbrains.jewel.foundation.theme.LocalContentColor
-import org.jetbrains.jewel.foundation.theme.OverrideDarkMode
-import org.jetbrains.jewel.ui.component.styling.LocalDefaultDropdownStyle
-import org.jetbrains.jewel.ui.component.styling.LocalIconButtonStyle
-import org.jetbrains.jewel.ui.util.isDark
-import org.jetbrains.jewel.window.styling.TitleBarStyle
-import org.jetbrains.jewel.window.utils.DesktopPlatform
-import org.jetbrains.jewel.window.utils.macos.MacUtil
-import java.awt.Window
-import kotlin.math.max
-
-internal const val TITLE_BAR_COMPONENT_LAYOUT_ID_PREFIX = "__TITLE_BAR_"
-
-internal const val TITLE_BAR_LAYOUT_ID = "__TITLE_BAR_CONTENT__"
-
-internal const val TITLE_BAR_BORDER_LAYOUT_ID = "__TITLE_BAR_BORDER__"
-
-@Composable
-public fun DecoratedWindowScope.TitleBar(
- modifier: Modifier = Modifier,
- gradientStartColor: Color = Color.Unspecified,
- style: TitleBarStyle = JewelTheme.defaultTitleBarStyle,
- content: @Composable TitleBarScope.(DecoratedWindowState) -> Unit,
-) {
- when (DesktopPlatform.Current) {
- DesktopPlatform.Linux -> TitleBarOnLinux(modifier, gradientStartColor, style, content)
- DesktopPlatform.Windows -> TitleBarOnWindows(modifier, gradientStartColor, style, content)
- DesktopPlatform.MacOS -> TitleBarOnMacOs(modifier, gradientStartColor, style, content)
- DesktopPlatform.Unknown -> error("TitleBar is not supported on this platform(${System.getProperty("os.name")})")
- }
-}
-
-@Composable
-internal fun DecoratedWindowScope.TitleBarImpl(
- modifier: Modifier = Modifier,
- gradientStartColor: Color = Color.Unspecified,
- style: TitleBarStyle = JewelTheme.defaultTitleBarStyle,
- applyTitleBar: (Dp, DecoratedWindowState) -> PaddingValues,
- content: @Composable TitleBarScope.(DecoratedWindowState) -> Unit,
-) {
- val titleBarInfo = LocalTitleBarInfo.current
-
- val background by style.colors.backgroundFor(state)
-
- val density = LocalDensity.current
-
- val backgroundBrush = remember(background, gradientStartColor) {
- if (gradientStartColor.isUnspecified) {
- SolidColor(background)
- } else {
- with(density) {
- Brush.horizontalGradient(
- 0.0f to background,
- 0.5f to gradientStartColor,
- 1.0f to background,
- startX = style.metrics.gradientStartX.toPx(),
- endX = style.metrics.gradientEndX.toPx(),
- )
- }
- }
- }
-
- Layout(
- content = {
- CompositionLocalProvider(
- LocalContentColor provides style.colors.content,
- LocalIconButtonStyle provides style.iconButtonStyle,
- LocalDefaultDropdownStyle provides style.dropdownStyle,
- ) {
- OverrideDarkMode(background.isDark()) {
- val scope = TitleBarScopeImpl(titleBarInfo.title, titleBarInfo.icon)
- scope.content(state)
- }
- }
- },
- modifier = modifier.background(backgroundBrush)
- .focusProperties { canFocus = false }
- .layoutId(TITLE_BAR_LAYOUT_ID)
- .height(style.metrics.height)
- .onSizeChanged { with(density) { applyTitleBar(it.height.toDp(), state) } }
- .fillMaxWidth(),
- measurePolicy = rememberTitleBarMeasurePolicy(
- window,
- state,
- applyTitleBar,
- ),
- )
-
- Spacer(
- Modifier.layoutId(TITLE_BAR_BORDER_LAYOUT_ID)
- .height(1.dp)
- .fillMaxWidth()
- .background(style.colors.border),
- )
-}
-
-internal class TitleBarMeasurePolicy(
- private val window: Window,
- private val state: DecoratedWindowState,
- private val applyTitleBar: (Dp, DecoratedWindowState) -> PaddingValues,
-) : MeasurePolicy {
-
- override fun MeasureScope.measure(measurables: List, constraints: Constraints): MeasureResult {
- if (measurables.isEmpty()) {
- return layout(width = constraints.minWidth, height = constraints.minHeight) {}
- }
-
- var occupiedSpaceHorizontally = 0
-
- var maxSpaceVertically = constraints.minHeight
- val contentConstraints = constraints.copy(minWidth = 0, minHeight = 0)
- val measuredPlaceable = mutableListOf>()
-
- for (it in measurables) {
- val placeable = it.measure(contentConstraints.offset(horizontal = -occupiedSpaceHorizontally))
- if (constraints.maxWidth < occupiedSpaceHorizontally + placeable.width) {
- break
- }
- occupiedSpaceHorizontally += placeable.width
- maxSpaceVertically = max(maxSpaceVertically, placeable.height)
- measuredPlaceable += it to placeable
- }
-
- val boxHeight = maxSpaceVertically
-
- val contentPadding = applyTitleBar(boxHeight.toDp(), state)
-
- val leftInset = contentPadding.calculateLeftPadding(layoutDirection).roundToPx()
- val rightInset = contentPadding.calculateRightPadding(layoutDirection).roundToPx()
-
- occupiedSpaceHorizontally += leftInset
- occupiedSpaceHorizontally += rightInset
-
- val boxWidth = maxOf(constraints.minWidth, occupiedSpaceHorizontally)
-
- return layout(boxWidth, boxHeight) {
- if (state.isFullscreen) {
- MacUtil.updateFullScreenButtons(window)
- }
- val placeableGroups =
- measuredPlaceable.groupBy { (measurable, _) ->
- (measurable.parentData as? TitleBarChildDataNode)?.horizontalAlignment
- ?: Alignment.CenterHorizontally
- }
-
- var headUsedSpace = leftInset
- var trailerUsedSpace = rightInset
-
- placeableGroups[Alignment.Start]?.forEach { (_, placeable) ->
- val x = headUsedSpace
- val y = Alignment.CenterVertically.align(placeable.height, boxHeight)
- placeable.placeRelative(x, y)
- headUsedSpace += placeable.width
- }
- placeableGroups[Alignment.End]?.forEach { (_, placeable) ->
- val x = boxWidth - placeable.width - trailerUsedSpace
- val y = Alignment.CenterVertically.align(placeable.height, boxHeight)
- placeable.placeRelative(x, y)
- trailerUsedSpace += placeable.width
- }
-
- val centerPlaceable = placeableGroups[Alignment.CenterHorizontally].orEmpty()
-
- val requiredCenterSpace = centerPlaceable.sumOf { it.second.width }
- val minX = headUsedSpace
- val maxX = boxWidth - trailerUsedSpace - requiredCenterSpace
- var centerX = (boxWidth - requiredCenterSpace) / 2
-
- if (minX <= maxX) {
- if (centerX > maxX) {
- centerX = maxX
- }
- if (centerX < minX) {
- centerX = minX
- }
-
- centerPlaceable.forEach { (_, placeable) ->
- val x = centerX
- val y = Alignment.CenterVertically.align(placeable.height, boxHeight)
- placeable.placeRelative(x, y)
- centerX += placeable.width
- }
- }
- }
- }
-}
-
-@Composable
-internal fun rememberTitleBarMeasurePolicy(
- window: Window,
- state: DecoratedWindowState,
- applyTitleBar: (Dp, DecoratedWindowState) -> PaddingValues,
-): MeasurePolicy =
- remember(window, state, applyTitleBar) {
- TitleBarMeasurePolicy(window, state, applyTitleBar)
- }
-
-public interface TitleBarScope {
-
- public val title: String
-
- public val icon: Painter?
-
- @Stable
- public fun Modifier.align(alignment: Alignment.Horizontal): Modifier
-}
-
-private class TitleBarScopeImpl(
- override val title: String,
- override val icon: Painter?,
-) : TitleBarScope {
-
- override fun Modifier.align(alignment: Alignment.Horizontal): Modifier =
- this then TitleBarChildDataElement(
- alignment,
- debugInspectorInfo {
- name = "align"
- value = alignment
- },
- )
-}
-
-private class TitleBarChildDataElement(
- val horizontalAlignment: Alignment.Horizontal,
- val inspectorInfo: InspectorInfo.() -> Unit = NoInspectorInfo,
-) : ModifierNodeElement(), InspectableValue {
-
- override fun create(): TitleBarChildDataNode = TitleBarChildDataNode(horizontalAlignment)
-
- override fun equals(other: Any?): Boolean {
- if (this === other) return true
- val otherModifier = other as? TitleBarChildDataElement ?: return false
- return horizontalAlignment == otherModifier.horizontalAlignment
- }
-
- override fun hashCode(): Int = horizontalAlignment.hashCode()
-
- override fun update(node: TitleBarChildDataNode) {
- node.horizontalAlignment = horizontalAlignment
- }
-
- override fun InspectorInfo.inspectableProperties() {
- inspectorInfo()
- }
-}
-
-private class TitleBarChildDataNode(
- var horizontalAlignment: Alignment.Horizontal,
-) : ParentDataModifierNode, Modifier.Node() {
-
- override fun Density.modifyParentData(parentData: Any?) =
- this@TitleBarChildDataNode
-}
diff --git a/decorated-window/src/main/kotlin/org/jetbrains/jewel/window/styling/DecoratedWindowStyling.kt b/decorated-window/src/main/kotlin/org/jetbrains/jewel/window/styling/DecoratedWindowStyling.kt
deleted file mode 100644
index cc15f5ac62..0000000000
--- a/decorated-window/src/main/kotlin/org/jetbrains/jewel/window/styling/DecoratedWindowStyling.kt
+++ /dev/null
@@ -1,53 +0,0 @@
-package org.jetbrains.jewel.window.styling
-
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.Immutable
-import androidx.compose.runtime.ProvidableCompositionLocal
-import androidx.compose.runtime.State
-import androidx.compose.runtime.rememberUpdatedState
-import androidx.compose.runtime.staticCompositionLocalOf
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.unit.Dp
-import org.jetbrains.jewel.foundation.GenerateDataFunctions
-import org.jetbrains.jewel.window.DecoratedWindowState
-
-@Immutable
-@GenerateDataFunctions
-public class DecoratedWindowStyle(
- public val colors: DecoratedWindowColors,
- public val metrics: DecoratedWindowMetrics,
-) {
-
- public companion object
-}
-
-@Immutable
-@GenerateDataFunctions
-public class DecoratedWindowColors(
- public val border: Color,
- public val borderInactive: Color,
-) {
-
- @Composable
- public fun borderFor(state: DecoratedWindowState): State =
- rememberUpdatedState(
- when {
- !state.isActive -> borderInactive
- else -> border
- },
- )
-
- public companion object
-}
-
-@Immutable
-@GenerateDataFunctions
-public class DecoratedWindowMetrics(public val borderWidth: Dp) {
-
- public companion object
-}
-
-public val LocalDecoratedWindowStyle: ProvidableCompositionLocal =
- staticCompositionLocalOf {
- error("No DecoratedWindowStyle provided. Have you forgotten the theme?")
- }
diff --git a/decorated-window/src/main/kotlin/org/jetbrains/jewel/window/styling/TitleBarStyling.kt b/decorated-window/src/main/kotlin/org/jetbrains/jewel/window/styling/TitleBarStyling.kt
deleted file mode 100644
index ca0d907f2c..0000000000
--- a/decorated-window/src/main/kotlin/org/jetbrains/jewel/window/styling/TitleBarStyling.kt
+++ /dev/null
@@ -1,102 +0,0 @@
-package org.jetbrains.jewel.window.styling
-
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.Immutable
-import androidx.compose.runtime.ProvidableCompositionLocal
-import androidx.compose.runtime.Stable
-import androidx.compose.runtime.State
-import androidx.compose.runtime.rememberUpdatedState
-import androidx.compose.runtime.staticCompositionLocalOf
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.unit.Dp
-import androidx.compose.ui.unit.DpSize
-import org.jetbrains.jewel.foundation.GenerateDataFunctions
-import org.jetbrains.jewel.ui.component.styling.DropdownStyle
-import org.jetbrains.jewel.ui.component.styling.IconButtonStyle
-import org.jetbrains.jewel.ui.painter.PainterProvider
-import org.jetbrains.jewel.window.DecoratedWindowState
-
-@Stable
-@GenerateDataFunctions
-public class TitleBarStyle(
- public val colors: TitleBarColors,
- public val metrics: TitleBarMetrics,
- public val icons: TitleBarIcons,
- public val dropdownStyle: DropdownStyle,
- public val iconButtonStyle: IconButtonStyle,
- public val paneButtonStyle: IconButtonStyle,
- public val paneCloseButtonStyle: IconButtonStyle,
-) {
-
- public companion object
-}
-
-@Immutable
-@GenerateDataFunctions
-public class TitleBarColors(
- public val background: Color,
- public val inactiveBackground: Color,
- public val content: Color,
- public val border: Color,
-
- // The background color for newControlButtons(three circles in left top corner) in MacOS
- // fullscreen mode
- public val fullscreenControlButtonsBackground: Color,
-
- // The hover and press background color for window control buttons(minimize, maximize) in Linux
- public val titlePaneButtonHoveredBackground: Color,
- public val titlePaneButtonPressedBackground: Color,
-
- // The hover and press background color for window close button in Linux
- public val titlePaneCloseButtonHoveredBackground: Color,
- public val titlePaneCloseButtonPressedBackground: Color,
-
- // The hover and press background color for IconButtons in title bar content
- public val iconButtonHoveredBackground: Color,
- public val iconButtonPressedBackground: Color,
-
- // The hover and press background color for Dropdown in title bar content
- public val dropdownPressedBackground: Color,
- public val dropdownHoveredBackground: Color,
-) {
-
- @Composable
- public fun backgroundFor(state: DecoratedWindowState): State =
- rememberUpdatedState(
- when {
- !state.isActive -> inactiveBackground
- else -> background
- },
- )
-
- public companion object
-}
-
-@Immutable
-@GenerateDataFunctions
-public class TitleBarMetrics(
- public val height: Dp,
- public val gradientStartX: Dp,
- public val gradientEndX: Dp,
- public val titlePaneButtonSize: DpSize,
-) {
-
- public companion object
-}
-
-@Immutable
-@GenerateDataFunctions
-public class TitleBarIcons(
- public val minimizeButton: PainterProvider,
- public val maximizeButton: PainterProvider,
- public val restoreButton: PainterProvider,
- public val closeButton: PainterProvider,
-) {
-
- public companion object
-}
-
-public val LocalTitleBarStyle: ProvidableCompositionLocal =
- staticCompositionLocalOf {
- error("No TitleBarStyle provided. Have you forgotten the theme?")
- }
diff --git a/decorated-window/src/main/kotlin/org/jetbrains/jewel/window/utils/DesktopPlatform.kt b/decorated-window/src/main/kotlin/org/jetbrains/jewel/window/utils/DesktopPlatform.kt
deleted file mode 100644
index 51872dc474..0000000000
--- a/decorated-window/src/main/kotlin/org/jetbrains/jewel/window/utils/DesktopPlatform.kt
+++ /dev/null
@@ -1,22 +0,0 @@
-package org.jetbrains.jewel.window.utils
-
-public enum class DesktopPlatform {
- Linux,
- Windows,
- MacOS,
- Unknown,
- ;
-
- public companion object {
-
- public val Current: DesktopPlatform by lazy {
- val name = System.getProperty("os.name")
- when {
- name?.startsWith("Linux") == true -> Linux
- name?.startsWith("Win") == true -> Windows
- name == "Mac OS X" -> MacOS
- else -> Unknown
- }
- }
- }
-}
diff --git a/decorated-window/src/main/kotlin/org/jetbrains/jewel/window/utils/JnaLoader.kt b/decorated-window/src/main/kotlin/org/jetbrains/jewel/window/utils/JnaLoader.kt
deleted file mode 100644
index 7e136b0f65..0000000000
--- a/decorated-window/src/main/kotlin/org/jetbrains/jewel/window/utils/JnaLoader.kt
+++ /dev/null
@@ -1,43 +0,0 @@
-package org.jetbrains.jewel.window.utils
-
-import com.sun.jna.Native
-import java.util.logging.Level
-import java.util.logging.Logger
-import kotlin.system.measureTimeMillis
-
-internal object JnaLoader {
-
- private var loaded: Boolean? = null
- private val logger = Logger.getLogger(JnaLoader::class.java.simpleName)
-
- @Synchronized
- fun load() {
- if (loaded == null) {
- loaded = false
- try {
- val time = measureTimeMillis { Native.POINTER_SIZE }
- logger.info("JNA library (${Native.POINTER_SIZE shl 3}-bit) loaded in $time ms")
- loaded = true
- } catch (@Suppress("TooGenericExceptionCaught") t: Throwable) {
- logger.log(
- Level.WARNING,
- "Unable to load JNA library(os=${
- System.getProperty("os.name")
- } ${System.getProperty("os.version")}, jna.boot.library.path=${
- System.getProperty("jna.boot.library.path")
- })",
- t,
- )
- }
- }
- }
-
- @get:Synchronized
- val isLoaded: Boolean
- get() {
- if (loaded == null) {
- load()
- }
- return loaded ?: false
- }
-}
diff --git a/decorated-window/src/main/kotlin/org/jetbrains/jewel/window/utils/UnsafeAccessing.kt b/decorated-window/src/main/kotlin/org/jetbrains/jewel/window/utils/UnsafeAccessing.kt
deleted file mode 100644
index ed0e7920a2..0000000000
--- a/decorated-window/src/main/kotlin/org/jetbrains/jewel/window/utils/UnsafeAccessing.kt
+++ /dev/null
@@ -1,73 +0,0 @@
-package org.jetbrains.jewel.window.utils
-
-import sun.misc.Unsafe
-import java.lang.reflect.AccessibleObject
-import java.util.logging.Level
-import java.util.logging.Logger
-
-internal object UnsafeAccessing {
-
- private val logger = Logger.getLogger(UnsafeAccessing::class.java.simpleName)
-
- private val unsafe: Any? by lazy {
- try {
- val theUnsafe = Unsafe::class.java.getDeclaredField("theUnsafe")
- theUnsafe.isAccessible = true
- theUnsafe.get(null) as Unsafe
- } catch (@Suppress("TooGenericExceptionCaught") error: Throwable) {
- logger.log(Level.WARNING, "Unsafe accessing initializing failed.", error)
- null
- }
- }
-
- val desktopModule by lazy { ModuleLayer.boot().findModule("java.desktop").get() }
-
- val ownerModule: Module by lazy { this.javaClass.module }
-
- private val isAccessibleFieldOffset: Long? by lazy {
- try {
- (unsafe as? Unsafe)?.objectFieldOffset(Parent::class.java.getDeclaredField("first"))
- } catch (_: Throwable) {
- null
- }
- }
-
- private val implAddOpens by lazy {
- try {
- Module::class.java
- .getDeclaredMethod("implAddOpens", String::class.java, Module::class.java)
- .accessible()
- } catch (_: Throwable) {
- null
- }
- }
-
- fun assignAccessibility(obj: AccessibleObject) {
- try {
- val theUnsafe = unsafe as? Unsafe ?: return
- val offset = isAccessibleFieldOffset ?: return
- theUnsafe.putBooleanVolatile(obj, offset, true)
- } catch (_: Throwable) {
- // ignore
- }
- }
-
- fun assignAccessibility(module: Module, packages: List) {
- try {
- packages.forEach { implAddOpens?.invoke(module, it, ownerModule) }
- } catch (_: Throwable) {
- // ignore
- }
- }
-
- private class Parent {
-
- var first = false
-
- @Volatile
- var second: Any? = null
- }
-}
-
-internal fun T.accessible(): T =
- apply { UnsafeAccessing.assignAccessibility(this) }
diff --git a/decorated-window/src/main/kotlin/org/jetbrains/jewel/window/utils/macos/Foundation.kt b/decorated-window/src/main/kotlin/org/jetbrains/jewel/window/utils/macos/Foundation.kt
deleted file mode 100644
index 193b29c7eb..0000000000
--- a/decorated-window/src/main/kotlin/org/jetbrains/jewel/window/utils/macos/Foundation.kt
+++ /dev/null
@@ -1,98 +0,0 @@
-package org.jetbrains.jewel.window.utils.macos
-
-import com.sun.jna.Function
-import com.sun.jna.Library
-import com.sun.jna.Native
-import com.sun.jna.Pointer
-import org.jetbrains.jewel.window.utils.JnaLoader
-import java.lang.reflect.Proxy
-import java.util.Arrays
-import java.util.Collections
-import java.util.logging.Level
-import java.util.logging.Logger
-
-internal object Foundation {
-
- private val logger = Logger.getLogger(Foundation::class.java.simpleName)
-
- init {
- if (!JnaLoader.isLoaded) {
- logger.log(Level.WARNING, "JNA is not loaded")
- }
- }
-
- private val myFoundationLibrary: FoundationLibrary? by lazy {
- try {
- Native.load(
- "Foundation",
- FoundationLibrary::class.java,
- Collections.singletonMap("jna.encoding", "UTF8"),
- )
- } catch (_: Throwable) {
- null
- }
- }
-
- private val myObjcMsgSend: Function? by lazy {
- try {
- (Proxy.getInvocationHandler(myFoundationLibrary) as Library.Handler).nativeLibrary.getFunction("objc_msgSend")
- } catch (_: Throwable) {
- null
- }
- }
-
- /**
- * Get the ID of the NSClass with className
- */
- fun getObjcClass(className: String?): ID? = myFoundationLibrary?.objc_getClass(className)
-
- fun getProtocol(name: String?): ID? = myFoundationLibrary?.objc_getProtocol(name)
-
- fun createSelector(s: String?): Pointer? = myFoundationLibrary?.sel_registerName(s)
-
- private fun prepInvoke(id: ID?, selector: Pointer?, args: Array): Array {
- val invokArgs = arrayOfNulls(args.size + 2)
- invokArgs[0] = id
- invokArgs[1] = selector
- System.arraycopy(args, 0, invokArgs, 2, args.size)
- return invokArgs
- }
-
- // objc_msgSend is called with the calling convention of the target method
- // on x86_64 this does not make a difference, but arm64 uses a different calling convention for varargs
- // it is therefore important to not call objc_msgSend as a vararg function
- operator fun invoke(id: ID?, selector: Pointer?, vararg args: Any?): ID =
- ID(myObjcMsgSend?.invokeLong(prepInvoke(id, selector, args)) ?: 0)
-
- /**
- * Invokes the given vararg selector.
- * Expects `NSArray arrayWithObjects:(id), ...` like signature, i.e. exactly one fixed argument, followed by varargs.
- */
- fun invokeVarArg(id: ID?, selector: Pointer?, vararg args: Any?): ID {
- // c functions and objc methods have at least 1 fixed argument, we therefore need to separate out the first argument
- return myFoundationLibrary?.objc_msgSend(
- id,
- selector,
- args[0],
- *Arrays.copyOfRange(args, 1, args.size),
- ) ?: ID.NIL
- }
-
- operator fun invoke(cls: String?, selector: String?, vararg args: Any?): ID =
- invoke(getObjcClass(cls), createSelector(selector), *args)
-
- fun invokeVarArg(cls: String?, selector: String?, vararg args: Any?): ID =
- invokeVarArg(getObjcClass(cls), createSelector(selector), *args)
-
- fun safeInvoke(stringCls: String?, stringSelector: String?, vararg args: Any?): ID {
- val cls = getObjcClass(stringCls)
- val selector = createSelector(stringSelector)
- if (!invoke(cls, "respondsToSelector:", selector).booleanValue()) {
- error("Missing selector $stringSelector for $stringCls")
- }
- return invoke(cls, selector, *args)
- }
-
- operator fun invoke(id: ID?, selector: String?, vararg args: Any?): ID =
- invoke(id, createSelector(selector), *args)
-}
diff --git a/decorated-window/src/main/kotlin/org/jetbrains/jewel/window/utils/macos/FoundationLibrary.kt b/decorated-window/src/main/kotlin/org/jetbrains/jewel/window/utils/macos/FoundationLibrary.kt
deleted file mode 100644
index a4c93807e2..0000000000
--- a/decorated-window/src/main/kotlin/org/jetbrains/jewel/window/utils/macos/FoundationLibrary.kt
+++ /dev/null
@@ -1,89 +0,0 @@
-package org.jetbrains.jewel.window.utils.macos
-
-import com.sun.jna.Callback
-import com.sun.jna.Library
-import com.sun.jna.Pointer
-
-internal interface FoundationLibrary : Library {
- fun NSLog(pString: Pointer?, thing: Any?)
- fun NSFullUserName(): ID?
- fun objc_allocateClassPair(supercls: ID?, name: String?, extraBytes: Int): ID?
- fun objc_registerClassPair(cls: ID?)
- fun CFStringCreateWithBytes(
- allocator: Pointer?,
- bytes: ByteArray?,
- byteCount: Int,
- encoding: Int,
- isExternalRepresentation: Byte,
- ): ID?
-
- fun CFStringGetCString(theString: ID?, buffer: ByteArray?, bufferSize: Int, encoding: Int): Byte
- fun CFStringGetLength(theString: ID?): Int
- fun CFStringConvertNSStringEncodingToEncoding(nsEncoding: Long): Long
- fun CFStringConvertEncodingToIANACharSetName(cfEncoding: Long): ID?
- fun CFStringConvertIANACharSetNameToEncoding(encodingName: ID?): Long
- fun CFStringConvertEncodingToNSStringEncoding(cfEncoding: Long): Long
- fun CFRetain(cfTypeRef: ID?)
- fun CFRelease(cfTypeRef: ID?)
- fun CFGetRetainCount(cfTypeRef: Pointer?): Int
- fun objc_getClass(className: String?): ID?
- fun objc_getProtocol(name: String?): ID?
- fun class_createInstance(pClass: ID?, extraBytes: Int): ID?
- fun sel_registerName(selectorName: String?): Pointer?
- fun class_replaceMethod(cls: ID?, selName: Pointer?, impl: Callback?, types: String?): ID?
- fun objc_getMetaClass(name: String?): ID?
-
- /**
- * Note: Vararg version. Should only be used only for selectors with a single fixed argument followed by varargs.
- */
- fun objc_msgSend(receiver: ID?, selector: Pointer?, firstArg: Any?, vararg args: Any?): ID?
- fun class_respondsToSelector(cls: ID?, selName: Pointer?): Boolean
- fun class_addMethod(cls: ID?, selName: Pointer?, imp: Callback?, types: String?): Boolean
- fun class_addMethod(cls: ID?, selName: Pointer?, imp: ID?, types: String?): Boolean
- fun class_addProtocol(aClass: ID?, protocol: ID?): Boolean
- fun class_isMetaClass(cls: ID?): Boolean
- fun NSStringFromSelector(selector: Pointer?): ID?
- fun NSStringFromClass(aClass: ID?): ID?
- fun objc_getClass(clazz: Pointer?): Pointer?
-
- companion object {
- const val kCFStringEncodingMacRoman = 0
- const val kCFStringEncodingWindowsLatin1 = 0x0500
- const val kCFStringEncodingISOLatin1 = 0x0201
- const val kCFStringEncodingNextStepLatin = 0x0B01
- const val kCFStringEncodingASCII = 0x0600
- const val kCFStringEncodingUnicode = 0x0100
- const val kCFStringEncodingUTF8 = 0x08000100
- const val kCFStringEncodingNonLossyASCII = 0x0BFF
- const val kCFStringEncodingUTF16 = 0x0100
- const val kCFStringEncodingUTF16BE = 0x10000100
- const val kCFStringEncodingUTF16LE = 0x14000100
- const val kCFStringEncodingUTF32 = 0x0c000100
- const val kCFStringEncodingUTF32BE = 0x18000100
- const val kCFStringEncodingUTF32LE = 0x1c000100
-
- // https://developer.apple.com/library/mac/documentation/Carbon/Reference/CGWindow_Reference/Constants/Constants.html#//apple_ref/doc/constant_group/Window_List_Option_Constants
- const val kCGWindowListOptionAll = 0
- const val kCGWindowListOptionOnScreenOnly = 1
- const val kCGWindowListOptionOnScreenAboveWindow = 2
- const val kCGWindowListOptionOnScreenBelowWindow = 4
- const val kCGWindowListOptionIncludingWindow = 8
- const val kCGWindowListExcludeDesktopElements = 16
-
- // https://developer.apple.com/library/mac/documentation/Carbon/Reference/CGWindow_Reference/Constants/Constants.html#//apple_ref/doc/constant_group/Window_Image_Types
- const val kCGWindowImageDefault = 0
- const val kCGWindowImageBoundsIgnoreFraming = 1
- const val kCGWindowImageShouldBeOpaque = 2
- const val kCGWindowImageOnlyShadows = 4
- const val kCGWindowImageBestResolution = 8
- const val kCGWindowImageNominalResolution = 16
-
- // see enum NSBitmapImageFileType
- const val NSBitmapImageFileTypeTIFF = 0
- const val NSBitmapImageFileTypeBMP = 1
- const val NSBitmapImageFileTypeGIF = 2
- const val NSBitmapImageFileTypeJPEG = 3
- const val NSBitmapImageFileTypePNG = 4
- const val NSBitmapImageFileTypeJPEG2000 = 5
- }
-}
diff --git a/decorated-window/src/main/kotlin/org/jetbrains/jewel/window/utils/macos/ID.kt b/decorated-window/src/main/kotlin/org/jetbrains/jewel/window/utils/macos/ID.kt
deleted file mode 100644
index df74e25e7f..0000000000
--- a/decorated-window/src/main/kotlin/org/jetbrains/jewel/window/utils/macos/ID.kt
+++ /dev/null
@@ -1,30 +0,0 @@
-package org.jetbrains.jewel.window.utils.macos
-
-import com.sun.jna.NativeLong
-
-/**
- * Could be an address in memory (if pointer to a class or method) or a
- * value (like 0 or 1)
- */
-internal class ID : NativeLong {
-
- constructor()
- constructor(peer: Long) : super(peer)
-
- fun booleanValue(): Boolean = toInt() != 0
-
- override fun toByte(): Byte = toInt().toByte()
-
- override fun toChar(): Char = toInt().toChar()
-
- override fun toShort(): Short = toInt().toShort()
-
- @Suppress("RedundantOverride") // Without this, we get a SOE
- override fun toInt(): Int = super.toInt()
-
- companion object {
-
- @JvmField
- val NIL = ID(0L)
- }
-}
diff --git a/decorated-window/src/main/kotlin/org/jetbrains/jewel/window/utils/macos/MacUtil.kt b/decorated-window/src/main/kotlin/org/jetbrains/jewel/window/utils/macos/MacUtil.kt
deleted file mode 100644
index 248cb170a1..0000000000
--- a/decorated-window/src/main/kotlin/org/jetbrains/jewel/window/utils/macos/MacUtil.kt
+++ /dev/null
@@ -1,95 +0,0 @@
-package org.jetbrains.jewel.window.utils.macos
-
-import org.jetbrains.jewel.window.utils.UnsafeAccessing
-import org.jetbrains.jewel.window.utils.accessible
-import java.awt.Component
-import java.awt.Window
-import java.lang.reflect.InvocationTargetException
-import java.util.logging.Level
-import java.util.logging.Logger
-import javax.swing.SwingUtilities
-
-internal object MacUtil {
-
- private val logger = Logger.getLogger(MacUtil::class.java.simpleName)
-
- init {
- try {
- UnsafeAccessing.assignAccessibility(
- UnsafeAccessing.desktopModule,
- listOf("sun.awt", "sun.lwawt", "sun.lwawt.macosx"),
- )
- } catch (@Suppress("TooGenericExceptionCaught") e: Exception) {
- logger.log(Level.WARNING, "Assign access for jdk.desktop failed.", e)
- }
- }
-
- fun getWindowFromJavaWindow(w: Window?): ID {
- if (w == null) {
- return ID.NIL
- }
- try {
- val cPlatformWindow = getPlatformWindow(w)
- if (cPlatformWindow != null) {
- val ptr = cPlatformWindow.javaClass.superclass.getDeclaredField("ptr")
- ptr.setAccessible(true)
- return ID(ptr.getLong(cPlatformWindow))
- }
- } catch (e: IllegalAccessException) {
- logger.log(Level.WARNING, "Fail to get cPlatformWindow from awt window.", e)
- } catch (e: NoSuchFieldException) {
- logger.log(Level.WARNING, "Fail to get cPlatformWindow from awt window.", e)
- }
- return ID.NIL
- }
-
- fun getPlatformWindow(w: Window): Any? {
- try {
- val awtAccessor = Class.forName("sun.awt.AWTAccessor")
- val componentAccessor = awtAccessor.getMethod("getComponentAccessor").invoke(null)
- val getPeer = componentAccessor.javaClass.getMethod("getPeer", Component::class.java).accessible()
- val peer = getPeer.invoke(componentAccessor, w)
- if (peer != null) {
- val cWindowPeerClass: Class<*> = peer.javaClass
- val getPlatformWindowMethod = cWindowPeerClass.getDeclaredMethod("getPlatformWindow")
- val cPlatformWindow = getPlatformWindowMethod.invoke(peer)
- if (cPlatformWindow != null) {
- return cPlatformWindow
- }
- }
- } catch (e: NoSuchMethodException) {
- logger.log(Level.WARNING, "Fail to get cPlatformWindow from awt window.", e)
- } catch (e: IllegalAccessException) {
- logger.log(Level.WARNING, "Fail to get cPlatformWindow from awt window.", e)
- } catch (e: InvocationTargetException) {
- logger.log(Level.WARNING, "Fail to get cPlatformWindow from awt window.", e)
- } catch (e: ClassNotFoundException) {
- logger.log(Level.WARNING, "Fail to get cPlatformWindow from awt window.", e)
- }
- return null
- }
-
- fun updateColors(w: Window) {
- SwingUtilities.invokeLater {
- val window = getWindowFromJavaWindow(w)
- val delegate = Foundation.invoke(window, "delegate")
- if (Foundation.invoke(delegate, "respondsToSelector:", Foundation.createSelector("updateColors"))
- .booleanValue()
- ) {
- Foundation.invoke(delegate, "updateColors")
- }
- }
- }
-
- fun updateFullScreenButtons(w: Window) {
- SwingUtilities.invokeLater {
- val selector = Foundation.createSelector("updateFullScreenButtons")
- val window = getWindowFromJavaWindow(w)
- val delegate = Foundation.invoke(window, "delegate")
-
- if (Foundation.invoke(delegate, "respondsToSelector:", selector).booleanValue()) {
- Foundation.invoke(delegate, "updateFullScreenButtons")
- }
- }
- }
-}
diff --git a/gradle.properties b/gradle.properties
index 2ce2eecdc4..1208c254b6 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -6,4 +6,4 @@ kotlin.stdlib.default.dependency=false
# See https://jb.gg/intellij-platform-kotlin-oom
kotlin.incremental.useClasspathSnapshot=false
-bridge.ijp.target=241
+bridge.ijp.target=232
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index bf7000ecea..44f0e5ae20 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -3,7 +3,7 @@ commonmark = "0.21.0"
composeDesktop = "1.6.0-dev1397"
detekt = "1.23.4"
dokka = "1.8.20"
-idea = "241.11761.10-EAP-SNAPSHOT"
+idea = "232.10227.8"
ideaGradlePlugin = "1.17.0"
jna = "5.14.0"
kotlin = "1.8.21"
diff --git a/ide-laf-bridge/api/ide-laf-bridge.api b/ide-laf-bridge/api/ide-laf-bridge.api
index 42235da257..e029402075 100644
--- a/ide-laf-bridge/api/ide-laf-bridge.api
+++ b/ide-laf-bridge/api/ide-laf-bridge.api
@@ -2,7 +2,7 @@ public final class org/jetbrains/jewel/bridge/BridgeIconDataKt {
public static final fun readFromLaF (Lorg/jetbrains/jewel/foundation/theme/ThemeIconData$Companion;)Lorg/jetbrains/jewel/foundation/theme/ThemeIconData;
}
-public final class org/jetbrains/jewel/bridge/BridgePainterHintsProvider : org/jetbrains/jewel/ui/painter/PalettePainterHintsProvider {
+public final class org/jetbrains/jewel/bridge/BridgePainterHintsProvider : org/jetbrains/jewel/ui/painter/BasePainterHintsProvider {
public static final field $stable I
public static final field Companion Lorg/jetbrains/jewel/bridge/BridgePainterHintsProvider$Companion;
public synthetic fun (ZLjava/util/Map;Ljava/util/Map;Ljava/util/Map;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
@@ -10,7 +10,7 @@ public final class org/jetbrains/jewel/bridge/BridgePainterHintsProvider : org/j
}
public final class org/jetbrains/jewel/bridge/BridgePainterHintsProvider$Companion {
- public final fun invoke (Z)Lorg/jetbrains/jewel/ui/painter/PalettePainterHintsProvider;
+ public final fun invoke (Z)Lorg/jetbrains/jewel/ui/painter/BasePainterHintsProvider;
}
public final class org/jetbrains/jewel/bridge/BridgeResourceResolverKt {
@@ -78,6 +78,10 @@ public final class org/jetbrains/jewel/bridge/TypographyKt {
public static final fun small (Lorg/jetbrains/jewel/ui/component/Typography;Landroidx/compose/runtime/Composer;I)Landroidx/compose/ui/text/TextStyle;
}
+public final class org/jetbrains/jewel/bridge/UiThemeExtensionsKt {
+ public static final fun getIcons (Lcom/intellij/ide/ui/UITheme;)Ljava/util/Map;
+}
+
public final class org/jetbrains/jewel/bridge/actionSystem/ProvideDataKt {
public static final fun ComponentDataProviderBridge (Ljavax/swing/JComponent;Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;II)V
public static final fun provideData (Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function1;)Landroidx/compose/ui/Modifier;
diff --git a/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/BridgeIconData.kt b/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/BridgeIconData.kt
index 69d1b2c759..fb6627088b 100644
--- a/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/BridgeIconData.kt
+++ b/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/BridgeIconData.kt
@@ -1,14 +1,16 @@
package org.jetbrains.jewel.bridge
import com.intellij.ide.ui.UITheme
+import com.intellij.ui.ColorUtil
+import org.jetbrains.jewel.foundation.InternalJewelApi
import org.jetbrains.jewel.foundation.theme.ThemeIconData
-@Suppress("UnstableApiUsage")
+@OptIn(InternalJewelApi::class)
public fun ThemeIconData.Companion.readFromLaF(): ThemeIconData {
val uiTheme = currentUiThemeOrNull()
- val bean = uiTheme?.describe()
- val iconMap = bean?.icons.orEmpty()
- val selectedIconColorPalette = bean?.iconColorsOnSelection.orEmpty()
+ val iconMap = uiTheme?.icons.orEmpty()
+ val selectedIconColorPalette = uiTheme?.selectedIconColorPalette.orEmpty()
+ .mapValues { ColorUtil.fromHex(it.value).rgb }
val colorPalette = UITheme.getColorPalette()
return ThemeIconData(iconMap, colorPalette, selectedIconColorPalette)
diff --git a/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/BridgeOverride.kt b/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/BridgeOverride.kt
index 5291ab3043..3651942891 100644
--- a/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/BridgeOverride.kt
+++ b/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/BridgeOverride.kt
@@ -1,22 +1,22 @@
package org.jetbrains.jewel.bridge
-import com.intellij.openapi.diagnostic.Logger
-import com.intellij.ui.icons.patchIconPath
import com.intellij.util.ui.DirProvider
import org.jetbrains.jewel.ui.painter.PainterPathHint
import org.jetbrains.jewel.ui.painter.PainterProviderScope
import org.jetbrains.jewel.ui.painter.ResourcePainterProviderScope
-/**
- * A [PainterPathHint] that implements the
- * [New UI Icon Mapping](https://plugins.jetbrains.com/docs/intellij/icons.html#mapping-entries)
- * by delegating to the IntelliJ Platform.
- */
internal object BridgeOverride : PainterPathHint {
private val dirProvider = DirProvider()
- @Suppress("UnstableApiUsage") // patchIconPath() is explicitly open to us
+ private val patchIconPath by lazy {
+ val clazz = Class.forName("com.intellij.ui.icons.CachedImageIconKt")
+ val patchIconPath =
+ clazz.getMethod("patchIconPath", String::class.java, ClassLoader::class.java)
+ patchIconPath.isAccessible = true
+ patchIconPath
+ }
+
override fun PainterProviderScope.patch(): String {
if (this !is ResourcePainterProviderScope) return path
@@ -25,50 +25,17 @@ internal object BridgeOverride : PainterPathHint {
// removed (the classloader is set up differently in prod IDEs and when running
// from Gradle, and the icon could be in either place depending on the environment)
val fallbackPath = path.removePrefix(dirProvider.dir())
-
- for (classLoader in classLoaders) {
- val patchedPath = patchIconPath(path.removePrefix("/"), classLoader)?.first
- ?: patchIconPath(fallbackPath, classLoader)?.first
-
- // 233 EAP 4 broke path patching horribly; now it can return a
- // "reflective path", which is a FQN to an ExpUIIcons entry.
- // As a (hopefully) temporary solution, we undo this transformation
- // back into the original path. The initial transform is lossy, and
- // this attempt might fail.
- if (patchedPath?.startsWith("com.intellij.icons.ExpUiIcons") == true) {
- return inferActualPathFromReflectivePath(patchedPath)
- }
-
- if (patchedPath != null) {
- return patchedPath
- }
- }
- return path
- }
-
- private fun inferActualPathFromReflectivePath(patchedPath: String): String {
- val iconPath = patchedPath.removePrefix("com.intellij.icons.ExpUiIcons.")
-
- return buildString {
- append("expui/")
- iconPath.split('.')
- .map { it.trim() }
- .filter { it.isNotEmpty() }
- .forEach {
- append(it.first().lowercaseChar())
- append(it.drop(1))
- append('/')
+ val patchedPath =
+ classLoaders
+ .firstNotNullOfOrNull { classLoader ->
+ val patchedPathAndClassLoader =
+ patchIconPath.invoke(null, path.removePrefix("/"), classLoader)
+ ?: patchIconPath.invoke(null, fallbackPath, classLoader)
+ patchedPathAndClassLoader as? Pair<*, *>
}
- replace(length - 1, length, "") // Drop last '/'
- if (iconPath.contains("_dark")) append("_dark")
- append(".svg")
+ ?.first as? String
- Logger.getInstance("IconsPathPatching")
- .warn(
- "IntelliJ returned a reflective path: $patchedPath for $iconPath." +
- " We reverted that to a plausible-looking resource path: ${toString()}",
- )
- }
+ return patchedPath ?: path
}
override fun toString(): String = "BridgeOverride"
diff --git a/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/BridgePainterHintsProvider.kt b/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/BridgePainterHintsProvider.kt
index d87425c581..6f600491c7 100644
--- a/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/BridgePainterHintsProvider.kt
+++ b/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/BridgePainterHintsProvider.kt
@@ -4,155 +4,50 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
import com.intellij.ide.ui.UITheme
import com.intellij.openapi.diagnostic.thisLogger
-import com.intellij.ui.NewUI
-import org.jetbrains.jewel.bridge.theme.isNewUiTheme
import org.jetbrains.jewel.foundation.InternalJewelApi
import org.jetbrains.jewel.foundation.theme.JewelTheme
+import org.jetbrains.jewel.ui.painter.BasePainterHintsProvider
import org.jetbrains.jewel.ui.painter.PainterHint
-import org.jetbrains.jewel.ui.painter.PalettePainterHintsProvider
-import org.jetbrains.jewel.ui.painter.hints.ColorBasedPaletteReplacement
import org.jetbrains.jewel.ui.painter.hints.Dark
import org.jetbrains.jewel.ui.painter.hints.HiDpi
-import org.jetbrains.jewel.ui.painter.hints.KeyBasedPaletteReplacement
-import org.jetbrains.jewel.ui.util.inDebugMode
-import org.jetbrains.jewel.ui.util.toRgbaHexString
+import org.jetbrains.jewel.ui.util.fromRGBAHexStringOrNull
-/**
- * Provide the default [PainterHint]s to use in the IDE.
- *
- * This is an internal Jewel API and should not be used directly.
- */
@InternalJewelApi
public class BridgePainterHintsProvider private constructor(
isDark: Boolean,
- intellijIconPalette: Map = emptyMap(),
+ intellijIconPalette: Map = emptyMap(),
themeIconPalette: Map = emptyMap(),
themeColorPalette: Map = emptyMap(),
-) : PalettePainterHintsProvider(isDark, intellijIconPalette, themeIconPalette, themeColorPalette) {
-
- override val checkBoxByColorPaletteHint: PainterHint
- override val checkBoxByKeyPaletteHint: PainterHint
- override val treePaletteHint: PainterHint
- override val uiPaletteHint: PainterHint
-
- init {
- val ui = mutableMapOf()
- val checkBoxesByColor = mutableMapOf()
- val checkBoxesByKey = mutableMapOf()
- val trees = mutableMapOf()
-
- @Suppress("LoopWithTooManyJumpStatements")
- for ((key, value) in themeIconPalette) {
- if (value == null) continue
-
- // Checkbox (and radio button) entries work differently: the ID field
- // for each element that needs patching has a "[fillKey]_[strokeKey]"
- // format, starting from IJP 241. This is only enabled for the New UI.
- if (key.startsWith("Checkbox.") && NewUI.isEnabled()) {
- registerIdBasedReplacement(checkBoxesByKey, key, value)
- }
-
- val map = selectMap(key, checkBoxesByColor, trees, ui) ?: continue
- registerColorBasedReplacement(map, key, value)
- }
-
- checkBoxByKeyPaletteHint = KeyBasedPaletteReplacement(checkBoxesByKey)
- checkBoxByColorPaletteHint = ColorBasedPaletteReplacement(checkBoxesByColor)
- treePaletteHint = ColorBasedPaletteReplacement(trees)
- uiPaletteHint = ColorBasedPaletteReplacement(ui)
- }
-
- private fun registerColorBasedReplacement(
- map: MutableMap,
- key: String,
- value: String,
- ) {
- // If either the key or the resolved value aren't valid colors, ignore the entry
- val keyAsColor = resolveKeyColor(key, intellijIconPalette, isDark) ?: return
- val resolvedColor = resolveColor(value) ?: return
-
- // Save the new entry (oldColor -> newColor) in the map
- map[keyAsColor] = resolvedColor
- }
-
- private fun registerIdBasedReplacement(
- map: MutableMap,
- key: String,
- value: String,
- ) {
- val adjustedKey = if (isDark) key.removeSuffix(".Dark") else key
-
- if (adjustedKey !in supportedCheckboxKeys) {
- if (inDebugMode) {
- logger.warn("${if (isDark) "Dark" else "Light"} theme: color key $key is not supported, will be ignored")
- }
- return
- }
-
- if (adjustedKey != key && inDebugMode) {
- logger.warn("${if (isDark) "Dark" else "Light"} theme: color key $key is deprecated, use $adjustedKey instead")
- }
-
- val parsedValue = resolveColor(value)
- if (parsedValue == null) {
- if (inDebugMode) {
- logger.warn("${if (isDark) "Dark" else "Light"} theme: color key $key has invalid value: '$value'")
- }
- return
- }
-
- map[adjustedKey] = parsedValue
- }
+) : BasePainterHintsProvider(isDark, intellijIconPalette, themeIconPalette, themeColorPalette) {
@Composable
- override fun hints(path: String): List =
- buildList {
- add(BridgeOverride)
- add(getPaletteHint(path, isNewUi = isNewUiTheme()))
- add(HiDpi())
- add(Dark(JewelTheme.isDark))
- }
+ override fun hints(path: String): List = buildList {
+ add(getPaletteHint(path))
+ add(BridgeOverride)
+ add(HiDpi())
+ add(Dark(JewelTheme.isDark))
+ }
public companion object {
private val logger = thisLogger()
- @Suppress("UnstableApiUsage") // We need to call @Internal APIs
- public operator fun invoke(isDark: Boolean): PalettePainterHintsProvider {
+ public operator fun invoke(isDark: Boolean): BasePainterHintsProvider {
val uiTheme = currentUiThemeOrNull() ?: return BridgePainterHintsProvider(isDark)
logger.info("Parsing theme info from theme ${uiTheme.name} (id: ${uiTheme.id}, isDark: ${uiTheme.isDark})")
- val bean = uiTheme.describe()
- val iconColorPalette =
- (bean.colorPalette as Map).mapValues {
- when (val value = it.value) {
- is String -> value
- is java.awt.Color -> value.toRgbaHexString()
+ val iconColorPalette = uiTheme.iconColorPalette
+ val keyPalette = UITheme.getColorPalette()
+ val themeColors = uiTheme.colors.orEmpty()
+ .mapValues { (_, v) ->
+ when (v) {
+ is Int -> Color(v)
+ is String -> Color.fromRGBAHexStringOrNull(v)
else -> null
}
}
- val keyPalette = UITheme.getColorPalette()
- val themeColors = bean.colors.mapValues { (_, v) -> Color(v) }
- return BridgePainterHintsProvider(
- isDark = isDark,
- intellijIconPalette = keyPalette,
- themeIconPalette = iconColorPalette,
- themeColorPalette = themeColors,
- )
+ return BridgePainterHintsProvider(isDark, keyPalette, iconColorPalette, themeColors)
}
-
- private val supportedCheckboxKeys: Set =
- setOf(
- "Checkbox.Background.Default",
- "Checkbox.Border.Default",
- "Checkbox.Foreground.Selected",
- "Checkbox.Background.Selected",
- "Checkbox.Border.Selected",
- "Checkbox.Focus.Wide",
- "Checkbox.Foreground.Disabled",
- "Checkbox.Background.Disabled",
- "Checkbox.Border.Disabled",
- )
}
}
diff --git a/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/UiThemeExtensions.kt b/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/UiThemeExtensions.kt
index 81a6cd6da6..c4a75d91af 100644
--- a/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/UiThemeExtensions.kt
+++ b/ide-laf-bridge/src/main/kotlin/org/jetbrains/jewel/bridge/UiThemeExtensions.kt
@@ -1,8 +1,45 @@
package org.jetbrains.jewel.bridge
import com.intellij.ide.ui.LafManager
-import com.intellij.ide.ui.laf.UIThemeLookAndFeelInfo
+import com.intellij.ide.ui.UITheme
+import com.intellij.ide.ui.laf.UIThemeBasedLookAndFeelInfo
+import com.intellij.openapi.diagnostic.Logger
+import org.jetbrains.jewel.foundation.InternalJewelApi
+import java.lang.reflect.Field
-@Suppress("UnstableApiUsage")
-internal fun currentUiThemeOrNull(): UIThemeLookAndFeelInfo? =
- LafManager.getInstance().currentUIThemeLookAndFeel?.takeIf { it.isInitialized }
+private val logger = Logger.getInstance("UiThemeExtensions")
+
+private val classUITheme
+ get() = UITheme::class.java
+
+@InternalJewelApi
+internal fun currentUiThemeOrNull() =
+ (LafManager.getInstance().currentLookAndFeel as? UIThemeBasedLookAndFeelInfo)?.theme
+
+@InternalJewelApi
+public val UITheme.icons: Map
+ get() = readMapField(classUITheme.getDeclaredField("icons"))
+ .filterKeys { it != "ColorPalette" }
+
+internal val UITheme.iconColorPalette: Map
+ get() = readMapField