Skip to content

Commit 9e3233f

Browse files
committed
Add RTL Windows module and update dependencies
Introduce a new RTL Windows module to address layout issues in Compose Desktop apps on Windows in RTL mode. Updated dependencies and developer information across multiple modules. Adjusted versioning mechanism and included the new module in the project structure.
1 parent d01018a commit 9e3233f

14 files changed

Lines changed: 245 additions & 25 deletions

File tree

README.MD

Lines changed: 57 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ println("App version: $version")
8585
This library is available on Maven Central. To include this library in your project, add the following dependency to your `build.gradle.kts`:
8686

8787
```kotlin
88-
implementation("io.github.kdroidfilter:platformtools.core:0.2.7")
88+
implementation("io.github.kdroidfilter:platformtools.core:<version>")
8989
```
9090

9191
## 🌙 Dark Mode Detection Module
@@ -185,7 +185,7 @@ On Linux, the title bar updates correctly with system-wide dark mode settings, s
185185
This library is available on Maven Central. To include this module in your project, add the following dependency to your `build.gradle.kts`:
186186

187187
```kotlin
188-
implementation("io.github.kdroidfilter:platformtools.darkmodedetector:0.2.7")
188+
implementation("io.github.kdroidfilter:platformtools.darkmodedetector:<version>")
189189
```
190190

191191
---
@@ -377,7 +377,7 @@ fun isFirstInstallation(): Boolean
377377
This library is available on Maven Central. To include it in your project, add the following dependency to your `build.gradle.kts` :
378378

379379
```kotlin
380-
implementation("io.github.kdroidfilter:platformtools.appmanager:0.2.7")
380+
implementation("io.github.kdroidfilter:platformtools.appmanager:<version>")
381381
```
382382

383383
---
@@ -508,7 +508,7 @@ fun main() = runBlocking {
508508
This library is available on Maven Central. To include it in your project, add the following dependency to your `build.gradle.kts`:
509509

510510
```kotlin
511-
implementation("io.github.kdroidfilter:platformtools.releasefetcher:0.2.7")
511+
implementation("io.github.kdroidfilter:platformtools.releasefetcher:<version>")
512512
```
513513

514514
---
@@ -701,7 +701,59 @@ fun checkAndRequestReadExternalStoragePermission() {
701701
This library is available on Maven Central. To include it in your project, add the following dependency to your `build.gradle.kts` :
702702

703703
```kotlin
704-
implementation("io.github.kdroidfilter:platformtools.permissionhandler:0.2.7")
704+
implementation("io.github.kdroidfilter:platformtools.permissionhandler:<version>")
705+
```
706+
707+
---
708+
709+
## 🔄 RTL Windows Module (JVM only)
710+
711+
The **RTL Windows** module fixes a specific bug in Compose Desktop applications running on Windows in RTL mode, where window buttons (minimize, maximize, close) are incorrectly positioned. This module simply resolves this issue and does nothing if the application is not in RTL mode. It's essential for applications that need to support right-to-left languages like Arabic, Hebrew, or Persian.
712+
713+
### 🔧 Function: `setWindowsRtlLayout`
714+
715+
The `setWindowsRtlLayout` function applies RTL mirroring to a Window based on its component orientation:
716+
717+
```kotlin
718+
fun Window.setWindowsRtlLayout()
719+
```
720+
721+
This extension function:
722+
- Checks if the operating system is Windows (returns early if not)
723+
- Determines if RTL layout is needed based on the window's component orientation
724+
- Applies the appropriate Windows-specific style flags to enable RTL layout
725+
- Updates the window to reflect the new style
726+
727+
### 🔍 How It Works
728+
729+
- Uses JNA (Java Native Access) to interact with the Windows API
730+
- Checks if the application is in RTL mode; if not, it does nothing
731+
- When in RTL mode, applies the `WS_EX_LAYOUTRTL` and `WS_EX_RTLREADING` extended window styles to fix the window buttons positioning
732+
- Only affects Windows OS; has no effect on other operating systems
733+
734+
### 🔧 Example Usage
735+
736+
Here is an example of using `setWindowsRtlLayout` in a Jetpack Compose for Desktop application:
737+
738+
```kotlin
739+
Window(
740+
title = "RTL Example",
741+
state = rememberWindowState(width = 800.dp, height = 600.dp),
742+
onCloseRequest = ::exitApplication,
743+
) {
744+
// Apply RTL layout if needed
745+
window.setWindowsRtlLayout()
746+
747+
App()
748+
}
749+
```
750+
751+
### 📦 Installation
752+
753+
This library is available on Maven Central. To include this module in your project, add the following dependency to your `build.gradle.kts`:
754+
755+
```kotlin
756+
implementation("io.github.kdroidfilter:platformtools.rtlwindows:<version>")
705757
```
706758

707759
---
@@ -722,5 +774,3 @@ Contributions are welcome! If you want to improve this library, please feel free
722774

723775
A demo is available in the `sample` module, showcasing the main features of all the modules included in this library.
724776
Additionally, a demo application with an integrated updater using this library is available [here](https://github.com/kdroidFilter/AppwithAutoUpdater).
725-
726-

build.gradle.kts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,9 @@ plugins {
1010
subprojects {
1111
apply(plugin = "org.jetbrains.dokka")
1212
}
13+
val ref = System.getenv("GITHUB_REF") ?: ""
1314

14-
extra["libVersion"] = "0.2.9"
15+
extra["libVersion"] = if (ref.startsWith("refs/tags/")) {
16+
val tag = ref.removePrefix("refs/tags/")
17+
if (tag.startsWith("v")) tag.substring(1) else tag
18+
} else "dev"

gradle/libs.versions.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ androidx-core = { group = "androidx.core", name = "core", version.ref = "core" }
2424
androidcontextprovider = { module = "io.github.kdroidfilter:androidcontextprovider", version.ref = "androidcontextprovider" }
2525
androidx-activityCompose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activityCompose" }
2626
jfa = { module = "de.jangassen:jfa", version.ref = "jfa" }
27-
jna = { module = "net.java.dev.jna:jna", version.ref = "jna" }
28-
jna-platform = { module = "net.java.dev.jna:jna-platform", version.ref = "jna" }
27+
jna = { module = "net.java.dev.jna:jna-jpms", version.ref = "jna" }
28+
jna-platform = { module = "net.java.dev.jna:jna-platform-jpms", version.ref = "jna" }
2929
kermit = { module = "co.touchlab:kermit", version.ref = "kermit" }
3030
kotlinx-browser-wasm-js = { module = "org.jetbrains.kotlinx:kotlinx-browser-wasm-js", version.ref = "kotlinxBrowserWasmJs" }
3131
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinxCoroutinesCore" }
@@ -48,4 +48,4 @@ compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "
4848
android-application = { id = "com.android.application", version.ref = "agp" }
4949
kotlinx-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
5050
vannitktech-maven-publish = {id = "com.vanniktech.maven.publish", version = "0.32.0"}
51-
dokka = { id = "org.jetbrains.dokka" , version = "2.0.0"}
51+
dokka = { id = "org.jetbrains.dokka" , version = "2.0.0"}

platformtools/appmanager/build.gradle.kts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ kotlin {
2222
commonMain.dependencies {
2323
implementation(project(":platformtools:core"))
2424
implementation(libs.kotlinx.coroutines.core)
25-
implementation("co.touchlab:kermit:2.0.5") //Add latest version
25+
implementation(libs.kermit)
2626
}
2727

2828
commonTest.dependencies {
@@ -86,7 +86,7 @@ mavenPublishing {
8686
developers {
8787
developer {
8888
id.set("kdroidfilter")
89-
name.set("Elyahou Hadass")
89+
name.set("Elie Gambache")
9090
email.set("elyahou.hadass@gmail.com")
9191
}
9292
}

platformtools/core/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ mavenPublishing {
127127
developers {
128128
developer {
129129
id.set("kdroidfilter")
130-
name.set("Elyahou Hadass")
130+
name.set("Elie Gambache")
131131
email.set("elyahou.hadass@gmail.com")
132132
}
133133
}

platformtools/darkmodedetector/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ mavenPublishing {
7979
developers {
8080
developer {
8181
id.set("kdroidfilter")
82-
name.set("Elyahou Hadass")
82+
name.set("Elie Gambache")
8383
email.set("elyahou.hadass@gmail.com")
8484
}
8585
}

platformtools/permissionhandler/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ mavenPublishing {
8989
developers {
9090
developer {
9191
id.set("kdroidfilter")
92-
name.set("Elyahou Hadass")
92+
name.set("Elie Gambache")
9393
email.set("elyahou.hadass@gmail.com")
9494
}
9595
}

platformtools/releasefetcher/build.gradle.kts

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,6 @@ kotlin {
4141
}
4242

4343

44-
jvmMain {
45-
dependencies {
46-
implementation(libs.androidcontextprovider)
47-
48-
}
49-
}
50-
5144
androidMain {
5245
dependencies {
5346
implementation(libs.androidcontextprovider)
@@ -100,7 +93,7 @@ mavenPublishing {
10093
developers {
10194
developer {
10295
id.set("kdroidfilter")
103-
name.set("Elyahou Hadass")
96+
name.set("Elie Gambache")
10497
email.set("elyahou.hadass@gmail.com")
10598
}
10699
}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import com.vanniktech.maven.publish.SonatypeHost
2+
import org.jetbrains.dokka.gradle.DokkaTask
3+
4+
plugins {
5+
alias(libs.plugins.multiplatform)
6+
alias(libs.plugins.compose)
7+
alias(libs.plugins.compose.compiler)
8+
alias(libs.plugins.vannitktech.maven.publish)
9+
}
10+
val libVersion : String by rootProject.extra
11+
12+
group = "io.github.kdroidfilter.platformtools.rtlwindows"
13+
version = libVersion
14+
15+
kotlin {
16+
jvmToolchain(17)
17+
18+
jvm()
19+
20+
21+
sourceSets {
22+
commonMain.dependencies {
23+
implementation(project(":platformtools:core"))
24+
implementation(libs.kotlinx.coroutines.core)
25+
implementation(libs.kermit)
26+
}
27+
28+
commonTest.dependencies {
29+
implementation(kotlin("test"))
30+
}
31+
32+
jvmMain.dependencies {
33+
implementation(libs.jna)
34+
implementation(libs.jna.platform)
35+
implementation(compose.foundation)
36+
}
37+
38+
39+
40+
}
41+
42+
//https://kotlinlang.org/docs/native-objc-interop.html#export-of-kdoc-comments-to-generated-objective-c-headers
43+
targets.withType<org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget> {
44+
compilations["main"].compileTaskProvider.configure {
45+
compilerOptions {
46+
freeCompilerArgs.add("-Xexport-kdoc")
47+
}
48+
}
49+
}
50+
51+
}
52+
53+
54+
mavenPublishing {
55+
coordinates(
56+
groupId = "io.github.kdroidfilter",
57+
artifactId = "platformtools.rtlwindows",
58+
version = version.toString()
59+
)
60+
61+
pom {
62+
name.set("PlatformTools Rtl Windows Fix")
63+
description.set("Fix in Windows OS bug that the Title bar not display correctly in rtl mode")
64+
inceptionYear.set("2025")
65+
url.set("https://github.com/kdroidFilter/")
66+
67+
licenses {
68+
license {
69+
name.set("MIT License")
70+
url.set("https://opensource.org/licenses/MIT")
71+
}
72+
}
73+
74+
developers {
75+
developer {
76+
id.set("kdroidfilter")
77+
name.set("Elie Gambache")
78+
email.set("elyahou.hadass@gmail.com")
79+
}
80+
}
81+
82+
scm {
83+
connection.set("scm:git:git://github.com/kdroidFilter/platformtools.git")
84+
developerConnection.set("scm:git:ssh://git@github.com:kdroidFilter/platformtools.git")
85+
url.set("https://github.com/kdroidFilter/platformtools")
86+
}
87+
}
88+
89+
publishToMavenCentral(SonatypeHost.CENTRAL_PORTAL)
90+
91+
signAllPublications()
92+
}
93+
94+
tasks.withType<DokkaTask>().configureEach {
95+
moduleName.set("Platforms Tools")
96+
offlineMode.set(true)
97+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package io.github.kdroidfilter.platformtools.rtlwindows
2+
3+
import com.sun.jna.Native
4+
import com.sun.jna.platform.win32.BaseTSD.LONG_PTR
5+
import com.sun.jna.platform.win32.WinDef
6+
import com.sun.jna.win32.StdCallLibrary
7+
import com.sun.jna.win32.W32APIOptions
8+
9+
/* ---------- User32 bindings ---------- */
10+
internal interface User32 : StdCallLibrary {
11+
companion object {
12+
val INSTANCE: User32 =
13+
Native.load("user32", User32::class.java, W32APIOptions.DEFAULT_OPTIONS)
14+
}
15+
16+
fun GetWindowLongPtr(hWnd: WinDef.HWND, nIndex: Int): LONG_PTR
17+
fun SetWindowLongPtr(hWnd: WinDef.HWND, nIndex: Int, dwNewLong: LONG_PTR): LONG_PTR
18+
fun SetWindowPos(
19+
hWnd: WinDef.HWND,
20+
hWndInsertAfter: WinDef.HWND?,
21+
X: Int,
22+
Y: Int,
23+
cx: Int,
24+
cy: Int,
25+
uFlags: Int
26+
): Boolean
27+
}
28+
29+
const val GWL_EXSTYLE = -20
30+
const val WS_EX_LAYOUTRTL = 0x0040_0000 // Mirror the entire window
31+
const val WS_EX_RTLREADING = 0x0000_2000 // RTL title-bar text
32+
const val SWP_NOMOVE = 0x0001
33+
const val SWP_NOSIZE = 0x0002
34+
const val SWP_NOZORDER = 0x0004
35+
const val SWP_FRAMECHANGED = 0x0020

0 commit comments

Comments
 (0)