]> git.plutz.net Git - gladerunner/commitdiff
additional widget/event classes, run input loop in separate thread
authorPaul Hänsch <paul@plutz.net>
Tue, 14 Jul 2026 15:03:45 +0000 (17:03 +0200)
committerPaul Hänsch <paul@plutz.net>
Tue, 14 Jul 2026 15:03:45 +0000 (17:03 +0200)
glade1.c

index 5438e93316e63eb42b372ddb7f2361aab0f71e66..c3277dd04c52c24b756fd83e424f5270bbb4b8dd 100644 (file)
--- a/glade1.c
+++ b/glade1.c
@@ -2,6 +2,9 @@
 #include <stdio.h>
 #include <unistd.h>
 #include <fcntl.h>
+#include <sys/select.h>  // only for idle_loop variant
+#include <sys/time.h>    // only for idle_loop variant
+#include <pthread.h>     // only for thread based variant
 
 static GtkBuilder *builder = NULL;
 static int chldin[2], chldout[2];
@@ -16,28 +19,63 @@ static int chldin[2], chldout[2];
 //   { GTK_TYPE_TEXT_VIEW, "set", &ca_text_view }
 // };
 
-void app_quit(GtkWidget *wdg, gpointer user_data) {
-  exit(0);
+// ====== UI EVENTS ======
+
+void e_si_activate(GtkWidget *wdg, gpointer d) {
+  printf("%s ACTIVATE\n", (char*) d);
 }
 
-void text_content(GtkWidget *wdg, gpointer user_data) {
-  GtkEntry *e;
-  if (GTK_IS_ENTRY(wdg)) {
-    e = GTK_ENTRY( wdg );
-    printf( "%s CHANGED %s\n",
-            gtk_buildable_get_name(GTK_BUILDABLE(wdg)),
-            gtk_entry_buffer_get_text(  gtk_entry_get_buffer( e ) )
-          );
-  }
+void e_button_clicked(GtkWidget *wdg, gpointer d) {
+  printf(
+    "%s CLICKED\n",
+    gtk_buildable_get_name(GTK_BUILDABLE(wdg))
+  );
 }
 
-void button_click(GtkWidget *wdg, gpointer d) {
-  printf( "%s CLICKED\n",
-          GTK_IS_BUILDABLE(wdg)?gtk_buildable_get_name(GTK_BUILDABLE(wdg)):(char *)d
-        );
+// Radio Buttons and Checkboxes are "Toggle Buttons"
+void e_tb_toggled(GtkWidget *wdg, gpointer d) {
+  GtkToggleButton *t = GTK_TOGGLE_BUTTON(wdg);
+  printf(
+    "%s TOGGLED %i\n",
+    gtk_buildable_get_name(GTK_BUILDABLE(wdg)),
+    gtk_toggle_button_get_active(t)
+  );
 }
 
-// ====== CLI ACTIONS =======
+// Radio Buttons and Checkboxes within menus are "Check Menu Items"
+void e_cmi_toggled(GtkWidget *wdg, gpointer d) {
+  GtkCheckMenuItem *c = GTK_CHECK_MENU_ITEM(wdg);
+  printf(
+    "%s TOGGLED %i\n",
+    gtk_buildable_get_name(GTK_BUILDABLE(wdg)),
+    gtk_check_menu_item_get_active(c)
+  );
+}
+
+gboolean s_switch_state_set(GtkWidget *wdg, gboolean state, gpointer d) {
+  GtkSwitch *s = GTK_SWITCH(wdg);
+  printf(
+    "%s STATE-SET %i\n",
+    gtk_buildable_get_name(GTK_BUILDABLE(wdg)),
+    state
+  );
+  return 0;
+}
+
+void e_entry_changed(GtkWidget *wdg, gpointer user_data) {
+  GtkEntry *e = GTK_ENTRY(wdg);
+  printf(
+    "%s CHANGED %s\n",
+    gtk_buildable_get_name(GTK_BUILDABLE(wdg)),
+    gtk_entry_buffer_get_text(gtk_entry_get_buffer(e))
+  );
+}
+
+void app_quit(GtkWidget *wdg, gpointer user_data) {
+  exit(0);
+}
+
+// ====== CLI ACTIONS ======
 
 void a_text_view_set(GtkTextView *v, char *c) {
   gtk_text_buffer_set_text(
@@ -93,12 +131,12 @@ int action(char *cli) {
   if ( !wid || !wid[0]
     || !(wdg = GTK_WIDGET(gtk_builder_get_object(builder, wid)))
   ) return 0;
-  else if (
-     (GTK_IS_BUTTON(wdg)    &&    a_button(GTK_BUTTON(wdg),    cmd, args))
+  else if (0
   || (GTK_IS_ENTRY(wdg)     &&     a_entry(GTK_ENTRY(wdg),     cmd, args))
   || (GTK_IS_WINDOW(wdg)    &&    a_window(GTK_WINDOW(wdg),    cmd, args))
   || (GTK_IS_TEXT_VIEW(wdg) && a_text_view(GTK_TEXT_VIEW(wdg), cmd, args))
   || (GTK_IS_EDITABLE(wdg)  &&  a_editable(GTK_EDITABLE(wdg),  cmd, args))
+  || (GTK_IS_BUTTON(wdg)    &&    a_button(GTK_BUTTON(wdg),    cmd, args))
   || (GTK_IS_WIDGET(wdg)    &&    a_widget(GTK_WIDGET(wdg),    cmd, args))
   ) return 1;
   else return 0;
@@ -108,14 +146,21 @@ gboolean idle_readline(gpointer d) {
   static size_t s = 128;
   static char *buf = NULL;
   static int len = 0; int l;
-  if (!buf) buf = malloc(s);
+  static fd_set fds;
+  struct timeval t = { .tv_sec = 0, .tv_usec = 10000 };
+  if (!buf) {
+    buf = malloc(s);
+    fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL) | O_NONBLOCK);
+  }
 
+  FD_ZERO(&fds);
+  FD_SET(STDIN_FILENO, &fds);
+  if ( select(STDIN_FILENO + 1, &fds, NULL, NULL, &t) <= 0) return G_SOURCE_CONTINUE;
   while ( (l = read(STDIN_FILENO, buf + len, s - len)) > 0) {
     len += l;
     if ( buf[len - 1] == '\n' && (len < 2 || buf[len - 2] != '\\') ) break;
     else if (len >= 2) buf[--len - 1] = '\n';
     if ( len == s - 1 ) buf = realloc(buf, s+=128);
-    l = read(0, buf + len, s - len);
   }
   if ( l > 0 ) {
     buf[len - 1] = 0;
@@ -124,23 +169,46 @@ gboolean idle_readline(gpointer d) {
   } else if (l == 0) {
     exit(0);
   }
-  return 1;
+  return G_SOURCE_CONTINUE;
+}
+
+void* thread_readline(void *d) {
+  int l, len = 0;
+  size_t s = 128;
+  char *buf = malloc(s);
+  // if (!buf) buf = malloc(s);
+
+  while ( (l = read(STDIN_FILENO, buf + len, s - len)) > 0 ) {
+    len += l;
+    if ( buf[len - 1] == '\n' && (len < 2 || buf[len - 2] != '\\') ) {
+      buf[len - 1] = 0;
+      action(buf);
+      len = 0;
+    } else if (len >= 2) buf[--len - 1] = '\n';
+    if ( len == s - 1 ) buf = realloc(buf, s+=128);
+  }
+  exit(0); return NULL;
 }
 
 void init_widgets(gpointer wp, gpointer data) {
-  GtkWidget *wdg;
+  GtkWidget *wdg; const char *name;
 
   if (GTK_IS_BUILDABLE(wp)) { 
     wdg = GTK_WIDGET(wp);
-    printf("%s load\n", gtk_buildable_get_name(GTK_BUILDABLE(wp)));
+    name = gtk_buildable_get_name(GTK_BUILDABLE(wp));
 
-    if      (GTK_IS_BUTTON(wdg)) g_signal_connect(wdg, "clicked", G_CALLBACK(button_click), NULL);
-    else if (GTK_IS_ENTRY(wdg) ) g_signal_connect(wdg, "changed", G_CALLBACK(text_content), NULL);
-    else if (GTK_IS_WINDOW(wdg)) g_signal_connect(wdg, "destroy", G_CALLBACK(app_quit), NULL);
+    if (strncmp(name, "___", 3) == 0 ) return;
+    else if (GTK_IS_TOGGLE_BUTTON(wdg))   g_signal_connect(wdg, "toggled", G_CALLBACK(e_tb_toggled),     NULL);
+    else if (GTK_IS_CHECK_MENU_ITEM(wdg)) g_signal_connect(wdg, "toggled", G_CALLBACK(e_cmi_toggled),    NULL);
+    else if (GTK_IS_ENTRY(wdg) )          g_signal_connect(wdg, "changed", G_CALLBACK(e_entry_changed),  NULL);
+    else if (GTK_IS_WINDOW(wdg))          g_signal_connect(wdg, "destroy", G_CALLBACK(app_quit),         NULL);
+    else if (GTK_IS_BUTTON(wdg))          g_signal_connect(wdg, "clicked", G_CALLBACK(e_button_clicked), NULL);
+    else { printf("%s unknown\n", name); return; }
+    printf("%s loaded\n", name);
 
   } else if (GTK_IS_STATUS_ICON(wp)) {
     printf("StatusIcon load\n");
-    g_signal_connect(wp, "activate", G_CALLBACK(button_click), "StatusIcon");
+    g_signal_connect(wp, "activate", G_CALLBACK(e_si_activate), "StatusIcon");
   }
 }
 
@@ -192,8 +260,9 @@ int main(int argc, char *argv[]) {
   g_slist_foreach(widgets, *init_widgets, NULL);
   g_slist_free(widgets);
 
-  fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL) | O_NONBLOCK);
-  g_idle_add(idle_readline, builder);
+  // g_idle_add(idle_readline, builder);
+  pthread_t rl;
+  pthread_create(&rl, NULL, thread_readline, NULL);
 
   gtk_main();
   return 0;