Reputation: 21
I am trying to build a GUI application for an activity monitor in C, and decided to use GTK library along with Glade to help with the design. (Using Ubuntu 20.04)
Upon pressing the button, values are displayed in the respective positions and are updated upon every click. The only problem is I need it to update by itself in real-time, so I shifted the code into an infinite loop with sleep(1), so it updates them after every 1 second. But values are not even being displayed on the GUI now. To test if the code is even being executed, I tried printing values on the console from different parts of the code, and they are indeed being printed.
Things I've tried, but didn't work:
I think it has to do with the button trigger, and output is only updated on the GUI after the callback function is executed (from my observation with console prints). So I am trying to have the button programmatically pressed in intervals, to avoid having to click it myself every time, but could not find much on the topic.
If you can think of any way to make this work or an alternative to the approach I am taking, kindly help out. The main idea is that the output GUI should have values updated in real-time, regardless of the button.
Thanks in advance!
This is the function used to print out the values on the GUI:
struct timespec tm;
tm.tv_sec = 0;
tm.tv_nsec = 1000 * 1000 * 1000;
myproc_t* myprocs = NULL;
unsigned int myprocs_len = 0;
//call to function that will return the processes and their specifications
sample_processes(&myprocs, &myprocs_len, tm);
if(s == 0){
// sort by CPU usage
qsort(myprocs, myprocs_len, sizeof(myprocs[0]), myproc_comp_pcpu);
}
else if(s == 1){
// sort by Memory usage
qsort(myprocs, myprocs_len, sizeof(myprocs[0]), myproc_comp_rss);
}
for (i = 0; i < myprocs_len && i < 5; i++)
{
if (strlen(myprocs[i].cmd) == 0) {
break;
}
//convert specs read from /proc file to string format
sprintf(pid, "%d", myprocs[i].tid);
sprintf(cpu, "%.2f",myprocs[i].pcpu);
sprintf(memory, "%lu", myprocs[i].vm_rss/1000);
sprintf(cmd, "%s", myprocs[i].cmd);
switch(i)
{
case 0:
gtk_label_set_text(GTK_LABEL(PID1), pid);
gtk_label_set_text(GTK_LABEL(CPU1), cpu);
gtk_label_set_text(GTK_LABEL(MEM1), memory);
gtk_label_set_text(GTK_LABEL(CMD1), cmd);
case 1:
gtk_label_set_text(GTK_LABEL(PID2), pid);
gtk_label_set_text(GTK_LABEL(CPU2), cpu);
gtk_label_set_text(GTK_LABEL(MEM2), memory);
gtk_label_set_text(GTK_LABEL(CMD2), cmd);
case 2:
gtk_label_set_text(GTK_LABEL(PID3), pid);
gtk_label_set_text(GTK_LABEL(CPU3), cpu);
gtk_label_set_text(GTK_LABEL(MEM3), memory);
gtk_label_set_text(GTK_LABEL(CMD3), cmd);
case 3:
gtk_label_set_text(GTK_LABEL(PID4), pid);
gtk_label_set_text(GTK_LABEL(CPU4), cpu);
gtk_label_set_text(GTK_LABEL(MEM4), memory);
gtk_label_set_text(GTK_LABEL(CMD4), cmd);
case 4:
gtk_label_set_text(GTK_LABEL(PID5), pid);
gtk_label_set_text(GTK_LABEL(CPU5), cpu);
gtk_label_set_text(GTK_LABEL(MEM5), memory);
gtk_label_set_text(GTK_LABEL(CMD5), cmd);
}
}
Upvotes: 1
Views: 296
Reputation: 7434
To expand on what @nielsdg correctly said, UI code based on event loop (such as GTK) must limit the blocking code to the bare minimum.
/* Never do this: it will freeze the UI */
static void
on_button_clicked()
{
do {
/* Your code here */
sleep(1);
while (condition);
}
Instead, unroll your code and leverage the main event loop:
static gboolean
iteration(gpointer user_data)
{
/* Your code here */
return condition ? G_SOURCE_CONTINUE : G_SOURCE_REMOVE;
}
static void
on_button_clicked()
{
g_timeout_add(1000, iteration, NULL);
}
This just gives you the main idea. The code above has some problems, above all if you click twice it will happily start two cooperative loops.
Upvotes: 0
Reputation: 2733
Using a loop with sleep(1)
or anything that blocks is always a no-go, since that means you're effectively blocking the UI thread from doing any actual work. The normal workflow is the following:
gtk_main()
or gtk_application_new()
and connecting to the "activate" signal (which will be called when you call gtk_application_run()
).gtk_widget_show()
and friendsg_timeout_add_seconds ()
. In the callback you can call gtk_label_set_text()
on the labels you created in the previous step. As long as the callback returns G_SOURCE_CONTINUE
, the callback will keep being called periodically at the specified intervalUpvotes: 1