Skip to content

Instantly share code, notes, and snippets.

@kropp
Created May 16, 2017 10:31
Show Gist options
  • Save kropp/9b8b9578b9421e932f932bb6aed9598a to your computer and use it in GitHub Desktop.
Save kropp/9b8b9578b9421e932f932bb6aed9598a to your computer and use it in GitHub Desktop.
GTK+ Demo Application in Kotlin/Native rewritten in OO-style
/*
* 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.*
// Note that all callback parameters must be primitive types or nullable C pointers.
fun <F : CFunction<*>> g_signal_connect(obj: CPointer<*>, actionName: String,
action: CPointer<F>, data: gpointer? = null, connect_flags: Int = 0) {
g_signal_connect_data(obj.reinterpret(), actionName, action.reinterpret(),
data = data, destroy_data = null, connect_flags = connect_flags)
}
class Application(id: String) {
val app = gtk_application_new(id, G_APPLICATION_FLAGS_NONE)!!
fun onActivate(callback: CPointer<CFunction<(CPointer<GtkApplication>?, gpointer?) -> Unit>>) {
g_signal_connect(app, "activate", callback)
}
fun run(args: Array<String>): Int {
val status = memScoped {
g_application_run(app.reinterpret(),
args.size, args.map { it.cstr.getPointer(memScope) }.toCValues())
}
g_object_unref(app)
return status
}
}
abstract class Widget {
abstract val widgetPtr: CPointer<GtkWidget>
}
abstract class Container: Widget() {
fun add(widget: Widget) = gtk_container_add(widgetPtr.reinterpret(), widget.widgetPtr)
}
class Window(app: CValuesRef<GtkApplication>): Container() {
override val widgetPtr = gtk_application_window_new(app)!!
private val window get() = widgetPtr.reinterpret<GtkWindow>()
var title: String
get() = ""
set(value) { gtk_window_set_title(window, value) }
fun setDefaultSize(width: Int, height: Int) = gtk_window_set_default_size(window, width, height)
fun showAll() = gtk_widget_show_all(widgetPtr)
}
class ButtonBox(orientation: GtkOrientation): Container() {
override val widgetPtr = gtk_button_box_new(orientation)!!
}
fun signalHandler(sender: CPointer<*>?, data: COpaquePointer?) {
val button = StableObjPtr.fromValue(data!!).get() as Button
button.clicked()
}
typealias SignalHandler = () -> Unit
class Signal {
private var handlers = emptyList<SignalHandler>()
operator fun plusAssign(handler: SignalHandler) { handlers += handler }
operator fun minusAssign(handler: SignalHandler) { handlers -= handler }
operator fun invoke() {
for (handler in handlers) {
try {
handler()
} catch (e: Throwable) {
}
}
}
}
class Button(label: String): Widget() {
override val widgetPtr = gtk_button_new_with_label(label)!!
init {
g_signal_connect(widgetPtr, "clicked", staticCFunction(::signalHandler), StableObjPtr.create(this).value)
}
val clicked = Signal()
}
fun CPointer<GtkApplication>.window(builder: Window.() -> Unit) {
Window(reinterpret()).apply(builder).showAll()
}
fun Container.buttonBox(builder: ButtonBox.() -> Unit) = add(ButtonBox(GtkOrientation.GTK_ORIENTATION_HORIZONTAL).apply(builder))
fun ButtonBox.button(label: String, builder: Button.() -> Unit) = add(Button(label).apply(builder))
fun gtkMain(args: Array<String>): Int {
val app = Application("org.gtk.example")!!
app.onActivate(staticCFunction { app, _ ->
app!!.window {
title = "Kotlin"
setDefaultSize(200, 200)
buttonBox {
button("Hello World!") {
clicked += {
println("Hello Kotlin!")
gtk_widget_destroy([email protected])
}
}
}
}
})
return app.run(args)
}
fun main(args: Array<String>) {
gtkMain(args)
}
Copy link

ghost commented May 31, 2017

I like vala, but kotlin even more.
I was thinking about creating anko style DSL for kotlin native with gtk too.
And this is awesome.

@itisrazza
Copy link

This is absolutely great. I'd guess a logical next step is to take advantage of GObject Introspection to recreate the class structure in Kotlin.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment