GTK sample (#515)

* GTK sample

* Add full UTF8 recoding ability to interop
This commit is contained in:
Nikolay Igotti
2017-04-20 23:09:36 +03:00
committed by GitHub
parent 5368eb0f2f
commit 5517ed7296
7 changed files with 135 additions and 15 deletions
@@ -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
+15 -1
View File
@@ -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 {
+12
View File
@@ -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.
+34
View File
@@ -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
+1
View File
@@ -0,0 +1 @@
headers = gtk/gtk.h
+69
View File
@@ -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)
}