I am trying to make a virtual LED using GTK3. I am not familiar with GUI programming. I don't know if my approach is correct. Anyway this is what I have done so far:
// gcc ledgui.c `pkg-config --cflags gtk+-3.0 pkg-config --libs gtk+-3.0`
#include <stdint.h>
#include <stdbool.h>
#include <gtk/gtk.h>
#define LED_COLOR_RED 0
#define LED_COLOR_GREEN 1
#define LED_COLOR_YELLOW 2
#define LED_COLOR_OFF 3
#define LED_COLOR_COUNT 4
static GtkTextBuffer *buffer;
GtkTextTag *tagLed[LED_COLOR_COUNT];
uint8_t ledColorData[] = {0,0};
static void activate (GtkApplication* app, gpointer user_data);
static void SetGuiLedColor(int id, GtkTextTag *tag);
static void SetLedColorTags();
void Task_sleep_ms(int ms);
int main()
{
GtkApplication *app;
int status;
app = gtk_application_new("org.gtk.example", G_APPLICATION_FLAGS_NONE);
g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
SetGuiLedColor(0, tagLed[LED_COLOR_RED]);
// Task_sleep_ms(500);
// SetGuiLedColor(0, tagLed[LED_COLOR_GREEN]);
// Task_sleep_ms(500);
status = g_application_run(G_APPLICATION(app), 0, NULL);
g_object_unref(app);
}
static void activate (GtkApplication* app, gpointer user_data)
{
GtkWidget *window;
window = gtk_application_window_new(app);
gtk_window_set_title(GTK_WINDOW(window), "LED");
gtk_window_set_default_size(GTK_WINDOW(window), 200, 50);
GtkWidget *view;
GtkCssProvider *provider;
GtkStyleContext *context;
view = gtk_text_view_new();
gtk_container_add (GTK_CONTAINER (window), view);
gtk_widget_set_name (view, "led1");
buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(view));
gtk_text_buffer_set_text(buffer, "1 2 3 4\no o o o", -1);
/* Change default font and color throughout the widget */
provider = gtk_css_provider_new();
gtk_css_provider_load_from_data(provider,
"* {"
" color: white;"
" background-color: black;"
" font: 20 monospace;"
"}",
-1,
NULL);
context = gtk_widget_get_style_context(view);
gtk_style_context_add_provider(context,
GTK_STYLE_PROVIDER(provider),
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
/* Change left margin throughout the widget */
gtk_text_view_set_left_margin (GTK_TEXT_VIEW (view), 40);
gtk_text_view_set_top_margin (GTK_TEXT_VIEW (view), 2);
SetLedColorTags();
// g_print ("Hello World\n");
SetGuiLedColor(0, tagLed[LED_COLOR_YELLOW]);
gtk_widget_show_all(window);
}
static void SetLedColorTags()
{
int i;
char *color[] = {"red", "green", "yellow", "black"};
/* Use a tag to change the color for just one part of the widget */
if (buffer == NULL)
{
printf("Error!! buffer is NULL\n");
return;
}
for (i=0; i<LED_COLOR_COUNT; i++)
{
tagLed[i] = gtk_text_buffer_create_tag (buffer, color[i] /*tag name*/,
"foreground", color[i], NULL);
}
}
static void SetGuiLedColor(int id, GtkTextTag *tag)
{
GtkTextIter start, end;
int idStart, idEnd;
idStart = id*2+8;
idEnd = idStart+1;
g_print ("LED color %p\n", tag);
gtk_text_buffer_get_iter_at_offset (buffer, &start, idStart);
gtk_text_buffer_get_iter_at_offset (buffer, &end, idEnd);
gtk_text_buffer_apply_tag (buffer, tag, &start, &end);
}
void Task_sleep_ms(int ms)
{
printf("sleep %d ms\n", ms);
usleep(ms * 1000);
}
I call the SetGuiLedColor
function 3 times.
When I run the code it only displays YELLOW. But I hope it displays YELLOW, RED and then GREEN sequentially.
How can I do it?
From the Alexander's advice, I have updated the code to thread-safe.
// gcc ledgui.c `pkg-config --cflags gtk+-3.0 pkg-config --libs gtk+-3.0`
#include <gtk/gtk.h>
#include <string.h>
#include <stdlib.h>
#define LED_COLOR_RED 0
#define LED_COLOR_GREEN 1
#define LED_COLOR_YELLOW 2
#define LED_COLOR_OFF 3
#define LED_COLOR_COUNT 4
char *color[] = {"red", "green", "yellow", "black"};
GtkWidget *ledLight;
GMutex mutex;
gchar ledText[256];
void *LedControllerTask (void *vargp);
void *LedGuiThread (void *vargp);
void SetFontColors(GtkWidget *grid);
gboolean updateLabel(gpointer data);
void Task_sleep_ms(int ms);
void SetTextColor(char* fcolor);
int main()
{
pthread_t thread_id;
pthread_t thread_id2;
pthread_create(&thread_id2, NULL, LedControllerTask, NULL);
pthread_create(&thread_id, NULL, LedGuiThread, NULL);
{
Task_sleep_ms(1000);
while (1)
{
Task_sleep_ms(100);
SetTextColor(color[LED_COLOR_GREEN]);
g_idle_add(updateLabel, ledLight);
Task_sleep_ms(100);
SetTextColor(color[LED_COLOR_OFF]);
g_idle_add(updateLabel, ledLight);
}
}
pthread_join(thread_id2, NULL);
pthread_join(thread_id, NULL);
exit(0);
}
void *LedControllerTask (void *vargp)
{
Task_sleep_ms(1000);
while (1)
{
Task_sleep_ms(100);
SetTextColor(color[LED_COLOR_RED]);
g_idle_add(updateLabel, ledLight);
Task_sleep_ms(100);
SetTextColor(color[LED_COLOR_OFF]);
g_idle_add(updateLabel, ledLight);
}
}
void *LedGuiThread (void *vargp)
{
GtkWidget *window;
GtkWidget *grid;
GtkWidget *ledLabel;
int argc=0;
char **argv=NULL;
gtk_init (&argc,&argv);
//Declarations
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window), "LED");
grid = gtk_grid_new ();
SetFontColors(grid);
ledLabel = gtk_label_new ("1");
ledLight = gtk_label_new ("O");
//Set Properties
gtk_container_set_border_width (GTK_CONTAINER(window), 20);
gtk_widget_set_size_request (GTK_WIDGET(window), 200, 50);
gtk_grid_set_row_spacing (GTK_GRID(grid), 4);
gtk_grid_set_column_spacing (GTK_GRID(grid), 4);
gtk_container_add (GTK_CONTAINER(window), grid);
//Fill the grid with shit (x, y, h, v)
gtk_grid_attach (GTK_GRID(grid), ledLabel, 2, 2, 2, 1);
gtk_grid_attach (GTK_GRID(grid), ledLight, 2, 3, 2, 1);
gtk_widget_show_all (window);
g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);
gtk_main();
}
void SetFontColors(GtkWidget *grid)
{
GtkCssProvider *provider;
GtkStyleContext *context;
/* Change default font and color throughout the widget */
provider = gtk_css_provider_new();
gtk_css_provider_load_from_data(provider,
"* {"
" color: white;"
" background-color: black;"
" font: 20px monospace;"
"}",
-1,
NULL);
context = gtk_widget_get_style_context(grid);
gtk_style_context_add_provider(context,
GTK_STYLE_PROVIDER(provider),
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
}
gboolean updateLabel(gpointer data)
{
char text[256];
GtkLabel *led = data;
g_mutex_lock (&mutex);
strncpy(text, ledText, sizeof(text));
g_mutex_unlock (&mutex);
gtk_label_set_markup (GTK_LABEL (led), text);
}
void Task_sleep_ms(int ms)
{
// printf("sleep %d ms\n", ms);
usleep(ms * 1000);
}
void SetTextColor(char* fcolor)
{
g_mutex_lock(&mutex);
snprintf(ledText, 256, "<span background=\"black\" foreground=\"%s\">O</span>", fcolor);
g_mutex_unlock(&mutex);
}
Thanks David!. I have updated the code. It looks much better.
// gcc ledgui.c `pkg-config --cflags gtk+-3.0 pkg-config --libs gtk+-3.0`
#include <gtk/gtk.h>
#include <string.h>
#include <stdlib.h>
#define LED_COLOR_RED 0
#define LED_COLOR_GREEN 1
#define LED_COLOR_YELLOW 2
#define LED_COLOR_OFF 3
#define LED_COLOR_COUNT 4
char *color[] = {"red", "green", "yellow", "black"};
GtkWidget *ledLight;
GMutex mutex;
gchar ledText[256];
void *LedTask1 (void *vargp);
void *LedTask2 (void *vargp);
void LedGuiThread ();
void SetFontColors(GtkWidget *grid);
gboolean updateLabel(gpointer data);
void Task_sleep_ms(int ms);
void SetTextColor(char* fcolor);
int main()
{
pthread_t thread_id;
pthread_t thread_id2;
LedGuiThread();
pthread_create(&thread_id2, NULL, LedTask1, NULL);
pthread_create(&thread_id, NULL, LedTask2, NULL);
gtk_main();
// pthread_join(thread_id2, NULL);
// pthread_join(thread_id, NULL);
exit(0);
}
void *LedTask1 (void *vargp)
{
while (1)
{
Task_sleep_ms(100);
SetTextColor(color[LED_COLOR_RED]);
g_idle_add(updateLabel, ledLight);
Task_sleep_ms(100);
SetTextColor(color[LED_COLOR_OFF]);
g_idle_add(updateLabel, ledLight);
}
}
void *LedTask2 (void *vargp)
{
while (1)
{
Task_sleep_ms(100);
SetTextColor(color[LED_COLOR_GREEN]);
g_idle_add(updateLabel, ledLight);
Task_sleep_ms(100);
SetTextColor(color[LED_COLOR_OFF]);
g_idle_add(updateLabel, ledLight);
}
}
void LedGuiThread()
{
GtkWidget *window;
GtkWidget *grid;
GtkWidget *ledLabel;
int argc=0;
char **argv=NULL;
gtk_init (&argc,&argv);
//Declarations
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window), "LED");
grid = gtk_grid_new ();
SetFontColors(grid);
ledLabel = gtk_label_new ("1");
ledLight = gtk_label_new ("O");
//Set Properties
gtk_container_set_border_width (GTK_CONTAINER(window), 20);
gtk_widget_set_size_request (GTK_WIDGET(window), 200, 50);
gtk_grid_set_row_spacing (GTK_GRID(grid), 4);
gtk_grid_set_column_spacing (GTK_GRID(grid), 4);
gtk_container_add (GTK_CONTAINER(window), grid);
//Fill the grid with shit (x, y, h, v)
gtk_grid_attach (GTK_GRID(grid), ledLabel, 2, 2, 2, 1);
gtk_grid_attach (GTK_GRID(grid), ledLight, 2, 3, 2, 1);
gtk_widget_show_all (window);
g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);
}
void SetFontColors(GtkWidget *grid)
{
GtkCssProvider *provider;
GtkStyleContext *context;
/* Change default font and color throughout the widget */
provider = gtk_css_provider_new();
gtk_css_provider_load_from_data(provider,
"* {"
" color: white;"
" background-color: black;"
" font: 20px monospace;"
"}",
-1,
NULL);
context = gtk_widget_get_style_context(grid);
gtk_style_context_add_provider(context,
GTK_STYLE_PROVIDER(provider),
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
}
gboolean updateLabel(gpointer data)
{
char text[256];
GtkLabel *led = data;
g_mutex_lock (&mutex);
strncpy(text, ledText, sizeof(text));
g_mutex_unlock (&mutex);
gtk_label_set_markup (GTK_LABEL (led), text);
}
void Task_sleep_ms(int ms)
{
// printf("sleep %d ms\n", ms);
usleep(ms * 1000);
}
void SetTextColor(char* fcolor)
{
g_mutex_lock(&mutex);
snprintf(ledText, 256, "<span background=\"black\" foreground=\"%s\">O</span>", fcolor);
g_mutex_unlock(&mutex);
}