Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add more info about lwjgl integration #1738

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

smallshen
Copy link

No description provided.


CompositionLocalProvider(
LocalLayerContainer provides awtContainer
Copy link
Collaborator

Choose a reason for hiding this comment

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

LocalLayerContainer is internal. Please describe in this doc how you use it.

Copy link
Author

Choose a reason for hiding this comment

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

rememberCursorPosition is using AWT to get mouse position, in an app with ComposeSence, currently, the only way to make cursor related feature (ContextMenu, CursorPopup, Tooltip) work is to provide a fake AWT Container and update window bound and position for the fake container, and you need to implement your own window region detection, render scaling, etc.

This can be removed or changed if we could have something LocalMouseLocationProvider mentioned in #1736

Copy link
Collaborator

Choose a reason for hiding this comment

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

I mean, how do you able to use/access LocalLayerContainer? It is marked as internal, so you can't access it in default Gradle/Kotlin configuration. Do you add some arguments to Kotlin compiler?

Copy link
Author

Choose a reason for hiding this comment

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

Oh, I just create a fake class and override in the classpath(Gradle default duplicate strategy should work). My current workaround is to create a package androidx.compose.ui.awt and create a file LocalLayerContainer.desktop.kt

import androidx.compose.runtime.staticCompositionLocalOf
import your.package.awtContainer

val LocalLayerContainer: androidx.compose.runtime.ProvidableCompositionLocal<java.awt.Container> =
    staticCompositionLocalOf { awtContainer }

I am also trying to make a kotlin compiler plugin to remove all access modifiers and make everything public open.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I just create a fake class and override in the classpath

Smart :). Could you add this into the doc?

Also, could you describe in ## Problems that this section contains only temporary workarounds, that won't needed when Compose resolves these problems.

Copy link
Author

Choose a reason for hiding this comment

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

Done

Copy link
Collaborator

Choose a reason for hiding this comment

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

  1. The file should contain the package:
package androidx.compose.ui.awt
  1. Better to write this:
package androidx.compose.ui.awt

import androidx.compose.runtime.compositionLocalOf
import java.awt.Container

internal val LocalLayerContainer = compositionLocalOf<Container> {
    error("CompositionLocal LayerContainer not provided")
}

because we use CompositionLocalProvider to pass awtContainer

  1. I have an exception (on Windows):
Exception in thread "main" java.lang.NullPointerException: graphicsConfiguration must not be null
	at androidx.compose.ui.window.LayoutConfiguration_desktopKt.getDensity(LayoutConfiguration.desktop.kt:39)
	at androidx.compose.ui.window.DesktopPopup_desktopKt.rememberCursorPositionProvider-B5uucgQ(DesktopPopup.desktop.kt:236)
	at androidx.compose.foundation.TooltipPlacement$CursorPoint.positionProvider(TooltipArea.desktop.kt:227)
	at androidx.compose.foundation.TooltipArea_desktopKt.TooltipArea(TooltipArea.desktop.kt:151)

when I try to run:

import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.TooltipArea
import androidx.compose.foundation.TooltipPlacement
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Button
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.awt.LocalLayerContainer
import androidx.compose.ui.awt.awtContainer
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.dp

@OptIn(ExperimentalFoundationApi::class)
@Composable
fun App() {
    CompositionLocalProvider(LocalLayerContainer provides awtContainer) {
        val buttons =
            listOf("Button A", "Button B", "Button C", "Button D", "Button E", "Button F")
        Column(Modifier.fillMaxSize(), Arrangement.spacedBy(5.dp)) {
            buttons.forEachIndexed { index, name ->
                // wrap button in BoxWithTooltip
                TooltipArea(
                    tooltip = {
                        // composable tooltip content
                        Surface(
                            modifier = Modifier.shadow(4.dp),
                            color = Color(255, 255, 210),
                            shape = RoundedCornerShape(4.dp)
                        ) {
                            Text(
                                text = "Tooltip for ${name}",
                                modifier = Modifier.padding(10.dp)
                            )
                        }
                    },
                    modifier = Modifier.padding(start = 40.dp),
                    delayMillis = 600, // in milliseconds
                    tooltipPlacement = TooltipPlacement.CursorPoint(
                        alignment = Alignment.BottomEnd,
                        offset = if (index % 2 == 0) DpOffset(
                            -16.dp,
                            0.dp
                        ) else DpOffset.Zero // tooltip offset
                    )
                ) {
                    Button(onClick = {}) { Text(text = name) }
                }
            }
        }
    }
}

How have you solved it?

  1. Add a note to ## Problems:
This section describes the current issues with LWJGL integration, and suggests temporary workarounds. These workarounds won't be needed when these issues are fixed in Compose.

Copy link
Author

Choose a reason for hiding this comment

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

Hmmm, weird. I didn't run into a null pointer error (with ComposeSence).

It might be caused by AWT headless property, try System.setProperty("java.awt.headless", "false")

Copy link
Collaborator

Choose a reason for hiding this comment

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

This works for me:

val awtContainer = object : Container() {
    // Note that this can cause some issues with multiple displays with different densities
    // (if some widget relies on the density of this container) 
    override fun getGraphicsConfiguration() =
        GraphicsEnvironment.getLocalGraphicsEnvironment()
            .defaultScreenDevice
            .defaultConfiguration
}

Choose a reason for hiding this comment

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

You can avoid classpath hacks with just using @Suppress("INVISIBLE_MEMBER") on use-site.


### Popup
Since Compose still use some AWT events (https://github.com/JetBrains/compose-jb/issues/1736), you can provide a fake contaniner.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
Since Compose still use some AWT events (https://github.com/JetBrains/compose-jb/issues/1736), you can provide a fake contaniner.
Since Compose still use some AWT events (https://github.com/JetBrains/compose-jb/issues/1736), you can provide a fake container.

@wgryglas
Copy link
Contributor

I am working with Compose and LWJGL on Linux.
I can confirm the workarounds listed in this pull request do the job - I was kind of stuck for some while with the same issue.
It will be very useful to add those hints to be much easier discoverable.

@akurasov akurasov added documentation Improvements or additions to documentation AK labels Feb 21, 2022
@igordmn igordmn removed the AK label Oct 11, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants