GTK4: Handle mouse events and log to a textview

2023-10-14

Description

This application catches mouse signals and logs them in a GtkTextView:

Type ESCAPE to close the window.


Source code

main.c

#include <gtk/gtk.h>
//
// Variables
//
static GtkWidget* textview = NULL;
static GtkTextBuffer* buffer = NULL;
//
// Logs output to textview and adds line break.
//
static void log_line(const char* text) {
	GtkTextIter iter;
	gtk_text_buffer_get_end_iter(buffer, &iter);
	gtk_text_buffer_insert(buffer, &iter, g_strdup_printf("%s\n", text), -1);
	//
	// autoscroll
	//
	gtk_text_buffer_get_end_iter(buffer, &iter);
	GtkTextMark* mark = gtk_text_buffer_create_mark(buffer, "mark", &iter, TRUE);
	gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(textview), mark, 0.0, TRUE, 0, 0);
}
//
/// Is called when the mouse cursor enters the label.
//
static void mouse_enter(GtkWidget* label, gdouble x, gdouble y, gpointer user_data) {
	const char* text = g_strdup_printf("Enter - x: %f y: %f", x, y);
	gtk_label_set_text(GTK_LABEL(label), text);
	log_line(text);
}
//
/// Is called when the mouse cursor leaves the label.
//
static void mouse_leave(GtkWidget* label, gpointer user_data) {
	const char* text = g_strdup_printf("Leave");
	gtk_label_set_text(GTK_LABEL(label), text);
	log_line(text);
}
//
// Is called when the mouse cursor moves above the label.
//
static void mouse_motion(GtkWidget* label, gdouble x, gdouble y, gpointer user_data) {
	const char* text = g_strdup_printf("Motion - x: %f y: %f", x, y);
	gtk_label_set_text(GTK_LABEL(label), text);
	log_line(text);
}
//
// Is called when a key is pressed while the main application window has focus.
//
static gboolean key_pressed(GtkWidget* window, guint keyval, guint keycode, GdkModifierType state, gpointer user_data) {
	const char* text = g_strdup_printf("key_pressed - keyval: %d keycode: %d", keyval, keycode);
	g_print(g_strdup_printf("%s\n", text));
	if (keyval == GDK_KEY_Escape) {
		g_print(g_strdup_printf("Good bye world.\n"));
		gtk_window_destroy(GTK_WINDOW(window));
	}
	return TRUE;
}
//
// Is called when the main application window is activated.
//
static void activate(GtkApplication* app) {
	//
	// Initialize window and signals
	//
	GtkWindow* window = GTK_WINDOW(gtk_application_window_new(app));
	{
		gtk_window_set_default_size(window, 600, 480);
		GtkEventController* event_controller = gtk_event_controller_key_new();
		g_signal_connect_object(event_controller, "key-pressed", G_CALLBACK(key_pressed), window, G_CONNECT_SWAPPED);
		gtk_widget_add_controller(GTK_WIDGET(window), event_controller);
	}
	//
	// Initialize label and signals
	//
	GtkWidget* label = gtk_label_new("Hello world!");
	{
		gtk_widget_set_size_request(label, 600, 240);
		GtkEventController* motion_controller = gtk_event_controller_motion_new();
		g_signal_connect_object(motion_controller, "enter", G_CALLBACK(mouse_enter), label, G_CONNECT_SWAPPED);
		g_signal_connect_object(motion_controller, "leave", G_CALLBACK(mouse_leave), label, G_CONNECT_SWAPPED);
		g_signal_connect_object(motion_controller, "motion", G_CALLBACK(mouse_motion), label, G_CONNECT_SWAPPED);
		gtk_widget_add_controller(GTK_WIDGET(label), motion_controller);
	}
	//
	// Initialize scrolled window for textview
	//	
	GtkWidget* scrolledwindow = gtk_scrolled_window_new();
	{
		gtk_scrolled_window_set_max_content_height(GTK_SCROLLED_WINDOW(scrolledwindow), 240);
		gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwindow), GTK_POLICY_ALWAYS, GTK_POLICY_ALWAYS);
		//
		// Initialize textview and buffer
		//
		textview = gtk_text_view_new();	
		gtk_widget_set_size_request(scrolledwindow, 600,240);
		buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview));
		gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scrolledwindow), textview);
	}
	//
	// Initialize grid
	//
	{
		GtkWidget* grid = gtk_grid_new();
		gtk_grid_attach(GTK_GRID(grid), label, 0, 0, 1, 1);
		gtk_grid_attach(GTK_GRID(grid), scrolledwindow, 0, 1, 1, 1);
		gtk_window_set_child(window, grid);
	}
	gtk_window_present(window);
}
//
// Main function.
//
int main(int argc, char* argv[]) {
	g_autoptr(GtkApplication) app = gtk_application_new(NULL, 0);
	g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
	return g_application_run(G_APPLICATION(app), argc, argv);
}


Compiling

Compile with:

cc $(pkg-config --cflags gtk4) main.c $(pkg-config --libs gtk4)


Executing

Execute program with:

./a.out


Lessons learned:

← Home