1. #1
    Membre régulier
    Homme Profil pro
    chercheur
    Inscrit en
    décembre 2012
    Messages
    162
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : chercheur

    Informations forums :
    Inscription : décembre 2012
    Messages : 162
    Points : 72
    Points
    72

    Par défaut Problème "assertion GTK_IS_WIDGET (widget) failed" avec gtk_widget_queue_draw_area()

    Bonjour à tous,

    Je bute sur une problème que je ne sais pas résoudre (GTK+2).

    J'ai bati un code exemple minimal qui déclanche le problème. Le voici:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    #include <stdio.h>
    #include <cairo.h>
    #include <gtk/gtk.h>
    #include <glib.h>
     
    gint pos_x=500,pos_y=500;
    GtkWidget *window;
    GtkWidget *drawarea; /* drawing area */
    GRand *tirage; /* a random generator */
     
    gint grid[1001][1001]; /* content of the grid  */
     
    int main(int argc, char *argv[])
    {
        gboolean on_expose_event(GtkWidget *widget, GdkEvent *event, gpointer userdata);
        gboolean update(gpointer);
        void OnDestroy(GtkWidget *pWidget, gpointer pData); /* function call back destroy */
        void initialise(int);
     
        gtk_init(&argc, &argv);
     
        /* main window creation */
        window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
        gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
     
        /* random generator creation */
        tirage=g_rand_new();
     
        /* drawing points in the grid */
        initialise(200);
     
        /* drawing area creation */
        drawarea=gtk_drawing_area_new();
        gtk_widget_set_size_request(drawarea, (gint)1200, (gint)1200);
     
        /* adding the drawarea to the window */
        gtk_container_add (GTK_CONTAINER(window), drawarea);
     
        g_signal_connect(G_OBJECT(drawarea), "expose_event", G_CALLBACK(on_expose_event), NULL);
        g_signal_connect(window, "destroy", G_CALLBACK(OnDestroy), NULL);
        g_timeout_add((guint)10, update, NULL); /* called function at regular intervals */
        gtk_widget_show_all(window);
        gtk_main();
        return 0;
    }
     
    void OnDestroy(GtkWidget *pWidget, gpointer pData)
    {
        g_rand_free(tirage);
        gtk_main_quit();
    }
     
    void initialise(int food)
    {
        int i,j,flag,tmp_x,tmp_y;
        for (i=1;i<=1000;i++)
        {
            for (j=1;j<=1000;j++)
            {
                grid[i][j]=0;
            }
        }
     
        /* drawing randomly locations in the grid */
        for (i=1;i<=food;i++)
        {
            flag=1;
            while (flag)
            {
                 /* drawing an empty cell in the grid */
                tmp_x=(int)(g_rand_double(tirage)*1000.)+1;
                tmp_y=(int)(g_rand_double(tirage)*1000.)+1;
                if (grid[tmp_x][tmp_y]==0)
                    flag=0;
            }
            grid[tmp_x][tmp_y]=1;
        }
    }
    gboolean on_expose_event(GtkWidget *widget, GdkEvent *event, gpointer userdata)
    {
        int i, j;
        cairo_t *cr=NULL;
        cr=gdk_cairo_create(drawarea->window);
        cairo_set_source_rgb(cr, .0, .0, .0);
        cairo_rectangle(cr, 10.,10.,1000.,1000.);
     
        /* drawing  items in the grid  */
        for (i=1;i<=1000;i++)
        {
            for (j=1;j<=1000;j++)
            {
                if (grid[i][j]==1)
                {
                    cairo_move_to(cr,(double)i+5.+10.,(double)j+10.);
                    cairo_arc(cr,(double)i+10.,(double)j+10., 5., 0.,6.28);
                }
            }
        }
        cairo_stroke(cr);
        cairo_destroy(cr);
        return FALSE;
    }
     
    gboolean update(gpointer pData)
    {
        /* invalidating a zone around pos_x, pos-y to force redrawing by the callback function link to expose-event */
        gtk_widget_queue_draw_area(drawarea, pos_x-40,pos_y-40,80,80);
        return TRUE;
    }
    Ce code tourne bien, sauf que en sortie, j'ai le message suivant :
    Gtk-CRITICAL **: gtk_widget_queue_draw_area: assertion 'GTK_IS_WIDGET (widget)' failed

    Je précise que ce code en soit ne présente aucun intérêt. Il fait un update toutes les 10 millisecondes, alors que rien ne change. Cependant, dans le véritable code que je développe, il y aura des choses qui changeront, d'où la nécessité de faire un rafraichissement rapide.

    Enfin, ce code tire au hasard 200 points sur une grille (voir ligne 30). En revanche, si je ne tire que 100 points, le problème disparait. Ca ressemble à un problème d'allocation de taille de tableau, mais je ne vois pas où, et surtout pourquoi ça serait gtk_widget_queue_draw_area() qui poserait problème dans ce cas, comme le message d'erreur l'indique ? C'est peut-être une erreur d'étourderie de ma part, mais je ne vois pas où..

    Merci pour toute aide sur ce point.

    Cordialement, Eric.

  2. #2
    Membre régulier
    Homme Profil pro
    chercheur
    Inscrit en
    décembre 2012
    Messages
    162
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : chercheur

    Informations forums :
    Inscription : décembre 2012
    Messages : 162
    Points : 72
    Points
    72

    Par défaut

    Bon,

    A force de chercher, j'ai fini par trouver le problème. Il suffit de rajouter un cairo_stroke() de manière régulière dans la construction de la chaine d'instructions de dessin. J'imagine que ceci vider égulièrement la pile d'instructions, et que - sans ça - cette pile devient trop grosse et va "empiéter" dans la pile des données..

    Le fait que le message d'erreur indiquait gtk_widget_queue_draw_area() comme la source du problème était vraiment trompeur..

    Problème résolu, donc,

    Désolé pour le dérangement,

    Eric.

  3. #3
    Modérateur

    Homme Profil pro
    Développeur informatique
    Inscrit en
    juin 2009
    Messages
    1 315
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Industrie

    Informations forums :
    Inscription : juin 2009
    Messages : 1 315
    Points : 1 979
    Points
    1 979

    Par défaut

    Bonjour,

    je viens de voir ton code, et tu n'es quand même pas venu pour rien, parce qu'il y a quand même plusieurs soucis.

    1. Pourquoi utiliser GTK+ 2, alors que GTK+ 3 est sorti en 2011 et est stable depuis des années.
    2. Si tu veux dessiner avec cairo, je te conseille aussi GTK+ 3 car il te fournit directement le contexte cairo. Tu n'as plus à le recréer/détruire sans cesse. En GTK+ 3, on dessine en réponse au signal "draw", "expose-event" a disparu.
    3. Tu utilises gtk_widget_queue_draw_area, mais dans ton expose-event, tu redessines tout à chaque image. Vu la quantité de cases (1 million), c'est complètement sous-optimal, surtout si tu comptes raffraîchir ça toutes les 10ms. Je te conseille de réécrire ta calback on_expose_event en regardant dans le GdkEvent la zone qui a été invalidée. Tu peux alors te restreindre à ne redessiner que le strict nécessaire.
    4. "GTK_IS_WIDGET (widget) failed", ça te dit que le pointeur passé ne pointe pas vers un widget, ce qui signifie souvent que la mémoire en question a été écrasée ou que le widget a déjà été détruit.
    5. N'utilise pas g_timeout_add toutes les 10ms pour forcer un rafraichissement. À la place, tu dois avoir une API qui te permet de manipuler ta grille (modifier des éléments dedans), et après chaque modification de la grille, tu appelles gtk_widget_queue_draw_area (voire éventuellement gtk_widget_queue_draw_region) avec juste la zone correspondant à la case à redessiner. Actuellement tu utilises massivement le CPU pour redessiner des choses qui ne changent pas.
    Documentation officielle GTK+ 3:
    GTK en C, GTK en Python

    Tutoriels GTK+ 3:
    GTK en C, GTK en Python

    Tutoriels par l'exemple (platform-demos):
    GTK (tous langages)

  4. #4
    Membre régulier
    Homme Profil pro
    chercheur
    Inscrit en
    décembre 2012
    Messages
    162
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : chercheur

    Informations forums :
    Inscription : décembre 2012
    Messages : 162
    Points : 72
    Points
    72

    Par défaut

    Citation Envoyé par liberforce Voir le message
    Bonjour,

    je viens de voir ton code, et tu n'es quand même pas venu pour rien, parce qu'il y a quand même plusieurs soucis.

    [*]Pourquoi utiliser GTK+ 2, alors que GTK+ 3 est sorti en 2011 et est stable depuis des années.
    C'est une bonne question et nous avons déjà discuté plusieurs fois de ceci sur ce forum. La raison est que j'ai la flemme (1) d'investir du temps pour apprendre ce qui a changé entre GTK+2 et GTK+3; et surtout (2) de reprendre et corriger tous mes codes pour que ca refonctionne bien (et j'en ai un paquet, et certains sont vraiment gros).. Mais bon, je sais que je suis criticable ici.

    Citation Envoyé par liberforce Voir le message
    Si tu veux dessiner avec cairo, je te conseille aussi GTK+ 3 car il te fournit directement le contexte cairo. Tu n'as plus à le recréer/détruire sans cesse. En GTK+ 3, on dessine en réponse au signal "draw", "expose-event" a disparu.
    Je crois que la réponse à ce commentaire est la même qu'au commentaire précédent.
    Citation Envoyé par liberforce Voir le message
    Tu utilises gtk_widget_queue_draw_area, mais dans ton expose-event, tu redessines tout à chaque image. Vu la quantité de cases (1 million), c'est complètement sous-optimal, surtout si tu comptes raffraîchir ça toutes les 10ms. Je te conseille de réécrire ta calback on_expose_event en regardant dans le GdkEvent la zone qui a été invalidée. Tu peux alors te restreindre à ne redessiner que le strict nécessaire.
    Là c'est une vraie question, et qui montre qu'il y a quelque chose que je n'ai pas compris, peut-être. gtk_widget_queue_draw_area() utilise explicitement la zone (rectangluaire) qui doit être ré-argumentée. J'imagine que seulement cette zone est donc redessinée, sans quoi pourquoi doit-on définir cette zone ici si tout est redessiné à chaque fois ? Il y a t'il un point ici (important) qui m'échappe ?
    Citation Envoyé par liberforce Voir le message
    "GTK_IS_WIDGET (widget) failed", ça te dit que le pointeur passé ne pointe pas vers un widget, ce qui signifie souvent que la mémoire en question a été écrasée ou que le widget a déjà été détruit.
    Oui, c'est ce que j'avais donc bien compris, comme je l'ai expliqué dans ma réponse précédente.
    Citation Envoyé par liberforce Voir le message
    [*]N'utilise pas g_timeout_add toutes les 10ms pour forcer un rafraichissement. À la place, tu dois avoir une API qui te permet de manipuler ta grille (modifier des éléments dedans), et après chaque modification de la grille, tu appelles gtk_widget_queue_draw_area (voire éventuellement gtk_widget_queue_draw_region) avec juste la zone correspondant à la case à redessiner. Actuellement tu utilises massivement le CPU pour redessiner des choses qui ne changent pas.
    Oui, mais dans l'application que je suis en train de développer, il y modification vraiment tout le temps. J'ai besoin d'une telle cadence (énorme je sais) de rafraichissement.

    Dans tous les cas, merci pour tes avis et ta disponibilité.

    Eric.

  5. #5
    Modérateur

    Homme Profil pro
    Développeur informatique
    Inscrit en
    juin 2009
    Messages
    1 315
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Industrie

    Informations forums :
    Inscription : juin 2009
    Messages : 1 315
    Points : 1 979
    Points
    1 979

    Par défaut

    Citation Envoyé par eric1708 Voir le message
    C'est une bonne question et nous avons déjà discuté plusieurs fois de ceci sur ce forum. La raison est que j'ai la flemme (1) d'investir du temps pour apprendre ce qui a changé entre GTK+2 et GTK+3; et surtout (2) de reprendre et corriger tous mes codes pour que ca refonctionne bien (et j'en ai un paquet, et certains sont vraiment gros).. Mais bon, je sais que je suis criticable ici.
    Désolé, je radote, mais bon, écrire du code pour une plateforme obsolète... Les fonctionnalités de dessin "à la main" comme tu fais sont aussi juste plus simple à gérer dans GTK+ 3 puisque l'intégration de cairo est nettement meilleure... Plus besoin de faire des aller-retours entre contextes GDK et cairo.

    Citation Envoyé par eric1708 Voir le message
    Là c'est une vraie question, et qui montre qu'il y a quelque chose que je n'ai pas compris, peut-être. gtk_widget_queue_draw_area() utilise explicitement la zone (rectangluaire) qui doit être ré-argumentée. J'imagine que seulement cette zone est donc redessinée, sans quoi pourquoi doit-on définir cette zone ici si tout est redessiné à chaque fois ? Il y a t'il un point ici (important) qui m'échappe ?
    Clariement oui, le toolkit ne fait pas de magie. Tu es responsable de l'image que tu dessines dans une GtkDrawingArea. Dans un toolkit graphique (j'ai fait des MFC sous Windows il y a longtemps, c'était pareil), quand tu dessines toi même à l'écran, tu indiques les zones à metre à jour. Cette information ne sert qu'à être transmise dans l'expose-event, pour que tu puisses récupérer les dans l'événement Gdk qui t'est passé (le GdkEvent que tu reçois en paramètre dans ta callback est un GdkEventExpose). Dans cet événement, le membre 'area' est un GdkRectangle qui correspond à la zone à redessiner, et créé à partir des informations que tu as toi même passé à gtk_widget_queue_draw_area. C'est cela que tu dois utiliser pour déduire quelles cases de ta grille doivent être mises à jour à l'écran, et tu ne redessines que celles là. Je te conseille de lire les tutoriels de dessin en GTK+ 2 et surtout de lancer gtk-demo et de regarder le code des exemples de dessin associé.

    Citation Envoyé par eric1708 Voir le message
    Oui, mais dans l'application que je suis en train de développer, il y modification vraiment tout le temps. J'ai besoin d'une telle cadence (énorme je sais) de rafraichissement.
    Je t'assure que non, tu n'as pas besoin de cette cadence . Tu en veux la preuve ? Un raffraichissement toutes les 10ms correspond à une fréquence de 100 images par secondes (100fps) . Ton écran doit sans doute rafraîchir à 60Hz, donc au mieux tu gaspilles de la puissance de calcul pour rien puisque tu ne pourrais pas afficher toutes les images que tu as calculées, au pire tu charges ton système tellement que tu auras 3 images par seconde... Ce n'est pas du temps réel, si tu écroule le système, tu as beau demander à g_timeout de te réveiller dans 10ms, il ne te le garantit pas. Je le sais, j'ai déjà fait une appli de ce genre en python + GTK+ 2 il y a 10 ans pour un projet de recherche: mise à jour de points dans une grille pour affichage sur une interface graphique déportée. C'était pour de la détection de forme dans un passage RATP. Les fonction de clipping de cairo m'avaient été très utile aussi dans ce contexte pour ne dessiner que le strict nécessaire. Tout ce que tu fais en trop, c'est du temps processeur en moins pour ton algo.
    Documentation officielle GTK+ 3:
    GTK en C, GTK en Python

    Tutoriels GTK+ 3:
    GTK en C, GTK en Python

    Tutoriels par l'exemple (platform-demos):
    GTK (tous langages)

  6. #6
    Membre régulier
    Homme Profil pro
    chercheur
    Inscrit en
    décembre 2012
    Messages
    162
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : chercheur

    Informations forums :
    Inscription : décembre 2012
    Messages : 162
    Points : 72
    Points
    72

    Par défaut

    Citation Envoyé par liberforce Voir le message
    Désolé, je radote, mais bon, écrire du code pour une plateforme obsolète... Les fonctionnalités de dessin "à la main" comme tu fais sont aussi juste plus simple à gérer dans GTK+ 3 puisque l'intégration de cairo est nettement meilleure... Plus besoin de faire des aller-retours entre contextes GDK et cairo.
    Non, tu ne radotes pas et tu as raison. Mais - comme je l'ai expliqué - je n'ai juste pas le temps pour investir dans l'apprentissage des nouvelles caractéristiques de GTK+3 par rapport à GTK+2, et surtout pour reprendre et modifier tous mes codes. J'ai mon sujet de recherche à développer. Coder est un moyen, pas un but pour moi.
    Citation Envoyé par liberforce Voir le message
    Clariement oui, le toolkit ne fait pas de magie. Tu es responsable de l'image que tu dessines dans une GtkDrawingArea. Dans un toolkit graphique (j'ai fait des MFC sous Windows il y a longtemps, c'était pareil), quand tu dessines toi même à l'écran, tu indiques les zones à metre à jour. Cette information ne sert qu'à être transmise dans l'expose-event, pour que tu puisses récupérer les dans l'événement Gdk qui t'est passé (le GdkEvent que tu reçois en paramètre dans ta callback est un GdkEventExpose). Dans cet événement, le membre 'area' est un GdkRectangle qui correspond à la zone à redessiner, et créé à partir des informations que tu as toi même passé à gtk_widget_queue_draw_area. C'est cela que tu dois utiliser pour déduire quelles cases de ta grille doivent être mises à jour à l'écran, et tu ne redessines que celles là. Je te conseille de lire les tutoriels de dessin en GTK+ 2 et surtout de lancer gtk-demo et de regarder le code des exemples de dessin associé.
    Ok, je comprends. Je vais tacher d'améliorer ceci. Deux remarques, cependant:
    1) Dans l'exemple que je donne au début de ce post, certes il y a une grille de 1000x1000 à argumenter (donc effectivement un million de cases), mais seulement 200 objets sont à dessiner, ce qui n'est pas énorme, et ca tourne de manière fluide sur ma machine.
    2) J'ai pas mal bataillé pour apprendre à me servir de cairo, et la raison est que les tutoriels sont assez rares sur la toile, je trouve. Des exemples seraient effectivement bienvenus..
    Citation Envoyé par liberforce Voir le message
    Je t'assure que non, tu n'as pas besoin de cette cadence . Tu en veux la preuve ? Un raffraichissement toutes les 10ms correspond à une fréquence de 100 images par secondes (100fps) . Ton écran doit sans doute rafraîchir à 60Hz, donc au mieux tu gaspilles de la puissance de calcul pour rien puisque tu ne pourrais pas afficher toutes les images que tu as calculées, au pire tu charges ton système tellement que tu auras 3 images par seconde... Ce n'est pas du temps réel, si tu écroule le système, tu as beau demander à g_timeout de te réveiller dans 10ms, il ne te le garantit pas. Je le sais, j'ai déjà fait une appli de ce genre en python + GTK+ 2 il y a 10 ans pour un projet de recherche: mise à jour de points dans une grille pour affichage sur une interface graphique déportée. C'était pour de la détection de forme dans un passage RATP. Les fonction de clipping de cairo m'avaient été très utile aussi dans ce contexte pour ne dessiner que le strict nécessaire. Tout ce que tu fais en trop, c'est du temps processeur en moins pour ton algo.
    Oui, bon point. 10 millisecondes est une cadence trop élevée. Cette remarque est pertinente. Je vais réduire, ce qui déchargera la cpu de ma machine.

    Encore merci pour ton temps et tes avis, très utiles.

    Cordialement, Eric.

  7. #7
    Modérateur

    Homme Profil pro
    Développeur informatique
    Inscrit en
    juin 2009
    Messages
    1 315
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Industrie

    Informations forums :
    Inscription : juin 2009
    Messages : 1 315
    Points : 1 979
    Points
    1 979

    Par défaut

    Citation Envoyé par eric1708 Voir le message
    Non, tu ne radotes pas et tu as raison. Mais - comme je l'ai expliqué - je n'ai juste pas le temps pour investir dans l'apprentissage des nouvelles caractéristiques de GTK+3 par rapport à GTK+2, et surtout pour reprendre et modifier tous mes codes. J'ai mon sujet de recherche à développer. Coder est un moyen, pas un but pour moi.
    Je le comprends tout à fait, et je suis complètement d'accord sur le fait que c'est un moyen et non un but. Mais les choses se compliquent quand tu es sur de vieilles versions. J'ai vu hier par exemple qu'il y a un bug dans la génération de la documentation en ligne de GTK+ 2, du coup il manque plein d'infos. J'ai un peu galérer à trouver les infos sur GdkEventExpose, j'ai du chercher directement dans le code. C'est un bug, mais passé ça a pu passer inaperçu car plus personne ne regarde vérifie cela parce que c'est une vielle version.

    Ensuite, il y a un guide de migration de GTK+ 2 à GTK+ 3 intégré à la documentation officielle (avec notamment un passage sur cairo), mais tu n'es absolument pas obligé de porter ton ancien code. En revanche, pour de nouveaux projets, ça peut éventuellement être plus intéressant de commencer sur une version plus récente. Après, tu as le droit de préférer l'homogénéité aussi et avoir envie de tout avoir qui tourne avec la même version de GTK+, ça se défend, et puis c'est ton code
    Documentation officielle GTK+ 3:
    GTK en C, GTK en Python

    Tutoriels GTK+ 3:
    GTK en C, GTK en Python

    Tutoriels par l'exemple (platform-demos):
    GTK (tous langages)

  8. #8
    Membre régulier
    Homme Profil pro
    chercheur
    Inscrit en
    décembre 2012
    Messages
    162
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : chercheur

    Informations forums :
    Inscription : décembre 2012
    Messages : 162
    Points : 72
    Points
    72

    Par défaut

    Citation Envoyé par liberforce Voir le message
    mais tu n'es absolument pas obligé de porter ton ancien code. En revanche, pour de nouveaux projets, ça peut éventuellement être plus intéressant de commencer sur une version plus récente.
    Si j'ai bien compris, quand tu dis que je ne suis pas obligé de porter mes anciens codes, ça veut juste dire que les codes compilés tourneront correctement, ce qui - pour moi - est une évidence. En revanche, si je dois y porter même une infime modification, ce qui arrive fréquemment et que je dois donc recompiler, je me heurterai alors à l'ensemble des problèmes de migration. C'est bien ça ? Ceci n'est pas une volonté de ma part d’atteindre l'homogénéité.

    Merci pour les liens sur la migration, y compris pour cairo. Je vais tâcher d'y jeter un oeiL

    Merci encore une fois pour ton temps.

    Cordialement, Eric.

  9. #9
    Modérateur

    Homme Profil pro
    Développeur informatique
    Inscrit en
    juin 2009
    Messages
    1 315
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Industrie

    Informations forums :
    Inscription : juin 2009
    Messages : 1 315
    Points : 1 979
    Points
    1 979

    Par défaut

    Citation Envoyé par eric1708 Voir le message
    Si j'ai bien compris, quand tu dis que je ne suis pas obligé de porter mes anciens codes, ça veut juste dire que les codes compilés tourneront correctement, ce qui - pour moi - est une évidence. En revanche, si je dois y porter même une infime modification, ce qui arrive fréquemment et que je dois donc recompiler, je me heurterai alors à l'ensemble des problèmes de migration. C'est bien ça ? Ceci n'est pas une volonté de ma part d’atteindre l'homogénéité.
    Non, j'ai dû mal m'exprimer. Ce que je dis c'est que tu peux rester en GTK+ 2 sur tes anciens projets, sans les migrer à GTK+ 3 si c'est ton choix. Cependant les versions majeures de GTK+ sont parallèlement installables. Là sur une vieille Ubuntu 14.04, j'ai les paquets libgtk2.0-0 et libgtk-3-0 installés. Tu peux donc avoir sur ton système des vieilles applications non migrées utilisant GTK+ 2 et des applications plus récentes où tu utilises directement GTK+ 3. Ainsi si un jour quelqu'un doit reprendre ton code, il ne sera pas obligé de se farcir la migration de toutes tes applications, juste les plus anciennes.

    Ensuite, voici concrètement comment on migre une application GTK+ 2 vers GTK+ 3:
    Avoir juste à recompiler sans changer le code, c'est nécessaire quand il y a rupture de compatibilité dans l'ABI. Or là le changement de version majeure indique qu'il y a aussi rupture dans l'API : si tu essaies de recompiler ton application GTK+ 2 en la linkant avec la bibliothèque GTK+ 3, cela peut potentiellement se faire sans soucis si tu as suivi quelques bonnes pratiques, que tu n'utilises aucun symbole (fonction, widget, signal) signalé comme obsolète. Tu peux vérifier si ton application GKT+ 2 est prête à migrer à GTK+ 3 en la compilant (toujours avec GTK+ 2) en définissant:

    • G_DISABLE_DEPRECATED (pour la glib)
    • GDK_PIXBUF_DISABLE_DEPRECATED (pour gdk-pixbuf)
    • GDK_DISABLE_DEPRECATED (pour gdk)
    • GTK_DISABLE_DEPRECATED (pour gtk)


    Évidemment pour cela il faut être à jour sur la dernière version de GTK+ 2 (2.24.x) pour que la liste des symboles déclarés comme obsolètes soit à jour. Si ça passe, alors la migration à GTK+ 3 derait se faire sans trop de difficulté. Il faut remplacer les signal "expose-event" par "draw" et changer le prototype de la callback associée pour recevoir un contexte cairo directement, mais c'est à peu près tout je crois.

    En revanche, si ça ne compile pas, alors c'est que tu utilises encore des fonctionnalités anciennes qui ont été rendues obsolètes pendant la vie de GTK+ 2. Et tout ce qui était obsolète en GTK+ 2 a disparu dans GTK+ 3 (la rupture de compatibilité d'API évite d'avoir à maintenir du vieux code sans cesse). Là ça peut être plus compliqué, parce que le compilateur s'arrête à la première erreur, et tu ne sais pas combien il en reste derrière. C'est pour cela que la technique qu'on utilisait à l'époque de la migration dans GNOME c'était d'avoir un fichier contenant toutes les API obsolètes, et on faisait un grep de ces symboles dans le code pour voir les symboles obsolètes utilisés (et donc à migrer):

    https://wiki.gnome.org/Initiatives/G...Symbols/GTK%2B
    https://wiki.gnome.org/Initiatives/G...edSymbols/Glib

    Cette méthode te donne un aperçu de la charge de travail que représente la migration, il suffit de compter le nombre de lignes où tu utilises des symboles obsolètes. Pour certains, ça peut être très simple à corriger, un simple rechercher/remplacer dans tout le code faisant le boulot en 1 seconde, pour d'autres, ça peut être plus complexe. Par exemple pour des widgets obsolètes, il faut redévelopper la portion de code qui l'utilise avec un autre widget, ce qui a potentiellement une influence sur l'apparence de ton application ou sur l'expérience utilisateur.

    Si tu veux un example d'une application simple utilisant cairo en GTK+ 2 et voir ce que ça donne en GTK+ 3, j'ai fait une application example il y a quelques temps:
    https://github.com/liberforce/gtk-sa...2-graph/main.c
    https://github.com/liberforce/gtk-sa...3-graph/main.c

    Pour ce programme de 102 lignes, le portage a consisté à modifier 6 lignes, et en supprimer 11 autres. Cela représente la suppression de la conversion gdk → cairo qui est n'est plus nécessaire en GTK+ 3, et le remplacement du signal "expose-event" par "draw". Ce n'est absolument pas représentatif d'un effort de portage pour une plus grosse application, celle-ci étant minimaliste, mais c'est représentatif de l'impact du passage de "expose-event" à "draw" quand on utilise déjà cairo en GTK+ 2.
    Documentation officielle GTK+ 3:
    GTK en C, GTK en Python

    Tutoriels GTK+ 3:
    GTK en C, GTK en Python

    Tutoriels par l'exemple (platform-demos):
    GTK (tous langages)

  10. #10
    Membre régulier
    Homme Profil pro
    chercheur
    Inscrit en
    décembre 2012
    Messages
    162
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : chercheur

    Informations forums :
    Inscription : décembre 2012
    Messages : 162
    Points : 72
    Points
    72

    Par défaut

    Citation Envoyé par liberforce Voir le message
    Non, j'ai dû mal m'exprimer. Ce que je dis c'est que tu peux rester en GTK+ 2 sur tes anciens projets, sans les migrer à GTK+ 3 si c'est ton choix. Cependant les versions majeures de GTK+ sont parallèlement installables. Là sur une vieille Ubuntu 14.04, j'ai les paquets libgtk2.0-0 et libgtk-3-0 installés. Tu peux donc avoir sur ton système des vieilles applications non migrées utilisant GTK+ 2 et des applications plus récentes où tu utilises directement GTK+ 3. Ainsi si un jour quelqu'un doit reprendre ton code, il ne sera pas obligé de se farcir la migration de toutes tes applications, juste les plus anciennes.

    Ensuite, voici concrètement comment on migre une application GTK+ 2 vers GTK+ 3:
    Avoir juste à recompiler sans changer le code, c'est nécessaire quand il y a rupture de compatibilité dans l'ABI. Or là le changement de version majeure indique qu'il y a aussi rupture dans l'API : si tu essaies de recompiler ton application GTK+ 2 en la linkant avec la bibliothèque GTK+ 3, cela peut potentiellement se faire sans soucis si tu as suivi quelques bonnes pratiques, que tu n'utilises aucun symbole (fonction, widget, signal) signalé comme obsolète. Tu peux vérifier si ton application GKT+ 2 est prête à migrer à GTK+ 3 en la compilant (toujours avec GTK+ 2) en définissant:

    • G_DISABLE_DEPRECATED (pour la glib)
    • GDK_PIXBUF_DISABLE_DEPRECATED (pour gdk-pixbuf)
    • GDK_DISABLE_DEPRECATED (pour gdk)
    • GTK_DISABLE_DEPRECATED (pour gtk)


    Évidemment pour cela il faut être à jour sur la dernière version de GTK+ 2 (2.24.x) pour que la liste des symboles déclarés comme obsolètes soit à jour. Si ça passe, alors la migration à GTK+ 3 derait se faire sans trop de difficulté. Il faut remplacer les signal "expose-event" par "draw" et changer le prototype de la callback associée pour recevoir un contexte cairo directement, mais c'est à peu près tout je crois.

    En revanche, si ça ne compile pas, alors c'est que tu utilises encore des fonctionnalités anciennes qui ont été rendues obsolètes pendant la vie de GTK+ 2. Et tout ce qui était obsolète en GTK+ 2 a disparu dans GTK+ 3 (la rupture de compatibilité d'API évite d'avoir à maintenir du vieux code sans cesse). Là ça peut être plus compliqué, parce que le compilateur s'arrête à la première erreur, et tu ne sais pas combien il en reste derrière. C'est pour cela que la technique qu'on utilisait à l'époque de la migration dans GNOME c'était d'avoir un fichier contenant toutes les API obsolètes, et on faisait un grep de ces symboles dans le code pour voir les symboles obsolètes utilisés (et donc à migrer):

    https://wiki.gnome.org/Initiatives/G...Symbols/GTK%2B
    https://wiki.gnome.org/Initiatives/G...edSymbols/Glib

    Cette méthode te donne un aperçu de la charge de travail que représente la migration, il suffit de compter le nombre de lignes où tu utilises des symboles obsolètes. Pour certains, ça peut être très simple à corriger, un simple rechercher/remplacer dans tout le code faisant le boulot en 1 seconde, pour d'autres, ça peut être plus complexe. Par exemple pour des widgets obsolètes, il faut redévelopper la portion de code qui l'utilise avec un autre widget, ce qui a potentiellement une influence sur l'apparence de ton application ou sur l'expérience utilisateur.

    Si tu veux un example d'une application simple utilisant cairo en GTK+ 2 et voir ce que ça donne en GTK+ 3, j'ai fait une application example il y a quelques temps:
    https://github.com/liberforce/gtk-sa...2-graph/main.c
    https://github.com/liberforce/gtk-sa...3-graph/main.c

    Pour ce programme de 102 lignes, le portage a consisté à modifier 6 lignes, et en supprimer 11 autres. Cela représente la suppression de la conversion gdk → cairo qui est n'est plus nécessaire en GTK+ 3, et le remplacement du signal "expose-event" par "draw". Ce n'est absolument pas représentatif d'un effort de portage pour une plus grosse application, celle-ci étant minimaliste, mais c'est représentatif de l'impact du passage de "expose-event" à "draw" quand on utilise déjà cairo en GTK+ 2.
    Ok, merci et utile.

    Je vais voir si j'ai le temps de ma lancer dans "cette aventure".

    Cordialement, Eric.

  11. #11
    Nouveau membre du Club
    Homme Profil pro
    Chercheur en informatique
    Inscrit en
    septembre 2017
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Chercheur en informatique
    Secteur : Bâtiment

    Informations forums :
    Inscription : septembre 2017
    Messages : 26
    Points : 35
    Points
    35

    Par défaut

    Bonsoir à tous,

    Gtk-CRITICAL **: gtk_widget_queue_draw_area: assertion 'GTK_IS_WIDGET (widget)' failed
    ça te dit que le pointeur passé ne pointe pas vers un widget, ce qui signifie souvent que la mémoire en question a été écrasée ou que le widget a déjà été détruit.

    Problème résolu[...]Il suffit de rajouter un cairo_stroke() de manière régulière dans la construction de la chaine d'instructions de dessin
    Nom : 7d93cd1e30croire.jpg
Affichages : 21
Taille : 28,5 Ko

    Pour ma part, j'ai lu et essayé ton code, J'ai l'impression que le message d'erreur survient lorsque l'on quitte ton application. J'imagine que g_timeout_add ne prenant pas en considération gtk_main_quit, ta fonction update() est appelé alors même que Gtk à détruit les widget. Aussi, je pense que cette erreur peut survenir au démarrage de l'application (quand les widget ne sont pas encore realized ).

    Je vois deux possibilité pour corriger ce problème :
    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    gboolean update(gpointer pData)
    {
        /* invalidating a zone around pos_x, pos-y to force redrawing by the callback function link to expose-event */
     
        if (GTK_IS_WIDGET(drawarea))
          gtk_widget_queue_draw_area(drawarea, pos_x-40,pos_y-40,80,80);
        return TRUE;
    }

    Ou :
    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
     
    static gboolean repeatedly = TRUE;//G_SOURCE_CONTINUE
    //...
    void OnDestroy(GtkWidget *pWidget, gpointer pData)
    {
        repeatedly = FALSE;//G_SOURCE_REMOVE
        g_rand_free(tirage);
        gtk_main_quit();
    }
    gboolean update(gpointer pData)
    {
        /* invalidating a zone around pos_x, pos-y to force redrawing by the callback function link to expose-event */
     
        if (repeatedly)
          gtk_widget_queue_draw_area(drawarea, pos_x-40,pos_y-40,80,80);
        return repeatedly;
    }

    Bien à vous,

  12. #12
    Membre régulier
    Homme Profil pro
    chercheur
    Inscrit en
    décembre 2012
    Messages
    162
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : chercheur

    Informations forums :
    Inscription : décembre 2012
    Messages : 162
    Points : 72
    Points
    72

    Par défaut

    Merci. Très instructif et très utile !

    Eric.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. problème d' "assertion" avec GTK+
    Par poutch dans le forum Langage
    Réponses: 5
    Dernier message: 02/05/2011, 22h42
  2. Problème "LoadModule ssl_module modules/mod_ssl.so"
    Par ldcarpathes dans le forum Apache
    Réponses: 9
    Dernier message: 24/01/2008, 12h07
  3. Réponses: 2
    Dernier message: 05/10/2005, 17h13
  4. Problème unit CRT pour Faire du Pascal avec Delphi
    Par alexmorel dans le forum Débutant
    Réponses: 4
    Dernier message: 01/06/2004, 18h13

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo