Problem mit Gtk4 und GLFW3



  • Hallo alle zusammen,

    Ich wollte Einbettung mit GLFW3 Fenster in der Gtk4 Zeichnungsbereich ( DrawingArea )

    Gtk4 ist ganz neu und ich verstehe ein bisschen nicht, weil Inhalt der GTK4 Framework zu viel verändert und umgebaut wurde. Ich kenne schon mit GDK-Window bzw gdk_win32_get_window_handle usw... Jetzt sieht GTK4 anders wie GdkSurface und viele neue Klassen.

    Ich wollte jetzt mit GTk4 und GL;FW3 zum Einbetten ( to embed )
    Ich habe Beuspiel Code von Gtk4 Gitlab herausgeholt und Änderung für Visual Studio 2019 Community ( Via VCPKG )

    Ihr wwusstet schon , dass Gtk4 unter vcpkg erhalten hat?
    Logisch könnt ihr tippen ( Wenn ihr schon vcpkg gemacht habt )

    vcpkg install gtk:x64-windows --recurse
    

    Es dauert sehr ewig ( ungefähr über 1 bis 2 Stunden oder mehr ) Weil vcpkg mit debug und release zum Vorbereiten, Bauen, Einpacken und Installieren ) sehr viel arbeitet.
    Wenn ihr vcpkg bereit ist, dann könnt ihr Visual Studio 2019 oder 2022 Community starten und Includes
    Ich zeige euch wie kann ich alle Include Verzeichnisse zum Kompilieren/Bauen
    https://i.imgur.com/fJ1mc4X.png

    Dann schreibe ich ein erstes Fenster für Gtk4:

    #include <gtk/gtk.h>
    
    void destroy_window(GtkWidget *widget, gpointer data)
    {
        gboolean* done =  static_cast<gboolean*>(GINT_TO_POINTER(data));
        *done = TRUE;
        g_main_context_wakeup(NULL);
    }
    
    int main(int argc, char* argv[])
    {
        GtkWidget *window,;
    
        gtk_init();
    
        gboolean done = FALSE;
    
        window = gtk_window_new();
        g_signal_connect(window, "destroy", G_CALLBACK(destroy_window), &done);
    
        gtk_widget_show(window);
    
        while (!done)
        {
            g_main_context_iteration(NULL, !done);
    
            // Logik wenn ihr etwa coden bzw Aktualisieren ( Update ) oder Machen ( Render )
        }
    
        return 0;
    }
    

    Das war alles. Ihr habt verstanden, oder? Bitte merkt

    static_cast<type>()
    

    für MSVC / Visual Studio um Kompilieren-Fehler zu vermeiden.
    Das ist unterschiedlich zwischen Win32 und Unix Wenn jemand ohne static_cast dann kompiliert es kein Fehler. Das ist unmöglich dass Kompilieren einen Fehler findet oder überhaupt nicht findet.

    Und ich wollte verstehen weil Win32 für HWND und HGDIOBJ als Konflikt zwingt.

    Error: creating glfw_window
    (process:29928): Gdk-WARNING **: 15:21:59.931: ../src/58ebac2b91-58f2f5c120.clean/gdk/win32/gdksurface-win32.c:4615 window is not a native Win32 window
    

    Das heißt Ich habe genauer gelesen, wie kann ich "native" binden?
    GLFW Native Dokumentation ( ENGLISCH )

    Und ich habe versucht.

    #include <stdio.h>
    #include <gtk/gtk.h>
    #include <gdk/win32/gdkwin32.h>
    #include <windows.h>
    
    #include <GLFW/glfw3.h>
    #define GLFW_EXPOSE_NATIVE_WIN32
    #define GLFW_EXPOSE_NATIVE_WGL
    #include <GLFW/glfw3native.h>
    
    static void
    set_fullscreen_monitor_cb(GtkWidget* widget, gpointer user_data)
    {
        GdkFullscreenMode mode = static_cast<GdkFullscreenMode>(GPOINTER_TO_INT(user_data));
        GdkDisplay* display;
        GdkSurface* surface;
        GdkMonitor* monitor;
        GdkToplevelLayout* layout;
    
        display = gtk_widget_get_display(widget);
        surface = gtk_native_get_surface(gtk_widget_get_native(widget));
        if (mode == GDK_FULLSCREEN_ON_CURRENT_MONITOR)
            monitor = gdk_display_get_monitor_at_surface(display, surface);
        else
            monitor = NULL;
        layout = gdk_toplevel_layout_new();
        gdk_toplevel_layout_set_resizable(layout, TRUE);
        gdk_toplevel_layout_set_fullscreen(layout, TRUE, monitor);
        gdk_toplevel_present(GDK_TOPLEVEL(surface), layout);
        gdk_toplevel_layout_unref(layout);
    }
    
    static void
    remove_fullscreen_cb(GtkWidget* widget, gpointer user_data)
    {
        GdkSurface* surface;
        GdkToplevelLayout* layout;
    
        surface = gtk_native_get_surface(gtk_widget_get_native(widget));
        layout = gdk_toplevel_layout_new();
        gdk_toplevel_layout_set_resizable(layout, TRUE);
        gdk_toplevel_layout_set_fullscreen(layout, FALSE, NULL);
        gdk_toplevel_present(GDK_TOPLEVEL(surface), layout);
        gdk_toplevel_layout_unref(layout);
    }
    
    void destroy_window(GtkWidget *widget, gpointer data)
    {
        gboolean* done = static_cast<gboolean*>(GINT_TO_POINTER(data));
        *done = TRUE;
        g_main_context_wakeup(NULL);
    }
    
    HGDIOBJ get_window_hwnd(GtkWidget* widget)
    {
        return gdk_win32_surface_get_handle(gtk_native_get_surface(gtk_widget_get_native(widget)));
    }
    
    int main(int argc, char* argv[])
    {
        GtkWidget *window, *vbox, *button, *darea;
        GLFWwindow *glfw_window;
    
        gtk_init();
    
        gboolean done = FALSE;
    
        window = gtk_window_new();
        g_signal_connect(window, "destroy", G_CALLBACK(destroy_window), &done); // <- You have forgot ??
    
        vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
        gtk_widget_set_valign(vbox, GTK_ALIGN_CENTER);
        gtk_widget_set_halign(vbox, GTK_ALIGN_CENTER);
        gtk_widget_set_margin_start(vbox, 5);
        gtk_widget_set_margin_end(vbox, 5);
        gtk_box_set_homogeneous(GTK_BOX(vbox), TRUE);
        gtk_window_set_child(GTK_WINDOW(window), vbox);
    
        // Trying embed GLFW in GTk4! Versuche´GLFW-Fenster im Gtk4 einzubetten
        darea = gtk_drawing_area_new();
        gtk_drawing_area_set_content_height(GTK_DRAWING_AREA(darea), 200);
        gtk_box_append(GTK_BOX(vbox), darea);
    
        glfwInit();
    
        glfwDefaultWindowHints();
        glfwWindowHint(GLFW_DECORATED, GLFW_FALSE);
        //glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
    
        glfw_window = glfwCreateWindow(gtk_widget_get_width(darea), gtk_widget_get_height(darea), nullptr, nullptr, nullptr);
        if (glfw_window == nullptr)
        {
            printf("Error: creating glfw_window");
        }
        glfwMakeContextCurrent(glfw_window);
    
        // HWND
        HWND from_gtk_darea = static_cast<HWND>(get_window_hwnd(darea));
        SetParent(glfwGetWin32Window(glfw_window), from_gtk_darea);
        SetWindowPos(glfwGetWin32Window(glfw_window), from_gtk_darea, 0, 0, 0, 0, SWP_SHOWWINDOW);
        //SetActiveWindow(from_gtk_darea);
    
        // End of Embed GLFW3
    
        button = gtk_button_new_with_label("Fullscreen on current monitor");
        g_signal_connect(button, "clicked", G_CALLBACK(set_fullscreen_monitor_cb), GINT_TO_POINTER(GDK_FULLSCREEN_ON_CURRENT_MONITOR));
        gtk_box_append(GTK_BOX(vbox), button);
    
        button = gtk_button_new_with_label("Fullscreen on all monitors");
        g_signal_connect(button, "clicked", G_CALLBACK(set_fullscreen_monitor_cb), GINT_TO_POINTER(GDK_FULLSCREEN_ON_ALL_MONITORS));
        gtk_box_append(GTK_BOX(vbox), button);
    
        button = gtk_button_new_with_label("Un-fullscreen");
        g_signal_connect(button, "clicked", G_CALLBACK(remove_fullscreen_cb), NULL);
        gtk_box_append(GTK_BOX(vbox), button);
    
        gtk_widget_show(window);
    
        while (!done && !glfwWindowShouldClose(glfw_window))
        {
            g_main_context_iteration(NULL, !done);
    
            glfwSwapBuffers(glfw_window);
            glfwPollEvents();
        }
    
        glfwTerminate();
    
        return 0;
    }
    

    Und ich kann nicht ausführen, weil es Fehler nach dem Fertigstellen ausgibt, dass es im Eingabeaufforderungsfenster zeigt:
    https://i.imgur.com/QBl1hYV.png

    Wie kann ich verstehen , dass ich HGDIOBJ zu HWND casten kann. Aber trotzdem , das geht es nicht...

    Liebe Grüße!



  • @DeafMan1983 sagte in Problem mit Gtk4 und GLFW3:

    HWND from_gtk_darea = static_cast<HWND>(get_window_hwnd(darea));
    

    Probier's mal mit

    HWND from_gtk_darea = static_cast<HWND>(get_window_hwnd(window));
    

    Ich meine, die Funktion ist deklariert als

    HGDIOBJ gdk_win32_surface_get_handle(GdkSurface *window);
    

    Ich denke der Parametername "window" wird wohl so gemeint sein dass man nur eine GdkSurface übergeben darf welche ein Fenster "ist". Und auf eine mit gtk_drawing_area_new erzeugte GdkSurface wird das wohl nicht zutreffen.

    Und was die Funktion get_window_hwnd angeht... die sollte besser gleich ein HWND zurückgeben - HGDIOBJ ist da total unpassend.
    (HGDIOBJ ist für GDI Handles, und ein Win32 Fenster ist halt kein GDI Objekt - d.h. ein Win32 Fenster Handle ist auch kein GDI Handle.)


Anmelden zum Antworten