Skip to content

Commit 817bd2b

Browse files
authored
Merge pull request #241 from kdroidFilter/fix-linux-crash-when-changing-from-no-empty-to-empty
Fix-[Linux] Crash when changing from/to empty menuContent #238
2 parents 3c9a82f + b9013c0 commit 817bd2b

4 files changed

Lines changed: 93 additions & 4 deletions

File tree

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package com.kdroid.composetray.demo
2+
3+
import androidx.compose.foundation.Image
4+
import androidx.compose.foundation.layout.fillMaxSize
5+
import androidx.compose.material.Text
6+
import androidx.compose.runtime.getValue
7+
import androidx.compose.runtime.mutableStateOf
8+
import androidx.compose.runtime.remember
9+
import androidx.compose.runtime.setValue
10+
import androidx.compose.ui.Modifier
11+
import androidx.compose.ui.window.Window
12+
import androidx.compose.ui.window.application
13+
import com.kdroid.composetray.tray.api.Tray
14+
import com.kdroid.composetray.utils.ComposeNativeTrayLoggingLevel
15+
import com.kdroid.composetray.utils.allowComposeNativeTrayLogging
16+
import com.kdroid.composetray.utils.composeNativeTrayloggingLevel
17+
import composenativetray.demo.generated.resources.Res
18+
import composenativetray.demo.generated.resources.icon
19+
import composenativetray.demo.generated.resources.icon2
20+
import org.jetbrains.compose.resources.painterResource
21+
22+
/**
23+
* DemoToggleEmptyMenu
24+
*
25+
* Minimal sample to test the Linux bug when switching the tray menu
26+
* from empty to non-empty (and back). Left-click the tray icon to toggle
27+
* the presence of a single menu item. When the flag is false, the menuContent
28+
* is intentionally left empty.
29+
*/
30+
fun main() = application {
31+
// Enable logging to help diagnose behavior on Linux
32+
allowComposeNativeTrayLogging = false
33+
composeNativeTrayloggingLevel = ComposeNativeTrayLoggingLevel.DEBUG
34+
35+
var showMenuItem by remember { mutableStateOf(false) }
36+
val icon = painterResource(Res.drawable.icon)
37+
val icon2 = painterResource(Res.drawable.icon2)
38+
39+
Tray(
40+
iconContent = {
41+
Image(
42+
painter = icon,
43+
contentDescription = "ComposeNativeTray Demo",
44+
modifier = Modifier.fillMaxSize()
45+
)
46+
},
47+
primaryAction = {
48+
// Toggle between empty and non-empty menu
49+
showMenuItem = !showMenuItem
50+
println("Toggled showMenuItem to $showMenuItem")
51+
},
52+
tooltip = "Toggle Empty Menu"
53+
) {
54+
if (showMenuItem) {
55+
Item("I'm here when toggled ON") {
56+
// Clicking this item turns the menu empty again on next open
57+
showMenuItem = false
58+
println("Clicked showMenuItem to $showMenuItem")
59+
}
60+
}
61+
62+
63+
}
64+
Window( onCloseRequest = ::exitApplication) {
65+
Text("Compose Native Tray Demo")
66+
}
67+
}

linuxlib

Submodule linuxlib added at c50e6cb

src/commonMain/kotlin/com/kdroid/composetray/lib/linux/LinuxTrayManager.kt

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,25 @@ internal class LinuxTrayManager(
8585
taskQueue += action
8686
}
8787

88+
// KDE environment detection (KDE Plasma / SNI)
89+
private fun isKDEDesktop(): Boolean {
90+
return try {
91+
val xdg = System.getenv("XDG_CURRENT_DESKTOP") ?: ""
92+
val session = System.getenv("DESKTOP_SESSION") ?: ""
93+
val kdeFull = System.getenv("KDE_FULL_SESSION") ?: ""
94+
val xdgL = xdg.lowercase()
95+
val sessionL = session.lowercase()
96+
val kdeDetected =
97+
kdeFull.equals("true", ignoreCase = true) ||
98+
xdgL.contains("kde") || xdgL.contains("plasma") ||
99+
sessionL.contains("kde") || sessionL.contains("plasma")
100+
if (kdeDetected) debugln { "LinuxTrayManager: KDE environment detected (XDG='$xdg', SESSION='$session', KDE_FULL_SESSION='$kdeFull')" }
101+
kdeDetected
102+
} catch (_: Throwable) {
103+
false
104+
}
105+
}
106+
88107
// ----------------------------------------------------------------------------- menu model
89108
data class MenuItem(
90109
val text: String,
@@ -186,7 +205,8 @@ internal class LinuxTrayManager(
186205
callbackReferences.clear()
187206
menuItemReferences.clear()
188207

189-
if (menuItems.isNotEmpty()) {
208+
val effectiveItems = if (menuItems.isEmpty() && isKDEDesktop()) listOf(MenuItem("-")) else menuItems
209+
if (effectiveItems.isNotEmpty()) {
190210
// Create or clear existing menu ------------------------------------------------
191211
if (menuHandle == null) {
192212
menuHandle = sni.create_menu()
@@ -215,7 +235,7 @@ internal class LinuxTrayManager(
215235
}
216236

217237
// Add menu items --------------------------------------------------------------
218-
menuItems.forEach { addNativeMenuItem(menuHandle!!, it) }
238+
effectiveItems.forEach { addNativeMenuItem(menuHandle!!, it) }
219239
sni.set_context_menu(trayHandle, menuHandle)
220240
infoln { "LinuxTrayManager: Context menu set" }
221241
} else {
@@ -326,12 +346,13 @@ internal class LinuxTrayManager(
326346
}
327347

328348
private fun initializeTrayMenu() {
329-
if (menuItems.isEmpty()) return
349+
val effectiveItems = if (menuItems.isEmpty() && isKDEDesktop()) listOf(MenuItem("-")) else menuItems
350+
if (effectiveItems.isEmpty()) return
330351
menuHandle = sni.create_menu() ?: run {
331352
errorln { "Failed to create menu" }
332353
return
333354
}
334-
menuItems.forEach { addNativeMenuItem(menuHandle!!, it) }
355+
effectiveItems.forEach { addNativeMenuItem(menuHandle!!, it) }
335356
trayHandle?.let { sni.set_context_menu(it, menuHandle) }
336357
}
337358

14.3 KB
Binary file not shown.

0 commit comments

Comments
 (0)