https://github.com/msink/kotlin-ui
https://github.com/msink/kotlin-ui
Last synced: about 2 months ago
JSON representation
- Host: GitHub
- URL: https://github.com/msink/kotlin-ui
- Owner: msink
- Created: 2017-07-21T10:01:50.000Z (almost 8 years ago)
- Default Branch: master
- Last Pushed: 2018-05-19T13:55:33.000Z (about 7 years ago)
- Last Synced: 2025-03-29T19:11:18.204Z (2 months ago)
- Language: C
- Size: 71.2 MB
- Stars: 21
- Watchers: 2
- Forks: 2
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
Kotiln-UI
=========2018-05-19: this repository remains here for historical reasons, continued in https://github.com/msink/kotlin-libui
## Motivation
Just for fun, wanted to try new flavor of [Kotlin](https://kotlinlang.org)
language - [Kotlin/Native](https://github.com/JetBrains/kotlin-native)_Kotlin/Native_ is under development, but as is - in technical preview stage -
can produce reasonably-sized self-contained programs for 64-bit versions
of 3 major OSes - Windows/Linux/MacOS.
(It also can produce binaries for embedded/mobile devices, but in this area not
so ready because of performance issues. For modern desktops performance is not
critical in most cases, and it is already usable.)Lets explore how _Kotlin/Native_ can be used for producing small self-contained
GUI applications.## UI library
We need a native GUI library with C interface - _Kotlin/Native_ currently can
interop only with libraries that have plain C API.
GTK and QT are too big and complex, I wanted someting relatively small,
cross-platform and with native-looking widgets.Here it is - [libui](https://github.com/andlabs/libui)
## Preparations
Assume we have Windows 7 64-bit, working environment is `c:\src`.
Download and build _Kotlin/Native_ :
cd \src
git clone https://github.com/JetBrains/kotlin-native.git
chdir kotlin-native
gradlew dependencies:update
gradlew dist
chdir ..Working directory:
mkdir kotlin-ui
chdir kotlin-uiNow we have two sibling directories: `\src\kotlin-native` and `\src\kotlin-ui`.
## Low-Level bindings
Create and enter working directory:
mkdir libui
chdir libuiDownload and unpack libui tarball:
wget https://github.com/andlabs/libui/releases/download/alpha3.1/alpha3.1.tgz --no-check-certificate -O libui.tgz`
7z x libui.tgz -so | 7z x -si -ttar(or use your favorite programs to download and unpack)
Create `libui\libui.def`:
headers = ui.h
headerFilter = ui.h
compilerOpts = -I./alpha3.1/srcCreate and run `libui\build.bat`:
@echo off
setlocal
set KOTLIN_HOME=..\..\kotlin-native\dist
set "PATH=%KOTLIN_HOME%\bin;%PATH%"
call cinterop -def libui.def -o libui || exit /b
rename libui-build build-nativeIt should produce `libui.klib` - native bindings for _Kotlin/Native_ :)
## High-Level bindings
Now we have direct binding for libui, but it is too low-level for user code.
Lets create one more level to isolate this low-level API -
[uiWidgets.kt](https://github.com/msink/kotlin-ui/blob/master/libui/kotlin/uiWidgets.kt)(TODO: complete bindings, something like TornadoFX)
## Test program
Create simple [test](https://github.com/msink/kotlin-ui/blob/master/src/test.kt):
```kotlin
fun main(args: Array) = ui.application {
val window = ui.Window("Button example", width=320, height=60)
window.margined = trueval button = ui.Button()
button.text = "Konan ãîâîðèò: click me!"
button.onClick { println ("Hi Kotlin") }
window.child = buttonwindow.show()
}
```Create and run `build.bat`:
@echo off
setlocal
set "PATH=..\kotlin-native\dist\bin;%PATH%"
set LFLAGS=libui\alpha3.1\windows_amd64\mingw_static\libui.a^
-luser32 -lkernel32 -lusp10 -lgdi32 -lcomctl32 -luxtheme^
-lmsimg32 -lcomdlg32 -ld2d1 -ldwrite -lole32 -loleaut32^
-loleacc -luuid -mwindows
call konanc src libui/kotlin -library libui/libui -linkerOpts "%LFLAGS%" -o testResult - `test.exe` - when runned should draw small window with one button inside.
## Debugging
OK, but how to debug?
Currently _Kotlin/Native_ have very limited debugging capabilites.
Sure it will improve someday, but what to do now?There is a way. _Kotlin/Native_ itself is JVM program, written in _Kotlin/JVM_ .
But it also heavily use LLVM toolchain, and LLVM is native.
How these two parts interact? And how compiler developers debug it?Looking in _Kotlin/Native_ sources, one can find *JVM version of Interop* .
It is almost similar to native cinterop, but designed to work with "big" Kotlin,
using under the hood `sun.misc.Unsafe` and `ffi`.But this way anyone can develop and debug in familiar and powerful IDEA,
and then just compile to native!Lets try.
First, quick and dirty, just copy jvm-citerop to our working directory:
xcopy /E /I \src\kotlin-native\Interop\Runtime\src\jvm cinterop\jvm\
xcopy /E /I \src\kotlin-native\Interop\Runtime\src\main cinterop\main\
xcopy /E /I \src\kotlin-native\dist\konan\nativelib\callbacks.dll cinteropNow, we need to generate jvm bindings for libui.
Modify `libui\libui.def` like this:
```
headers = ui.h
headerFilter = ui.hcompilerOpts = -I./alpha3.1/src -std=c99 -fPIC \
-Wall -W -Wno-unused-parameter -Wwrite-strings -Wmissing-field-initializers \
-pedantic -Wno-long-long -Wcovered-switch-default -Wdelete-non-virtual-dtor \
-DNDEBUG -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROSlinker = clang++
linkerOpts = -fPIC -fvisibility-inlines-hidden \
-Wall -W -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers \
-pedantic -Wno-long-long -Wcovered-switch-default -Wnon-virtual-dtor -Wdelete-non-virtual-dtor \
-std=c++11 \
-DNDEBUG -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS
```And `libui\build.bat`:
```
@echo off
setlocalset KOTLIN_HOME=..\..\kotlin-native\dist
set "PATH=%KOTLIN_HOME%\bin;%PATH%"set LFLAGS=alpha3.1\windows_amd64\mingw_static\libui.a^
-luser32 -lkernel32 -lusp10 -lgdi32 -lcomctl32 -luxtheme^
-lmsimg32 -lcomdlg32 -ld2d1 -ldwrite -lole32 -loleaut32^
-loleacc -luuid^
-mwindows^
-static-libgcc -static-libstdc++^
-Wl,-Bstatic,--whole-archive -lwinpthread -Wl,--no-whole-archive,-Bdynamiccall cinterop -def libui.def -flavor jvm -linkerOpts "%LFLAGS%" -o libui
rename libui-build build-jvmcall cinterop -def libui.def -o libui || exit /b
rename libui-build build-native
```This "magic" was mostly copied from `kotlin-native\backend.native\llvm.def`
But `citerop` don't like undocumented `-flavor` option, so I just patched kotlin
sources, and rebuild. Yes, quick and dirty :)```patch
@@ -329,11 +329,11 @@ private fun processLib(konanHome: String,
args: Map>) {val userDir = System.getProperty("user.dir")
val ktGenRoot = args["-generated"]?.single() ?: userDir
val nativeLibsDir = args["-natives"]?.single() ?: userDir
- val flavorName = args["-flavor"]?.single() ?: "jvm"
+ val flavorName = args["-flavor"]?.lastOrNull() ?: "jvm"
val flavor = KotlinPlatform.values().single { it.name.equals(flavorName, ignoreCase = true) }
val target = args["-target"]?.single()?.targetSuffix() ?: defaultTarget
val defFile = args["-def"]?.single()?.let { File(it) }
val manifestAddend = args["-manifest"]?.single()?.let { File(it) }
```Now, running libui\build.bat should produce both native and jvm bindings.
And finally, create IDEA kotlin project in our working directory,
add source paths (Ctrl+Alt+Shift+S) - `libui/kotlin`, `build-jvm/kotlin`, `cinterop`
add native paths `libui/build-jvm/natives` and `cinterop`Trying to run - we get error, something like "ffi not loaded".
OK, patch our copy of cinterop, quick and dirty again:```patch
--- "F:\src\kotlin-native\Interop\Runtime\src\jvm\kotlin\kotlinx\cinterop\JvmCallbacks.kt"
+++ "F:\src\kotlin-ui\cinterop\jvm\JvmCallbacks.kt"
@@ -201,7 +201,6 @@
val kFunction = function as? KFunction<*> ?: function.reflect() ?:
throw IllegalArgumentException(errorMessage)+ loadCallbacksLibrary()
val returnType = getArgOrRetValCType(kFunction.returnType)
val paramTypes = kFunction.parameters.map { getArgOrRetValCType(it.type) }
```Finally it should work, you can develop and debug in IDEA.