hello la team Gtk

J'essaie de me familiariser avec la customisation des widgets.

J'ai travaillé un code avec diverses avancées liées aux évolutions de Glib, Gtk etc....
Et j'ai lu pas mal de doc

il me reste à résoudre probablement un dernier point au lancement je ne vois pas le dessin de la led mais si je clique sur le bouton elle apparait


voici les 3 codes en chantier et le meson.build correspondant

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
/* gtkled.h */
 
#ifndef __GTK_LED_H
#define __GTK_LED_H
 
#include <gtk/gtk.h>
#include <cairo.h>
 
G_BEGIN_DECLS
 
#define CB_TEST
 
 
G_DECLARE_FINAL_TYPE(GtkLed, gtk_led,GTK , LED , GtkWidget)
/** signification des paramètres
 * le préfixe GtkLed pour la classe GtkLedClass
 * gtk_led pour définir le type gtk_led_get_type()
 * le transtypage GTK_LED
 * l'ancêtre GtkWidget
 **/
 
 /* Type definition */
typedef struct _GtkLedPrivate GtkLedPrivate;
 
struct _GtkLed 
{
	GtkWidget parent;
 
	/*< Private >*/
	GtkLedPrivate *priv;
};
 
struct _GtkLedClass 
{
   GtkWidgetClass parent_class;
};
 
/* Public API */
gboolean gtk_led_get_state (GtkLed * led);
void gtk_led_set_state (GtkLed * led, gboolean state);
GtkWidget * gtk_led_new (const gchar * on_image,
                         const gchar * off_image,
                         gboolean state);
 
G_END_DECLS
 
#endif /* __GTK_LED_H */
puis

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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
#include "gtkled.h"
 
/* gtkled.c */
 
/* Private data structure */
struct _GtkLedPrivate 
{    
	const gchar * on_image;
	const gchar * off_image;
 
	GdkPixbuf * on_pixbuf;
	GdkPixbuf * off_pixbuf;
 
	gint width;
	gint height;
 
	gboolean state;
	GdkWindow *window;
};
enum {
  PROP_0,
  PROP_IMAGE_ON,
  PROP_IMAGE_OFF,
  PROP_STATE
};
 
/* Internal API */
static void gtk_led_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
static void gtk_led_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
static void gtk_led_class_init (GtkLedClass * klass);
static void gtk_led_init (GtkLed * led);
static void gtk_led_load_image (GtkLed * led);
static void gtk_led_size_request (GtkWidget * widget, GtkRequisition * requisition);
static void gtk_led_get_preferred_height (GtkWidget *widget, gint *minimal_height, gint *natural_height);
static void gtk_led_get_preferred_width (GtkWidget *widget, gint *minimal_width, gint *natural_width);
static void gtk_led_size_allocate (GtkWidget * widget, GtkAllocation * allocation);
static void gtk_led_realize (GtkWidget * widget);
static void gtk_led_paint (GtkWidget * widget);
static void gtk_led_finalize (GObject * object);
 
/* Define variable GTK_TYPE_LED in order to represent GType fonction */
#define GTK_TYPE_LED gtk_led_get_type()
/* Define type */
G_DEFINE_TYPE(GtkLed, gtk_led, GTK_TYPE_WIDGET)
/** signification des paramètres pour G_DEFINE_TYPE(GtkLed, gtk_led, GTK_TYPE_WIDGET)
 * le même préfixe GtkLed que pour la classe GtkLedClass
 * implementation de la fonction gtk_led_get_type avec un  protocole standard
 * define a parent class pointer accessible from the whole .c file
 **/
 
/* Initialization */
static void gtk_led_class_init (GtkLedClass * klass)
{
	GtkWidgetClass * widget_class;
	GObjectClass * object_class;
	GParamSpec *pspec;
	#ifdef CB_TEST
		g_print ("gtk_led_class_init\n");
	#endif
	widget_class = (GtkWidgetClass *) klass;
	object_class = (GObjectClass *) klass;
 
	/* Override widget class methods */
	object_class->set_property = gtk_led_set_property;
	object_class->get_property = gtk_led_get_property;
 
	widget_class->realize = gtk_led_realize;
	widget_class->get_preferred_width = gtk_led_get_preferred_width;
	widget_class->get_preferred_height = gtk_led_get_preferred_height;
 
	widget_class->size_allocate = gtk_led_size_allocate;
 
	object_class->finalize = gtk_led_finalize;
	/************************/
	pspec = g_param_spec_boolean ("state",
                                "State",
                                "True when the led is switched_on",
                                FALSE,
                                G_PARAM_READWRITE);           
	g_object_class_install_property (object_class, PROP_STATE, pspec);
	/************************/
	pspec = g_param_spec_string ("on-image",
                               "On-Image",
                               "Path for the led on image file",
                               "",
                               G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
	g_object_class_install_property (object_class, PROP_IMAGE_ON, pspec);
	/************************/
	pspec = g_param_spec_string ("off-image",
                               "Off-Image",
                               "Path for the led off image file",
                               "",
                               G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
	g_object_class_install_property (object_class, PROP_IMAGE_OFF, pspec);
 
	g_type_class_add_private (klass, sizeof(GtkLedPrivate));
 
	g_print ("\n gtk_led_class_init ligne SUCCESS %d\n", __LINE__);
}
 
static void gtk_led_init (GtkLed * led)
{
	#ifdef CB_TEST
		g_print ("gtk_led_init\n");
	#endif
	GtkLedPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE(led, GTK_TYPE_LED, GtkLedPrivate);
 
	gtk_widget_set_has_window(GTK_WIDGET(led), TRUE);
	priv->on_image = NULL;
	priv->off_image = NULL;
	priv->on_pixbuf = NULL;
	priv->off_pixbuf = NULL;
	priv->width = 0;
	priv->height =0;
	priv->state = FALSE;
	g_print ("dans gtk_led_init les tailles sont %d et %d \n",priv->width,priv->height);
 
	/* Create cache for faster access */
	led->priv = priv;
	g_print ("\n gtk_led_init ligne SUCCESS %d\n", __LINE__);
}
 
static void gtk_led_set_property (GObject           *object,
                      guint             prop_id,
                      const GValue      *value,
                      GParamSpec        *pspec)
{
	#ifdef CB_TEST
		g_print ("gtk_led_set_property\n");
	#endif
	GtkLed * led = GTK_LED (object);;
	switch (prop_id) {
		case PROP_STATE:
		  gtk_led_set_state (led, g_value_get_boolean(value));
		  break;
		case PROP_IMAGE_ON:
		  g_free (led->priv->on_image);
		  led->priv->on_image = g_value_dup_string (value);
		  break;
 
		case PROP_IMAGE_OFF:
		  g_free (led->priv->off_image);
		  led->priv->off_image = g_value_dup_string (value);
		  break;
		default:
		  G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
	}
}
 
static void gtk_led_get_property (GObject           *object,
                      guint             prop_id,
                      GValue            *value,
                      GParamSpec        *pspec)
{
	#ifdef CB_TEST
		g_print ("gtk_led_get_property\n");
	#endif
	GtkLed * led = GTK_LED (object);
	switch (prop_id) {
		case PROP_STATE:
		  g_value_set_boolean (value, led->priv->state);
		  break;
 
		case PROP_IMAGE_ON:
		  g_value_set_string (value, led->priv->on_image);
		  break;
 
		case PROP_IMAGE_OFF:
		  g_value_set_string (value, led->priv->off_image);
		  break;
 
		default:
		  G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
  }
}
gboolean gtk_led_get_state (GtkLed * led)
{
	g_return_val_if_fail(GTK_LED(led), 0);
	#ifdef CB_TEST
		g_print ("gtk_led_get_state\n");
	#endif
	g_print ("gtk_led_get_state Etat=%d (1 = ON 0=OFF)\n",led->priv->state);
	g_print ("\n gtk_led_get_state ligne ok %d\n", __LINE__);
	return (led->priv->state);
}
 
void gtk_led_set_state (GtkLed * led, gboolean state)
{
	#ifdef CB_TEST
		g_print ("gtk_led_set_state\n");
	#endif
   led->priv->state = state;
   gtk_led_paint (GTK_WIDGET (led));
   g_print ("\n gtk_led_set_state ligne ok %d\n", __LINE__);
}
 
GtkWidget * gtk_led_new (const gchar * on_image,
						 const gchar * off_image,
						 gboolean state)
{
	GtkLed * led = NULL;
	#ifdef CB_TEST
		g_print ("gtk_led_new\n");
	#endif
	if (on_image != NULL && off_image != NULL) 
	{
		// la taille de la zone led n'est pas allouée donc il manque quelque chose
		led = g_object_new (GTK_TYPE_LED,
                       "state", state,
                       "on-image", on_image,
                       "off-image", off_image,
                       NULL);
		gtk_led_load_image (led);
		g_print ("\n gtk_led_new ligne SUCCESS %d\n", __LINE__);
		return GTK_WIDGET (led);
	}
	g_print ("\n gtk_led_new ligne FATAL ERROR %d\n", __LINE__);
	return GTK_WIDGET (led);
}
 
static void gtk_led_get_preferred_width (GtkWidget *widget, gint *minimal_width, gint *natural_width)
{
	/** la fonction établit une largeur   compatible avec le fichier image   **/
	g_return_if_fail (widget != NULL);
	g_return_if_fail (GTK_LED (widget));
	#ifdef CB_TEST
		g_print ("gtk_led_get_preferred_width\n");
	#endif
	GtkRequisition requisition;
 
	gtk_led_size_request (widget, &requisition);
	*minimal_width = *natural_width = requisition.width;
	g_print ("dans gtk_led_get_preferred_width les tailles sont %d  \n",requisition.width);
	g_print ("\n gtk_led_get_preferred_width ligne ok %d\n", __LINE__);
}
 
static void gtk_led_get_preferred_height (GtkWidget *widget, gint *minimal_height, gint *natural_height)
{
	/** la fonction établit une hauteur  compatible avec le fichier image**/
	g_return_if_fail (widget != NULL);
	g_return_if_fail (GTK_LED (widget));
	#ifdef CB_TEST
		g_print ("gtk_led_get_preferred_height\n");
	#endif
	GtkRequisition requisition;
 
	gtk_led_size_request (widget, &requisition);
	*minimal_height = *natural_height = requisition.height;
	g_print ("dans gtk_led_get_preferred_height les tailles sont %d  \n",requisition.height);
	g_print ("\n gtk_led_get_preferred_height ligne ok %d\n", __LINE__);
}
 
static void gtk_led_size_request (GtkWidget * widget, GtkRequisition * requisition)
{
	/** nous stockons la taille préférée de notre widget, cette fonction ne sert qu'a cela
         * mais requisition sera par la suite consulté **/
	g_return_if_fail (widget != NULL);
	g_return_if_fail (GTK_LED (widget));
	#ifdef CB_TEST
		g_print ("gtk_led_size_request\n");
	#endif	
 
	GtkLedPrivate *priv = GTK_LED(widget)->priv;
	requisition->width = priv->width;
	requisition->height = priv->height;
	g_print ("dans gtk_led_size_request les tailles sont %d et %d \n",priv->width,priv->height);
	g_print ("\n gtk_led_size_request ligne ok %d\n", __LINE__);
}
 
void gtk_led_load_image (GtkLed * led)
{
	#ifdef CB_TEST
		g_print ("gtk_led_load_image\n");
	#endif
	GtkLedPrivate *priv = led->priv;
	priv->on_pixbuf = gdk_pixbuf_new_from_file (priv->on_image, NULL);
	priv->off_pixbuf = gdk_pixbuf_new_from_file (priv->off_image, NULL);
	/** c'est ici que ces paramètres son initialisé avec la taille des pixbuf **/
	priv->width = gdk_pixbuf_get_width (priv->on_pixbuf);
	priv->height = gdk_pixbuf_get_height (priv->on_pixbuf);
	g_print ("dans gtk_led_load_image les tailles sont %d et %d \n",priv->width,priv->height);
	g_print ("\n gtk_led_load_image ligne ok %d\n", __LINE__);
}
 
static void gtk_led_size_allocate (GtkWidget * widget, GtkAllocation * allocation)
{
	/** Cette fonction sera appelée par le conteneur dans lequel se trouvera notre widget,
         * une fois que les contraintes qui sont imposées au conteneur sont fixées, 
         * ça permet au conteneur de redimensionner au mieux notre widget gtkled,
         * d'après le résultat obtenu dans le second argument de la fonction avec
         * gtk_widget_set_allocation(widget, allocation);
         * puis nous lançons la demande de déplacement, et re-dimensionnement, 
         * avec l'appel à gdk_window_move_resize.
         * C'est un protocole qu'on retrouve dans les divers exemples  **/ 
	g_return_if_fail (widget != NULL);
	g_return_if_fail (GTK_LED (widget));
	#ifdef CB_TEST
		g_print ("gtk_led_size_allocate\n");
	#endif
	GtkLedPrivate *priv = GTK_LED(widget)->priv;
 
	gtk_widget_set_allocation(widget, allocation);
 
	if (gtk_widget_get_realized(widget)) 
	{
		g_print ("\n gtk_led_size_allocate ligne GOOOOOOOOOOOOOD %d\n", __LINE__);
		g_print ("dans gtk_led_size_allocate les tailles private sont %d et %d \n",priv->width,priv->height);
		g_print ("dans gtk_led_size_allocate les tailles allocation sont %d et %d \n",allocation->width,allocation->height);
		gdk_window_move_resize (priv->window, 
								allocation->x, 
								allocation->y, 
								priv->width, priv->height);
	}
	else
		g_print ("\n gtk_led_size_allocate ligne BAAAAAAD  %d\n", __LINE__);
	g_print ("\n gtk_led_size_allocate ligne ok %d\n", __LINE__);
}
 
static void gtk_led_realize (GtkWidget * widget)
{
	/** cette fonction est au coeur du dispositif c'est ici que la fenêtre est créé
         * avec les bonnes dimensions
         **/
	g_return_if_fail (widget != NULL);
	g_return_if_fail (GTK_LED (widget));
	#ifdef CB_TEST
		g_print ("gtk_led_realize\n");
	#endif
	GtkLedPrivate *priv = GTK_LED(widget)->priv;
	GdkWindowAttr attributes;
	guint attributes_mask;
	GtkAllocation allocation;
 
	gtk_widget_set_realized(widget, TRUE);
 
	gtk_widget_get_allocation(widget, &allocation);
 
	attributes.window_type = GDK_WINDOW_CHILD;
	attributes.x = allocation.x;
	attributes.y = allocation.y;
	attributes.width = allocation.width;
	attributes.height = allocation.height;
	attributes.wclass = GDK_INPUT_OUTPUT;
	attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
 
	attributes_mask = GDK_WA_X | GDK_WA_Y;
 
	priv->window = gdk_window_new (
	  gtk_widget_get_parent_window (widget),
	  & attributes, attributes_mask);
 
	gdk_window_set_user_data (priv->window, widget);
	gtk_widget_set_window(widget, priv->window);
 
	g_print ("\n gtk_led_realize ligne ok %d\n", __LINE__);
}
 
static void gtk_led_paint (GtkWidget * widget)
{
	g_return_if_fail (widget != NULL);
	g_return_if_fail (GTK_LED (widget));
	GdkPixbuf * pixbuf = NULL;
	gint center_x = 0;
	gint center_y = 0;
 
	GtkAllocation allocation;
	gtk_widget_get_allocation(widget, &allocation);
	GtkLedPrivate *priv = GTK_LED(widget)->priv;
 
	if (gtk_widget_get_realized (widget)) 
	{
		center_x = (allocation.width / 2) - (priv->width / 2);
		center_y = (allocation.height / 2) - (priv->height / 2);
 
		if (priv->state)
			pixbuf = priv->on_pixbuf;
		else
			pixbuf = priv->off_pixbuf;
		cairo_t *cr = gdk_cairo_create (priv->window);
		gdk_cairo_set_source_pixbuf (cr, pixbuf, center_x, center_y);
		cairo_paint (cr);
		cairo_destroy (cr);
	}
}
 
static void gtk_led_finalize (GObject * object)
{
	// Destruction des données privées si nécessaire
	GtkLed * led;
	GtkLedPrivate *priv;
	#ifdef CB_TEST
		g_print ("gtk_led_finalize\n");
	#endif
	led = GTK_LED (object);
	priv = G_TYPE_INSTANCE_GET_PRIVATE(led, GTK_TYPE_LED, GtkLedPrivate);
 
	if (priv->on_pixbuf != NULL && priv->off_pixbuf != NULL) 
	{
		g_object_unref (priv->on_pixbuf);
		g_object_unref (priv->off_pixbuf);
		priv->on_pixbuf = NULL;
		priv->off_pixbuf = NULL;
	}
	g_print ("\n gtk_led_finalize ligne ok %d\n", __LINE__);
}
pour finir le code test
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
#include <stdio.h>
//#include <stdlib.h>
#include <gtk/gtk.h>
 
#include "gtkled.h"
 
static void cb_switch (GtkWidget * widget, gpointer data)
{
	#ifdef CB_TEST
		g_print ("cb_switch\n");
	#endif
   GtkWidget * led = (GtkWidget *) data;
   gtk_led_set_state (GTK_LED (led), ! gtk_led_get_state (GTK_LED (led)));
   g_print ("\n cb_switch ligne SUCCESS %d\n", __LINE__);
}
 
int main (int argc, char ** argv)
{
	GtkWidget * window;
	GtkWidget * hbox;
	GtkWidget * button;
	GtkWidget * led = NULL;
 
	gtk_init (& argc, & argv);
	/*
	* Creation de la fenetre principale et ajout d'un container.
	*/
	window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
	gtk_window_set_title (GTK_WINDOW (window), "Test de GtkLed");
	gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER);
	gtk_window_set_default_size (GTK_WINDOW (window), 250, 50);
 
	g_signal_connect (window,"destroy",G_CALLBACK (gtk_main_quit),NULL);
 
	hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
 
	gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
	gtk_container_add (GTK_CONTAINER (window), hbox);
	/*
	* Creation d'un bouton et d'un GtkLed.
	*/
	button = gtk_button_new_with_label ("Switch led state");
	gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
 
	led = gtk_led_new ("led_on.png", "led_off.png", TRUE);
 
	if (led !=NULL) 
	{
		gtk_box_pack_start (GTK_BOX (hbox), led, TRUE, TRUE, 0);
		g_signal_connect (button, "clicked",G_CALLBACK (cb_switch),(gpointer) led);
	} 
	else
		printf ("Impossible de créer le widget GtkLed !\n");
	gtk_widget_show_all (window);
	gtk_main ();
	return EXIT_SUCCESS;
}
le meson.build

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
project('gtkled', 'c')
gtkdep = dependency('gtk+-3.0')
scr= [ 'gtkled.h','main.c','gtkled.c']
executable('gtkled', scr, dependencies : gtkdep)
Je me suis inspiré de ce tuto
https://franckh.developpez.com/tutor...eation-widget/


Comme indiqué plus haut je ne comprend pas pourquoi la led n'est pas affichée au lancement du programme test et affiché ensuite si on clique sur le bouton.

Si un expert GTK peut m'expliquer ce qui manque je l'en remercie d'avance.