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)
|
||||
|
||||
fun encodeToUtf8(str: String): ByteArray {
|
||||
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
|
||||
}
|
||||
fun encodeToUtf8(str: String): ByteArray = kotlin.text.toUtf8Array(str, 0, str.length)
|
||||
|
||||
@Intrinsic
|
||||
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_);
|
||||
}
|
||||
|
||||
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) {
|
||||
const ArrayHeader* array = thiz->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(
|
||||
theStringTypeInfo, size, OBJ_RESULT)->array();
|
||||
theStringTypeInfo, size, OBJ_RESULT)->array();
|
||||
memcpy(CharArrayAddressOfElementAt(result, 0),
|
||||
CharArrayAddressOfElementAt(array, start),
|
||||
size * sizeof(KChar));
|
||||
|
||||
@@ -15,11 +15,13 @@
|
||||
*/
|
||||
|
||||
package kotlin.text
|
||||
import kotlin.collections.*
|
||||
|
||||
@SymbolName("Kotlin_String_fromUtf8Array")
|
||||
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?
|
||||
@SymbolName("Kotlin_String_fromCharArray")
|
||||
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")
|
||||
external fun toCharArray(string: String) : CharArray
|
||||
|
||||
|
||||
class StringBuilder private constructor (
|
||||
private var array: CharArray
|
||||
) : 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