Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package com.crosspaste.app

import androidx.compose.ui.awt.ComposeWindow
import androidx.compose.ui.window.WindowPlacement
import androidx.compose.ui.window.WindowPosition
import androidx.compose.ui.window.WindowState
import com.crosspaste.config.DesktopConfigManager
import com.crosspaste.listener.ShortcutKeys
Expand Down Expand Up @@ -82,16 +80,6 @@ abstract class DesktopAppWindowManager(
private val _showMainWindow = MutableStateFlow(false)
val showMainWindow: StateFlow<Boolean> = _showMainWindow

private val _mainWindowState =
MutableStateFlow(
WindowState(
placement = WindowPlacement.Floating,
position = WindowPosition.PlatformDefault,
size = appSize.mainWindowSize,
),
)
val mainWindowState: StateFlow<WindowState> = _mainWindowState

var mainComposeWindow: ComposeWindow? = null

private val _showMainDialog = MutableStateFlow(false)
Expand Down Expand Up @@ -124,14 +112,6 @@ abstract class DesktopAppWindowManager(
_showSearchWindow.value = true
}

fun setMainWindowState(windowState: WindowState) {
_mainWindowState.value = windowState
}

fun getMainWindowState(): WindowState {
return mainWindowState.value
}

fun setSearchWindowState(windowState: WindowState) {
_searchWindowState.value = windowState
}
Expand Down
32 changes: 0 additions & 32 deletions app/src/desktopMain/kotlin/com/crosspaste/ui/LinuxTrayView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.WindowPosition
import androidx.compose.ui.window.WindowState
import com.crosspaste.app.AppLaunchState
import com.crosspaste.app.DesktopAppLaunch
import com.crosspaste.app.DesktopAppWindowManager
Expand All @@ -22,8 +19,6 @@ import io.github.oshai.kotlinlogging.KotlinLogging
import kotlinx.coroutines.delay
import org.jetbrains.compose.resources.ExperimentalResourceApi
import org.koin.compose.koinInject
import java.awt.GraphicsEnvironment
import java.awt.Toolkit
import java.net.URI

object LinuxTrayView {
Expand Down Expand Up @@ -83,40 +78,13 @@ object LinuxTrayView {
}

LaunchedEffect(Unit) {
refreshWindowPosition(appWindowManager)

if (appLaunchState.firstLaunch && !firstLaunchCompleted) {
appWindowManager.showMainWindow()
appLaunch.setFirstLaunchCompleted(true)
}
}
}

private fun refreshWindowPosition(appWindowManager: DesktopAppWindowManager) {
val gd = GraphicsEnvironment.getLocalGraphicsEnvironment().defaultScreenDevice
val bounds = gd.defaultConfiguration.bounds
val insets = Toolkit.getDefaultToolkit().getScreenInsets(gd.defaultConfiguration)

val appSize = appWindowManager.appSize

val windowWidth = appSize.mainWindowSize.width

val windowPosition =
WindowPosition.Absolute(
x = (bounds.x + bounds.width).dp - windowWidth + appSize.mainHorizontalShadowPadding,
y = (bounds.y + insets.top).dp,
)

appWindowManager.setMainWindowState(
WindowState(
size = appWindowManager.appSize.mainWindowSize,
position = windowPosition,
),
)

logger.debug { "main position: $windowPosition" }
}

private fun getTrayType(): TrayType {
return System.getProperty("linux.force.trayType")?.let {
safeFromString(it)
Expand Down
28 changes: 1 addition & 27 deletions app/src/desktopMain/kotlin/com/crosspaste/ui/MacTrayView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.WindowPosition
import androidx.compose.ui.window.WindowState
import com.crosspaste.app.DesktopAppLaunch
import com.crosspaste.app.DesktopAppLaunchState
import com.crosspaste.app.DesktopAppWindowManager
Expand Down Expand Up @@ -79,8 +76,6 @@ object MacTrayView {
val screenDevice = ge.defaultScreenDevice

(windowInfos.firstOrNull { it.contained(screenDevice) } ?: windowInfos.firstOrNull())?.let {
logger.debug { "windowInfo: $it" }
refreshWindowPosition(appWindowManager, it)
if (appLaunchState.firstLaunch && !firstLaunchCompleted) {
appWindowManager.showMainWindow()
appLaunch.setFirstLaunchCompleted(true)
Expand All @@ -94,7 +89,7 @@ object MacTrayView {
state = remember { notificationManager.trayState },
tooltip = "CrossPaste",
mouseListener =
MacTrayMouseClicked(appWindowManager, appLaunchState) { event, windowInfo ->
MacTrayMouseClicked(appLaunchState) { event, windowInfo ->
val isCtrlDown = (event.modifiersEx and InputEvent.CTRL_DOWN_MASK) != 0
if (event.button == MouseEvent.BUTTON1 && !isCtrlDown) {
mainCoroutineDispatcher.launch(CoroutineName("Switch CrossPaste")) {
Expand All @@ -121,27 +116,7 @@ object MacTrayView {
)
}

private fun refreshWindowPosition(
appWindowManager: DesktopAppWindowManager,
windowInfo: WindowInfo,
) {
val appSize = appWindowManager.appSize
val windowPosition =
WindowPosition.Absolute(
x = windowInfo.x.dp + (windowInfo.width.dp / 2) - (appSize.mainWindowSize.width / 2),
y = windowInfo.y.dp + appSize.mainWindowTopMargin,
)
appWindowManager.setMainWindowState(
WindowState(
size = appWindowManager.appSize.mainWindowSize,
position = windowPosition,
),
)
logger.debug { "main position: $windowPosition" }
}

class MacTrayMouseClicked(
private val appWindowManager: DesktopAppWindowManager,
private val appLaunchState: DesktopAppLaunchState,
private val mouseClickedAction: (MouseEvent, WindowInfo) -> Unit,
) : MouseAdapter() {
Expand All @@ -151,7 +126,6 @@ object MacTrayView {
windowInfos.useAll {
windowInfos.first { it.contains(e.xOnScreen, e.yOnScreen) }.let {
mouseClickedAction(e, it)
refreshWindowPosition(appWindowManager, it)
}
}
}
Expand Down
10 changes: 9 additions & 1 deletion app/src/desktopMain/kotlin/com/crosspaste/ui/MainWindow.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.window.WindowPosition
import androidx.compose.ui.window.rememberWindowState
import com.crosspaste.app.DesktopAppSize
import com.crosspaste.app.DesktopAppWindowManager
import com.crosspaste.listener.GlobalListener
Expand Down Expand Up @@ -36,9 +39,14 @@ fun MainWindow(windowIcon: Painter?) {
val globalListener = koinInject<GlobalListener>()
val themeDetector = koinInject<ThemeDetector>()

val mainWindowState by appWindowManager.mainWindowState.collectAsState()
val showMainWindow by appWindowManager.showMainWindow.collectAsState()

val mainWindowState =
rememberWindowState(
size = appSize.mainWindowSize,
position = WindowPosition(Alignment.Center),
)

// Initialize global listener only once
LaunchedEffect(Unit) {
globalListener.start()
Expand Down
35 changes: 2 additions & 33 deletions app/src/desktopMain/kotlin/com/crosspaste/ui/WindowsTrayView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.WindowPlacement
import androidx.compose.ui.window.WindowPosition
import androidx.compose.ui.window.WindowState
import androidx.compose.ui.window.rememberWindowState
import com.crosspaste.app.AppLaunchState
import com.crosspaste.app.DesktopAppLaunch
Expand Down Expand Up @@ -76,7 +75,6 @@ object WindowsTrayView {

LaunchedEffect(Unit) {
delay(1000)
refreshWindowPosition(appWindowManager, null) { _, _, _ -> }
if (appLaunchState.firstLaunch && !firstLaunchCompleted) {
appWindowManager.showMainWindow()
appLaunch.setFirstLaunchCompleted(true)
Expand All @@ -88,7 +86,7 @@ object WindowsTrayView {
state = remember { notificationManager.trayState },
tooltip = "CrossPaste",
mouseListener =
WindowsTrayMouseClicked(appWindowManager) { event, gd, insets ->
WindowsTrayMouseClicked { event, gd, insets ->
if (event.button == MouseEvent.BUTTON1) {
mainCoroutineDispatcher.launch(CoroutineName("Switch CrossPaste")) {
appWindowManager.hideMainWindow()
Expand Down Expand Up @@ -181,49 +179,20 @@ object WindowsTrayView {
}

fun refreshWindowPosition(
appWindowManager: DesktopAppWindowManager,
event: MouseEvent?,
eventAction: (MouseEvent, GraphicsDevice, Insets) -> Unit,
) {
Copy link

Copilot AI Jul 6, 2025

Choose a reason for hiding this comment

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

[nitpick] Since this method now only forwards the event to mouseClickedAction, consider inlining or removing it to reduce indirection and simplify the click handler.

Copilot uses AI. Check for mistakes.
val gd = GraphicsEnvironment.getLocalGraphicsEnvironment().defaultScreenDevice
val insets = Toolkit.getDefaultToolkit().getScreenInsets(gd.defaultConfiguration)
event?.let { eventAction(it, gd, insets) }

val bounds = gd.defaultConfiguration.bounds
val usableWidth = bounds.width - insets.right
val usableHeight = bounds.height - insets.bottom

val appSize = appWindowManager.appSize

val windowWidth = appSize.mainWindowSize.width
val windowHeight = appSize.mainWindowSize.height

val xOffset = appSize.mainHorizontalShadowPadding - appSize.edgePadding
val yOffset = appSize.mainBottomShadowPadding - appSize.edgePadding

val windowPosition =
WindowPosition.Absolute(
x = usableWidth.dp - windowWidth + xOffset,
y = usableHeight.dp - windowHeight + yOffset,
)

appWindowManager.setMainWindowState(
WindowState(
size = appWindowManager.appSize.mainWindowSize,
position = windowPosition,
),
)

logger.debug { "main position: $windowPosition" }
}

class WindowsTrayMouseClicked(
private val appWindowManager: DesktopAppWindowManager,
private val mouseClickedAction: (MouseEvent, GraphicsDevice, Insets) -> Unit,
) : MouseAdapter() {

override fun mouseClicked(e: MouseEvent) {
refreshWindowPosition(appWindowManager, e, mouseClickedAction)
refreshWindowPosition(e, mouseClickedAction)
}
}
}