Contenu | Rechercher | Menus

Annonce

Si vous avez des soucis pour rester connecté, déconnectez-vous puis reconnectez-vous depuis ce lien en cochant la case
Me connecter automatiquement lors de mes prochaines visites.

À propos de l'équipe du forum.

#1 Le 20/01/2021, à 15:47

DonutMan75

gtk+-3.0 un exemple que je ne comprends pas...

Bonjour à tous,
je découvre gtk+-3.0 et je bloque rapidement sur l'analyse des exemples...

J'ai installé le paquet gtk-3-examples qui fait miroir (je suppose !) à la documentation de gnome.

$ sudo apt-get install gtk-3-examples

L'exemple application1 est d'une structure très simple :
- main.c > programme principal, se limite à lancer l'application
- exampleapp.{c,h}
- exampleappwin.{c,h}

Dans exampleapp.h, il y a toutefois cette ligne mystérieuse :

#define EXAMPLE_APP_TYPE (example_app_get_type ())

Or cet example_app_get_type n'est défini nulle part ailleurs !!

$ ls *{c,h} | xargs grep "example_app_get_type"
exampleapp.h:#define EXAMPLE_APP_TYPE (example_app_get_type ())

Comment l'interprétez-vous ??

Je ne fais pas encore bien la distinction entre les rôles de exampleapp et exampleappwin mais je bloque déjà sur le #define...

Merci

D.

Hors ligne

#2 Le 20/01/2021, à 19:08

Compte anonymisé

Re : gtk+-3.0 un exemple que je ne comprends pas...

Avec une ligne de code c'est difficile ...

Il doit y avoir en dessous une ligne du genre:

G_DEFINE_TYPE(ExampleApp, example_app, GTK_TYPE_APPLICATION);

G_DEFINE_TYPE est une macro qui sert entre autres à définir "example_app_get_type". Je suppose qu'il n'est pas possible de définir une macro depuis une macro donc on est obligé de la définir manuellement au dessus.

GTK est basé sur GLib et GObject, donc pense à lire la doc de cette dernière.

C'est un choix de commencer avec (le très difficile et verbeux) C ?
Aussi, quitte à découvrir, autant découvrir GTK4 directement.

Dernière modification par abakkk (Le 20/01/2021, à 19:16)

#3 Le 20/01/2021, à 19:23

kevlar

Re : gtk+-3.0 un exemple que je ne comprends pas...

C'est cela, je complète avec un petit historique. Cette macro n'est pas obligatoire, on peut le faire à la main. Pourquoi est-elle présente :? parce que depuis le passage à tk 3, il est recommandé d'abandonner le modèle "gtk_application" au profit du modèle "g_application". Et la macro fort bien reproduite par Abakk te montre tout simplement comment préparer la démarrage d'une "g_application". Attention, c'est touffu : car l'initialisation réelle se fait via un processus d'interruptions logicielles, une réaction à des "événements" prévus par Gtk 3. Peut-être n'est-ce pas un conseil qu'aprrécieront les "pros", mais je te recommande, si tu découvres, de t'inspirer d'anciens progralmmes Gtk, dont l'initialisation est beaucoup plus simple, et restaient comptaibles avec Gtk 3.10, voir si c'est toujours le cas.
Je vais te mettre un  extrait de programme perso sans appel aux macros, qui déclare une g_application malgré tout dans un prochain message.

Hors ligne

#4 Le 20/01/2021, à 19:37

kevlar

Re : gtk+-3.0 un exemple que je ne comprends pas...

Voilà, c'et le 'main.c' du programme nommé PlanLibre. Regarde les deux "callbacks" obligatoires pour activer correctement la g_application (voir dans le bloc de fonction main {} )  Et je vois que je laisse encore traîner une déclaration gtk_application que je sécurise par une macro G_APPLICATION.
Excuse : pas touché au programme depuis août.
Mais ce qui compte ce sont les callbacks vers startiup et activate qui sont obligatoires dans une g_application.
Data_app est propre à mon programme, ne pas en tenir compte.
Tu peux voir également comment j'accède aux fichiers d'interface faits avec Glade en regardant comment lje teste et charge l'interface principale "main.ui" çà peut toujours aider.
Autre "truc" à connaître : le blocage ou non de l'application à une seule instance ou autoriser des instances multiples ; dans mon cas j'interdis les instances multiples (le programme utilise des timers c'est trop dangereux). C'est le test suivant :
/* test for uniqueness */
Bon courage !

#include <libintl.h>
#include <locale.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <glib.h>
#include <glib/gstdio.h> /* g_fopen, etc */
#include <gtk/gtk.h>
#include "support.h"
#include "misc.h"
#include "files.h"
#include "interface.h"
#include "savestate.h"
#include "calendars.h"

/*********************************
  startup for a standard
  g_application

**********************************/

static void planlibre_startup (APP_data *data)
{

  /* we add directories ton find various ressources */
  add_pixmap_directory (PACKAGE_DATA_DIR "/pixmaps/" PACKAGE); /* New location for all pixmaps */
  add_pixmap_directory (PACKAGE_DATA_DIR "/pixmaps"); /* Gnome users /usr/share/pixmaps folder */  
  add_ui_directory (PACKAGE_DATA_DIR "/planlibre/ui" ); /* New location for all glade xml files */

}


/*********************************
  activation for a standard
  g_application

**********************************/
static void
planlibre_activate (GApplication *app, APP_data *data)
{
  GList *list;
  GKeyFile *keyString;
  GError *err = NULL; 
  gchar *filename, *summary;

  /* get datas from xml Glade file - CRITICAL : only in activate phase !!!! */
  data->builder =NULL;
  data->builder = gtk_builder_new ();

  /* load UI file */

  /* theming */
//g_object_set(gtk_settings_get_default(),
  //  "gtk-application-prefer-dark-theme", TRUE,
   // NULL);

  
  if(!gtk_builder_add_from_file (data->builder, find_ui_file ("main.ui"), &err)) {
     g_error_free (err);
     misc_halt_after_glade_failure (data);
  }

  list = gtk_application_get_windows (GTK_APPLICATION (app));
  /* test for uniqueness */
  if (list) {
      gtk_window_present (GTK_WINDOW (list->data));
  }
  else
    {
      planlibre_prepare_GUI (app, data);
      gtk_widget_show (data->appWindow);
    }
  /* now we get configuration stored datas */
  createGKeyFile (data, data->appWindow);/* reload */
  keyString = g_object_get_data (G_OBJECT(data->appWindow), "config");
  /* same for application */
  data->keystring = keyString;
  data->app = GTK_APPLICATION(app);

  /* default name for current project */

  keyString = g_object_get_data (G_OBJECT(data->appWindow), "config");
//  filename = g_strdup_printf ("%s.xml", _("noname_project"));
//filename = NULL;
  //summary = g_strdup_printf ("%s", _("No summary"));
//  summary = NULL;
//  store_current_file_in_keyfile (keyString, filename, summary);
//  g_free (summary);
//  g_free (filename);

  misc_display_app_status (FALSE, data);
  /* timeouts */
  misc_prepare_timeouts (data);
  /* calendars */
  calendars_init_main_calendar (data);
  /* dashboard */
  dashboard_init (data);

  /* prepare home page */
  home_set_app_logo (data);
  home_today_date (data);
  home_project_infos (data);
  home_project_tasks (data);
  home_project_milestones (data);
}

/**********************

  MAIN

***********************/

int main (int argc, char *argv[]) {
  GtkApplication *app;
  APP_data app_data;
  gint status;

  setlocale (LC_ALL, "");

  bindtextdomain (PACKAGE, LOCALEDIR);
  textdomain (PACKAGE);

  /* we parse datas from config file - we get the configuration file   */
  app_data.gConfigFile = g_build_filename (g_get_user_config_dir (), 
                       "/planlibre/", PLANLIBRE_CONFIG, NULL); /* Create hidden directory to store PlanLibre config datas */
  /* we check if the directory already exists */
  if(!g_file_test (app_data.gConfigFile, G_FILE_TEST_EXISTS)) {
     printf("* PlanLibre critical : config.ini file absent or corrupted ! *\n");
     /* we create the directory */
     gint i = g_mkdir (g_strdup_printf ("%s/planlibre/", g_get_user_config_dir ()), S_IRWXU);/* i's a macro from gstdio.h */
  }

  timeline_reset_store_date ();
  misc_init_vars (&app_data);
  /* g_application mechanism */
  app = gtk_application_new ("org.gtk.planlibre", 0);
  app_data.app = app;
  g_signal_connect (app, "startup", G_CALLBACK (planlibre_startup), &app_data);
  g_signal_connect (app, "activate", G_CALLBACK (planlibre_activate), &app_data);

  /* main loop */
  status = g_application_run (G_APPLICATION (app), argc, argv);

  g_object_unref (app_data.builder);
  g_object_unref (app);

  return status;
}

Hors ligne

#5 Le 20/01/2021, à 19:43

kevlar

Re : gtk+-3.0 un exemple que je ne comprends pas...

En résumé : une application, en démarrant, va chercher à provoquer deux événements :
- un événement "startup"
- un événement "activate".
Pour que çà marche, il faut donc que toi, programmeur, tu aies déclaré les deux fonctions d'appel vers ces deux événements, les fameuses "callbacks".
En ce qui concerne ces deux événements, celui qui est critique, c'est "activate".je te conseille donc d'étudier en détail les exemples fournis sur le site de Gnome, car le mien est un peu long bien qu'il soit facile de voir que je crée l'interface graphique au sein de la fonction callback qui répond à l'évenement "activate".

Hors ligne

#6 Le 20/01/2021, à 20:17

kamaris

Re : gtk+-3.0 un exemple que je ne comprends pas...

@DonutMan75 : tu peux consulter cette page de la doc en particulier : https://developer.gnome.org/gobject/sta … bject.html
Elle donne une assez bonne introduction à divers concepts autour de GObject, et contient en particulier une référence à la macro créant les fonctions *_get_type().

Hors ligne

#7 Le 20/01/2021, à 20:38

kamaris

Re : gtk+-3.0 un exemple que je ne comprends pas...

@kevlar : il y a des confusions dans ce que tu dis.
La macro G_DEFINE_TYPE() est liée à GObject, pas à GApplication, qui est simplement une classe parmi tant d'autres qui héritent de GObject. C'est donc sans lien avec la manière de « préparer la démarrage d'une "g_application" ».
Tu peux très bien instancier une GApplication sans en définir de sous-classe, auquel cas tu n'utiliseras pas cette macro, ce qui est d'ailleurs ce que tu fais dans l'exemple que tu donnes.

Par ailleurs, il n'est pas « recommandé d'abandonner le modèle "gtk_application" au profit du modèle "g_application" » à ma connaissance, d'ailleurs GtkApplication a bien survécu au passage de GTK 3 à GTK 4.
Et tu ne « sécurises » pas « une déclaration gtk_application […] par une macro G_APPLICATION » : il s'agit d'un cast, une conversion de type de GtkApplication vers GApplication, toujours permise car GtkApplication hérite de GApplication.
Cette macro G_APPLICATION() fait d'ailleurs partie des macros automatiquement définies lors de la création de la classe GApplication, qui hérite de GObject.

Hors ligne

#8 Le 20/01/2021, à 22:24

DonutMan75

Re : gtk+-3.0 un exemple que je ne comprends pas...

Bonsoir à tous,
merci beaucoup pour vos retours détaillés et précis !

En effet, abakkk a raison il y a bien une ligne en-dessous du #define mais je la pensais complètement déconnectée !

#define EXAMPLE_APP_TYPE (example_app_get_type ())
G_DECLARE_FINAL_TYPE (ExampleApp, example_app, EXAMPLE, APP, GtkApplication)

Bon, il me faut du temps pour digérer tout ça. On gagne vite en complexité par rapport au simple bouton "Hello World" du Getting Started ^^

Mes choix d'utiliser le langage C et la version gtk3 proviennent :
1- de mon envie de consolider mes bases en C
2- de regarder comment fonctionne le logiciel Rhythmbox (codé en C et avec gtk3)

Merci encore à vous pour vos éclaircissements !

D.

Hors ligne

#9 Le 20/01/2021, à 22:42

kamaris

Re : gtk+-3.0 un exemple que je ne comprends pas...

Il faut un moment avant de digérer toute la machinerie GLib/GTK en jeu dans l'écriture d'un tel logiciel.
Si j'ai un conseil à te donner, c'est de te trouver soit un bug à corriger, soit une petite fonctionnalité à ajouter, histoire de te donner une motivation et un truc précis à faire.
Ça limitera le champ de tes recherches dans le code dans un premier temps, et ça devrait aider à faire passer la pilule smile

Hors ligne

#10 Le 20/01/2021, à 23:39

DonutMan75

Re : gtk+-3.0 un exemple que je ne comprends pas...

Hello kamaris,
oui c'est justement ce que j'essaie de faire en fait ^^
J'avais dans l'idée d'essayer d'ajouter une option pour lire un morceau en boucle (chose qui n'existe pas car on ne peut que 1/ lire une play-list une fois ou 2/ lire une play-list en boucle).

En farfouillant j'ai bien vu qu'il existait des plugins Rhythmbox qui font ça (notamment en python et avec très peu de ligne de code !).
Mais je ne les ai pas regardé en détail pour ne pas être influencé ^^

Bon pour le moment, je suis resté sur l'exemple "simple" de la doc de gnome et j'essaie de faire cycler la couleur d'un bouton entre trois états... j'avance petit à petit...

D.

Hors ligne