GTK4 + GSK Cairo (Windows) or Vulkan (Linux) -- [Experimental]

Submitted by Dickens A S on Sat, 12/07/2019 - 09:52

GitHub: https://github.com/dickensas/kotlin-gradle-templates/tree/master/gtk4-gsk

This demo kotlin code explains how to render a cairo+graphene rectangle region using GSK

Kotlin Code

package plot

import kotlinx.cinterop.*
import gtk4.*

fun realize_callback(widget:CPointer<GtkWidget>?) = memScoped {
    println("realize_callback")
}

fun render_callback(glarea:CPointer<GtkDrawingArea>?, cr:CPointer<cairo_t>?) = memScoped {
    println("render_callback")
    var csurface = cairo_get_target(cr)
    var region = gdk_cairo_region_create_from_surface(csurface)
    var rbga = allocArray<GdkRGBA>(1).apply {
        this[0].red = 1.0
        this[0].green = 0.0
        this[0].blue = 0.0
        this[0].alpha = 1.0
    }
    
    var grect = graphene_rect_alloc()
    grect = graphene_rect_init(grect, 50.0f, 50.0f, 300.0f, 300.0f)
    var gsknode = gsk_color_node_new(rbga, grect)
    
    gsk_render_node_draw(gsknode, cr)
    
    graphene_rect_free(grect)
    cairo_region_destroy(region)
}

fun main() {
    
    gtk_init()
        
    var builder = gtk_builder_new()
    gtk_builder_add_from_file (builder, "glade/window_main.glade", null)
    
    var window = gtk_builder_get_object(builder, "window_main")!!.reinterpret<GtkWidget>()
    gtk_window_set_position(window.reinterpret<GtkWindow>(), GtkWindowPosition.GTK_WIN_POS_CENTER)
    gtk_window_set_default_size(window.reinterpret<GtkWindow>(), 400, 400)
    gtk_window_set_title(window.reinterpret<GtkWindow>(), "Demo Window")
    
    gtk_window_set_resizable(window.reinterpret<GtkWindow>(), 0)
    gtk_window_set_decorated(window.reinterpret<GtkWindow>(), 0)
    gtk_window_set_mnemonics_visible(window.reinterpret<GtkWindow>(), 0)
    
    val box = gtk_drawing_area_new()
    gtk_widget_set_size_request (box, 400, 400);
    gtk_container_add (window.reinterpret(), box)
    
    g_signal_connect_data(
        window.reinterpret(), 
        "destroy", 
        staticCFunction {  
            -> gtk_main_quit()
        }.reinterpret(), 
        null, 
        null, 
        0u
    )
    
    g_signal_connect_data(
        box!!.reinterpret(), 
        "realize", 
        staticCFunction {  glarea:CPointer<GtkWidget>?
            -> realize_callback(glarea)
        }.reinterpret(), 
        null, 
        null, 
        0u
    )
    
    gtk_drawing_area_set_draw_func(
        box.reinterpret(),
        staticCFunction {  glarea:CPointer<GtkDrawingArea>?, cr:CPointer<cairo_t>?
            -> render_callback(glarea,cr)
        }.reinterpret(),
        null, 
        null
    )
    
    gtk_widget_show(window)
    gtk_widget_show(box.reinterpret<GtkWidget>())
    gtk_main()
}

Demo output

GSK GTK4

Please use Alt+F4 to close the GTK window, currently the code written to disable resize

 

For vulkan set environment variable (in linux only)

GSK_RENDERER = vulkan

The entire GTK will be rendered using Vulkan

as of now custom shader cannot be submited to swapchain or framebuffers, none of those function are exposed

Experiment with your own risk:
you can use below functions to create a custom context and do offscreen rendering

in realize callback

gdk_surface_create_vulkan_context
gdk_draw_context_get_surface
gsk_renderer_new_for_surface
gdk_display_flush
gdk_display_sync

in render callback

gdk_draw_context_begin_frame
gdk_vulkan_context_get_draw_semaphore
gdk_vulkan_context_get_draw_index
vkQueuePresentKHR
vkQueueWaitIdle
gdk_draw_context_end_frame

To compile GTK4 refer this article gtk4 msys2

Add new comment