GTK sample (#515)
* GTK sample * Add full UTF8 recoding ability to interop
This commit is contained in:
@@ -4,18 +4,7 @@ import konan.internal.Intrinsic
|
|||||||
|
|
||||||
internal fun decodeFromUtf8(bytes: ByteArray): String = kotlin.text.fromUtf8Array(bytes, 0, bytes.size)
|
internal fun decodeFromUtf8(bytes: ByteArray): String = kotlin.text.fromUtf8Array(bytes, 0, bytes.size)
|
||||||
|
|
||||||
fun encodeToUtf8(str: String): ByteArray {
|
fun encodeToUtf8(str: String): ByteArray = kotlin.text.toUtf8Array(str, 0, str.length)
|
||||||
val result = ByteArray(str.length)
|
|
||||||
|
|
||||||
for (index in 0 .. str.length - 1) {
|
|
||||||
val char = str[index]
|
|
||||||
if (char.toInt() >= 128) {
|
|
||||||
TODO("non-ASCII char")
|
|
||||||
}
|
|
||||||
result[index] = char.toByte()
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
@Intrinsic
|
@Intrinsic
|
||||||
external fun bitsToFloat(bits: Int): Float
|
external fun bitsToFloat(bits: Int): Float
|
||||||
|
|||||||
@@ -784,6 +784,20 @@ OBJ_GETTER(Kotlin_String_fromUtf8Array, KConstRef thiz, KInt start, KInt size) {
|
|||||||
RETURN_RESULT_OF(utf8ToUtf16, rawString, array->count_);
|
RETURN_RESULT_OF(utf8ToUtf16, rawString, array->count_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OBJ_GETTER(Kotlin_String_toUtf8Array, KString thiz, KInt start, KInt size) {
|
||||||
|
RuntimeAssert(thiz->type_info() == theStringTypeInfo, "Must use String");
|
||||||
|
if (start < 0 || size < 0 || size > thiz->count_ - start) {
|
||||||
|
ThrowArrayIndexOutOfBoundsException();
|
||||||
|
}
|
||||||
|
const KChar* utf16 = CharArrayAddressOfElementAt(thiz, start);
|
||||||
|
std::string utf8;
|
||||||
|
utf8::utf16to8(utf16, utf16 + size, back_inserter(utf8));
|
||||||
|
ArrayHeader* result = AllocArrayInstance(
|
||||||
|
theByteArrayTypeInfo, utf8.size() + 1, OBJ_RESULT)->array();
|
||||||
|
::memcpy(ByteArrayAddressOfElementAt(result, 0), utf8.c_str(), utf8.size());
|
||||||
|
RETURN_OBJ(result->obj());
|
||||||
|
}
|
||||||
|
|
||||||
OBJ_GETTER(Kotlin_String_fromCharArray, KConstRef thiz, KInt start, KInt size) {
|
OBJ_GETTER(Kotlin_String_fromCharArray, KConstRef thiz, KInt start, KInt size) {
|
||||||
const ArrayHeader* array = thiz->array();
|
const ArrayHeader* array = thiz->array();
|
||||||
RuntimeAssert(array->type_info() == theCharArrayTypeInfo, "Must use a char array");
|
RuntimeAssert(array->type_info() == theCharArrayTypeInfo, "Must use a char array");
|
||||||
@@ -796,7 +810,7 @@ OBJ_GETTER(Kotlin_String_fromCharArray, KConstRef thiz, KInt start, KInt size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ArrayHeader* result = AllocArrayInstance(
|
ArrayHeader* result = AllocArrayInstance(
|
||||||
theStringTypeInfo, size, OBJ_RESULT)->array();
|
theStringTypeInfo, size, OBJ_RESULT)->array();
|
||||||
memcpy(CharArrayAddressOfElementAt(result, 0),
|
memcpy(CharArrayAddressOfElementAt(result, 0),
|
||||||
CharArrayAddressOfElementAt(array, start),
|
CharArrayAddressOfElementAt(array, start),
|
||||||
size * sizeof(KChar));
|
size * sizeof(KChar));
|
||||||
|
|||||||
@@ -15,11 +15,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
package kotlin.text
|
package kotlin.text
|
||||||
import kotlin.collections.*
|
|
||||||
|
|
||||||
@SymbolName("Kotlin_String_fromUtf8Array")
|
@SymbolName("Kotlin_String_fromUtf8Array")
|
||||||
external fun fromUtf8Array(array: ByteArray, start: Int, size: Int) : String
|
external fun fromUtf8Array(array: ByteArray, start: Int, size: Int) : String
|
||||||
|
|
||||||
|
@SymbolName("Kotlin_String_toUtf8Array")
|
||||||
|
external fun toUtf8Array(string: String, start: Int, size: Int) : ByteArray
|
||||||
|
|
||||||
// TODO: make it somewhat private?
|
// TODO: make it somewhat private?
|
||||||
@SymbolName("Kotlin_String_fromCharArray")
|
@SymbolName("Kotlin_String_fromCharArray")
|
||||||
external fun fromCharArray(array: CharArray, start: Int, size: Int) : String
|
external fun fromCharArray(array: CharArray, start: Int, size: Int) : String
|
||||||
@@ -27,7 +29,6 @@ external fun fromCharArray(array: CharArray, start: Int, size: Int) : String
|
|||||||
@SymbolName("Kotlin_String_toCharArray")
|
@SymbolName("Kotlin_String_toCharArray")
|
||||||
external fun toCharArray(string: String) : CharArray
|
external fun toCharArray(string: String) : CharArray
|
||||||
|
|
||||||
|
|
||||||
class StringBuilder private constructor (
|
class StringBuilder private constructor (
|
||||||
private var array: CharArray
|
private var array: CharArray
|
||||||
) : CharSequence, Appendable {
|
) : CharSequence, Appendable {
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# GTK application
|
||||||
|
|
||||||
|
This example shows how one may use _Kotlin/Native_ to build GUI
|
||||||
|
applications with the GTK toolkit.
|
||||||
|
|
||||||
|
To build use `./build.sh` script without arguments (or specify `TARGET` variable if cross-compiling).
|
||||||
|
To run on Mac install XQuartz X server (https://www.xquartz.org/), and then
|
||||||
|
|
||||||
|
./Gtk3Demo
|
||||||
|
|
||||||
|
Dialog box with the button will be shown, and application will print message
|
||||||
|
and terminate on button click.
|
||||||
Executable
+34
@@ -0,0 +1,34 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
PATH=../../dist/bin:../../bin:$PATH
|
||||||
|
DIR=.
|
||||||
|
|
||||||
|
IPREFIX_macbook=-I/opt/local/include
|
||||||
|
IPREFIX_linux=-I/usr/include
|
||||||
|
LINKER_ARGS_macbook="-L/opt/local/lib -lglib-2.0 -lgdk-3.0 -lgtk-3 -lgio-2.0 -lgobject-2.0"
|
||||||
|
LINKER_ARGS_linux="-L/usr/lib/x86_64-linux-gnu -lglib-2.0 -lgdk-3.0 -lgtk-3 -lgio-2.0 -lgobject-2.0"
|
||||||
|
|
||||||
|
if [ x$TARGET == x ]; then
|
||||||
|
case "$OSTYPE" in
|
||||||
|
darwin*) TARGET=macbook ;;
|
||||||
|
linux*) TARGET=linux ;;
|
||||||
|
*) echo "unknown: $OSTYPE" && exit 1;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
var=IPREFIX_${TARGET}
|
||||||
|
IPREFIX="${!var}"
|
||||||
|
var=LINKER_ARGS_${TARGET}
|
||||||
|
LINKER_ARGS=${!var}
|
||||||
|
var=COMPILER_ARGS_${TARGET}
|
||||||
|
COMPILER_ARGS=${!var} # add -opt for an optimized build.
|
||||||
|
|
||||||
|
if [ ! -f $DIR/gtk3.bc ]; then
|
||||||
|
echo "Generating GTK stubs (once), may take few mins depending on the hardware..."
|
||||||
|
cinterop -J-Xmx8g -copt $IPREFIX/atk-1.0 -copt $IPREFIX/gdk-pixbuf-2.0 -copt $IPREFIX/cairo -copt $IPREFIX/pango-1.0 \
|
||||||
|
-copt -I/opt/local/lib/glib-2.0/include -copt $IPREFIX/gtk-3.0 -copt $IPREFIX/glib-2.0 -def $DIR/gtk3.def \
|
||||||
|
-target $TARGET -o $DIR/gtk3.bc || exit 1
|
||||||
|
fi
|
||||||
|
konanc -target $TARGET $DIR/src -library $DIR/gtk3.bc -linkerArgs "$LINKER_ARGS" -o $DIR/Gtk3Demo.kexe || exit 1
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
headers = gtk/gtk.h
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import kotlinx.cinterop.*
|
||||||
|
import gtk3.*
|
||||||
|
|
||||||
|
internal fun print_hello(widget: CPointer<GtkApplication>?, data: gpointer?) {
|
||||||
|
println("Hi Kotlin")
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun finish(widget: CPointer<GtkWidget>?) {
|
||||||
|
gtk_widget_destroy(widget)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note that all callback parameters must be primitive types or nullable C pointers.
|
||||||
|
fun g_signal_connect(obj: CPointer<*>, actionName: String,
|
||||||
|
action: GCallback, data: gpointer? = null, connect_flags: Int = 0) {
|
||||||
|
g_signal_connect_data(obj.reinterpret(), actionName, action,
|
||||||
|
data = data, destroy_data = null, connect_flags = connect_flags)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun activate(app: CPointer<GtkApplication>?, user_data: gpointer?) {
|
||||||
|
val windowWidget = gtk_application_window_new(app)!!
|
||||||
|
val window = windowWidget.reinterpret<GtkWindow>()
|
||||||
|
gtk_window_set_title(window, "Window");
|
||||||
|
gtk_window_set_default_size(window, 200, 200)
|
||||||
|
|
||||||
|
val button_box = gtk_button_box_new(
|
||||||
|
GtkOrientation.GTK_ORIENTATION_HORIZONTAL)!!
|
||||||
|
gtk_container_add(window.reinterpret(), button_box);
|
||||||
|
|
||||||
|
val button = gtk_button_new_with_label("Konan говорит: click me!")!!
|
||||||
|
g_signal_connect(button, "clicked",
|
||||||
|
staticCFunction(::print_hello).reinterpret());
|
||||||
|
g_signal_connect(button, "clicked",
|
||||||
|
staticCFunction(::finish).reinterpret(), window, G_CONNECT_SWAPPED)
|
||||||
|
gtk_container_add (button_box.reinterpret(), button);
|
||||||
|
|
||||||
|
gtk_widget_show_all(windowWidget)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun gtkMain(args: Array<String>): Int {
|
||||||
|
val app = gtk_application_new("org.gtk.example", G_APPLICATION_FLAGS_NONE)!!
|
||||||
|
g_signal_connect(app, "activate", staticCFunction(::activate).reinterpret())
|
||||||
|
val status = memScoped {
|
||||||
|
g_application_run(app.reinterpret(),
|
||||||
|
args.size, args.map { it.cstr.getPointer(memScope) }.toCValues())
|
||||||
|
}
|
||||||
|
g_object_unref(app)
|
||||||
|
return status
|
||||||
|
}
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
gtkMain(args)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user