Draw event function not getting executed

Please refer to the snippet below.

//gcc `pkg-config --cflags --libs gtk4` multiple_graphs.c -lcairo -lgtk-4 -lglib-2.0 -lgio-2.0 -lgobject-2.0 && ./a.out

#include<gtk/gtk.h>

const int graph_height = 200;
const int graph_width = 300;
const int num_of_graphs = 3;

struct node
{
	int position;
	int execute_count;
	GtkWidget *button;
	GtkWidget *box;
	GtkWidget *drawing_area;
	cairo_surface_t *surface;
	cairo_t *cr;
};

void on_draw_event( GtkDrawingArea *drawing_area, cairo_t *cr, int width, int height, gpointer param )
{
	struct node * const param_node = param;
	const GdkRGBA rgba =
	{
		.red   = ((float)(random()%101))/100,
		.green = ((float)(random()%101))/100,
		.blue  = ((float)(random()%101))/100,
		.alpha = 1,
	};

	const int x1 = random()%width;
	const int x2 = random()%width;
	const int y1 = random()%height;
	const int y2 = random()%height;
	gdk_cairo_set_source_rgba( param_node->cr, &rgba );
	cairo_move_to( param_node->cr, x1, y1 );
	cairo_line_to( param_node->cr, x2, y2 );
	cairo_stroke( param_node->cr );
	cairo_set_source_surface( cr, param_node->surface, 0, 0 );
	cairo_paint( cr );
	param_node->execute_count++;
}

gboolean draw_graphs( gpointer param )
{
	struct node *all_nodes = param;
	for( int i=0; i<num_of_graphs; i++ )
	{
		gtk_widget_queue_draw( all_nodes[i].drawing_area );
	}
	return G_SOURCE_CONTINUE;
}

struct node * prv_node;

static gboolean button_clicked( GtkButton *button, gpointer param )
{
	struct node * const param_node = param;
	gtk_widget_set_visible( prv_node->box, false );
	prv_node = param_node;
	gtk_widget_set_visible( param_node->box, true );
	return G_SOURCE_CONTINUE;
}

static gboolean close_request_received( GtkWindow *main_window, gpointer param )
{
	struct node *all_nodes = param;
	for( int i=0; i<num_of_graphs; i++ )
	{
		printf( "Graph %d count: %d\n", i, all_nodes[i].execute_count );
	}
	gtk_window_destroy( main_window );
}

static void activate( GtkApplication *app, gpointer argv )
{
	GtkWidget *main_window = gtk_application_window_new( app );
	GtkWidget *main_vbox = gtk_box_new( GTK_ORIENTATION_VERTICAL, 5 );
	gtk_window_set_child( (GtkWindow*)main_window, main_vbox );
	GtkWidget *button_hbox = gtk_box_new( GTK_ORIENTATION_HORIZONTAL, 5 );
	gtk_box_append( (GtkBox*)main_vbox, button_hbox );
	struct node *all_nodes = calloc( sizeof(struct node), num_of_graphs );
	if( g_signal_connect( main_window, "close-request", G_CALLBACK(close_request_received), all_nodes ) <= 0 )
	{
		fprintf( stderr, "%s %d\n", __func__, __LINE__ );
		exit( EXIT_FAILURE );
	}
	char button_name[20];
	for( int i=0; i<num_of_graphs; i++ )
	{
		all_nodes[i].position = i;
		sprintf( button_name, "Graph %d", i );
		all_nodes[i].button = gtk_button_new_with_label( button_name );
		gtk_box_append( (GtkBox*)button_hbox, all_nodes[i].button );
		if( g_signal_connect( G_OBJECT(all_nodes[i].button), "clicked", G_CALLBACK( button_clicked ), &all_nodes[i] ) <= 0 )
		{
			fprintf( stderr, "%s %d\n", __func__, __LINE__ );
			exit( EXIT_FAILURE );
		}
		all_nodes[i].box = gtk_box_new( GTK_ORIENTATION_VERTICAL, 5 );
		all_nodes[i].drawing_area = gtk_drawing_area_new();
		gtk_box_append( (GtkBox*)all_nodes[i].box, all_nodes[i].drawing_area );
		gtk_box_append( (GtkBox*)main_vbox, all_nodes[i].box );
		gtk_widget_set_size_request( all_nodes[i].drawing_area, graph_width, graph_height );
		all_nodes[i].surface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, graph_width, graph_height );
		all_nodes[i].cr = cairo_create( all_nodes[i].surface );
		gtk_drawing_area_set_draw_func( (GtkDrawingArea*)all_nodes[i].drawing_area, on_draw_event, &all_nodes[i], NULL );
	}
	prv_node = &all_nodes[0];
	gtk_widget_set_visible( main_window, true );
	for( int i=0; i<num_of_graphs; i++ )
	{
		gtk_widget_set_visible( all_nodes[i].box, false );
	}
	gtk_widget_set_visible( prv_node->box, true );
	g_timeout_add_seconds( 5, draw_graphs, all_nodes );
}

int main( const int argc, char * argv[] )
{
	GtkApplication * const app = gtk_application_new( "TrueTraffik.Gui", 0 );
	if( g_signal_connect( app, "activate", G_CALLBACK( activate ), argv ) <= 0 )
	{
		fprintf( stderr, "%s %d\n", __func__, __LINE__ );
		exit( EXIT_FAILURE );
	}
	const int status = g_application_run( G_APPLICATION( app ), 0, NULL );
	g_object_unref( app );

	return status;
}

result I am seeing after closing the window is

Graph 0 count: 3
Graph 1 count: 2
Graph 2 count: 1

Because of certain constraints, I can display only one graph at any given time.
May be because of this reason, on_draw_event function is being executed only if visibility is true.

Would like to understand if there is a way to ensure the execution of on_draw_event irrespective of visibility status.

Hi,

as far as I know, the draw callback won’t be called if the widget is hidden, or the window minimized, etc…

If you need to perform some actions other than drawing at specific times, then don’t rely on the draw callback, and use a g_timeout_add instead (or a tick callback for e.g. fast animations).