compose-multiplatform icon indicating copy to clipboard operation
compose-multiplatform copied to clipboard

How to open Window/Dialog on the same screen as launcher/trigger, when working with multiple screen

Open haikalpribadi opened this issue 3 years ago • 13 comments

Say you have 2 screens -- Screen 1 and Screen 2, and the "main/default" screen is Screen 1. When you launch the application from Screen 2 (via terminal, or application icon, or IDE), the application Window will always start in Screen 1. Even after you drag the application window to Screen 2, when you click any button that opens a Dialog, that dialog will always open in Screen 1, and you have to drag it manually to Screen 2 again.

Effectively, how can we get Compose to recognise that you're working on multiple screens, and that it should focus on working on just the one screen that the application sits in the moment?

haikalpribadi avatar Feb 14 '22 15:02 haikalpribadi

Hey guys, @igordmn and @akurasov any updates on this? Seems like it's removed from you milestone 4 days ago now? We actually start having customers complaining to us about this issue. Is there anything we can do to help from our side?

haikalpribadi avatar May 30 '22 10:05 haikalpribadi

Hey!

Our plans regarding 1.1.2/1.2 are changed, and scope of it will be revised.

Currently, if you need this feature right now, you can copy-paste Window / Dialog, and use another constructor of ComposeWindow:

import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.awt.ComposeWindow
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.application
import java.awt.Dimension
import java.awt.event.WindowAdapter
import java.awt.event.WindowEvent
import javax.swing.JFrame

private var isSecondWindowOpened by mutableStateOf(false)

fun main() = application {
    Window(onCloseRequest = ::exitApplication) {
        Button({
            isSecondWindowOpened = !isSecondWindowOpened
        }) {
            Text("Second window")
        }
    }

    if (isSecondWindowOpened) {
        val graphicsConfiguration = remember {
            java.awt.Window.getWindows().find { it.isActive }?.graphicsConfiguration
        }
        Window(
            create = {
                ComposeWindow(graphicsConfiguration).apply {
                    defaultCloseOperation = JFrame.DO_NOTHING_ON_CLOSE
                    size = Dimension(200, 200)
                    addWindowListener(object : WindowAdapter() {
                        override fun windowClosing(e: WindowEvent) {
                            isSecondWindowOpened = false
                        }
                    })
                }
            },
            dispose = ComposeWindow::dispose
        ) {
        }
    }
}

(I don't have multiple monitors right now, so can't verify if code is correct)

igordmn avatar May 31 '22 13:05 igordmn

Can you tell me which what's the key requirement in the code above, @igordmn ?

haikalpribadi avatar May 31 '22 14:05 haikalpribadi

Okay, I think I understand the essence of what you're doing there: you're passing GraphicsConfiguration from java.aw.Window.getWindows() that isActive into ComposeWindow(). Am I right?

However, right now we construct our windows using Window() from androidx.compose.ui.window.Window.desktop.kt, which seems to manage a lot of things such as: title, resizing, icon, focus, alwaysOnTop, closeRequest, minimization, decoration, placement, position, etc. If we go with your suggestion above, does that mean we will loose all these functionalities? @igordmn

haikalpribadi avatar May 31 '22 14:05 haikalpribadi

I think I understand the essence of what you're doing there: you're passing GraphicsConfiguration from

Yes, GraphicsConfiguration defines on which display the window should be shown.

However, right now we construct our windows using Window()

Yes, it is unfortunate, but you can copy-paste this file (temporarily), and pass graphicsConfiguration here

We will add this feature into the official release, but before that we should be sure that this code won't break other cases (aligning in the center of the screen, positioning, etc).

igordmn avatar May 31 '22 14:05 igordmn

I did think of doing that, but as I expected, copying the file over is not possible as it depends on internal APIs:

Error:(33, 33) cannot access 'ComponentUpdater': it is internal in 'androidx.compose.ui.util'
Error:(34, 33) cannot access 'makeDisplayable': it is internal in 'androidx.compose.ui.util'
Error:(35, 33) cannot access 'setIcon': it is internal in 'androidx.compose.ui.util'
Error:(36, 33) cannot access 'setPositionSafely': it is internal in 'androidx.compose.ui.util'
Error:(37, 33) cannot access 'setSizeSafely': it is internal in 'androidx.compose.ui.util'
Error:(38, 33) cannot access 'setUndecoratedSafely': it is internal in 'androidx.compose.ui.util'
Error:(144, 19) cannot access 'ComponentUpdater': it is internal in 'androidx.compose.ui.util'
Error:(195, 21) cannot access 'ComponentUpdater': it is internal in 'androidx.compose.ui.util'
Error:(196, 17) cannot access 'ComponentUpdater': it is internal in 'androidx.compose.ui.util'
Error:(197, 17) cannot access 'ComponentUpdater': it is internal in 'androidx.compose.ui.util'
Error:(197, 17) cannot access 'setIcon': it is internal in 'androidx.compose.ui.util'
Error:(198, 17) cannot access 'ComponentUpdater': it is internal in 'androidx.compose.ui.util'
Error:(198, 17) cannot access 'setUndecoratedSafely': it is internal in 'androidx.compose.ui.util'
Error:(199, 17) cannot access 'ComponentUpdater': it is internal in 'androidx.compose.ui.util'
Error:(200, 17) cannot access 'ComponentUpdater': it is internal in 'androidx.compose.ui.util'
Error:(201, 17) cannot access 'ComponentUpdater': it is internal in 'androidx.compose.ui.util'
Error:(202, 17) cannot access 'ComponentUpdater': it is internal in 'androidx.compose.ui.util'
Error:(203, 17) cannot access 'ComponentUpdater': it is internal in 'androidx.compose.ui.util'
Error:(206, 24) cannot access 'setSizeSafely': it is internal in 'androidx.compose.ui.util'
Error:(210, 24) cannot access 'setPositionSafely': it is internal in 'androidx.compose.ui.util'
Error:(384, 20) cannot access 'makeDisplayable': it is internal in 'androidx.compose.ui.util'

Did you anticipate this? Or is there a workaround, @igordmn ?

haikalpribadi avatar May 31 '22 15:05 haikalpribadi

You can add the following to the top of your file, but use with caution:

@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")

Thomas-Vos avatar May 31 '22 15:05 Thomas-Vos

Thanks @Thomas-Vos ! That worked like magic! Crazy dangerous 😅 -- but magic.

@igordmn I gave it a try as you suggested: https://github.com/haikalpribadi/typedb-studio/commit/ad1be4cfefe627e297dea1f03598fa8b6b797115

However, the application still opens only in the "main screen", and most critically: after I drag the application into the second screen, all dialogs (androidx.compose.ui.window.Dialog) that I open still opens only in the main (first) screen.

I tried to look into whether I can pass GraphicsConfiguration into ComposeDialog (androidx.compose.ui.awt.ComposeDialog) and I don't seem to find any such input parameter.

Do you have an idea where I should go from here, @igordmn ?

haikalpribadi avatar May 31 '22 15:05 haikalpribadi

Also, @igordmn, when you said "We will add this feature into the official release" do you mean 1.2.0? Or not yet known?

haikalpribadi avatar May 31 '22 16:05 haikalpribadi

Probably it will be in 1.2.0, if there won't be major issues with the code above.

igordmn avatar Jun 01 '22 03:06 igordmn

I implemented it the way you suggested, above, but it didn't work. Any idea why, @igordmn ?

haikalpribadi avatar Jun 01 '22 08:06 haikalpribadi

Any updates on this @igordmn ?

haikalpribadi avatar Aug 16 '22 15:08 haikalpribadi

No updates yet. I don't have the second monitor right now to test it, but probably will receive it this month.

igordmn avatar Aug 16 '22 15:08 igordmn