aboutsummaryrefslogtreecommitdiff
path: root/experimental/status.c
diff options
context:
space:
mode:
authorB. Stack <bgstack15@gmail.com>2022-09-29 15:16:37 -0400
committerB. Stack <bgstack15@gmail.com>2022-09-29 15:16:37 -0400
commit42b63d91290ba85bb9a6a95f33ad0de2f9d64e7a (patch)
tree0d5615ba93b1a16a6f3f583e7a7329eb387cb47b /experimental/status.c
parentadd C proof of concept (diff)
downloadkeyboard-leds-trayicons-42b63d91290ba85bb9a6a95f33ad0de2f9d64e7a.tar.gz
keyboard-leds-trayicons-42b63d91290ba85bb9a6a95f33ad0de2f9d64e7a.tar.bz2
keyboard-leds-trayicons-42b63d91290ba85bb9a6a95f33ad0de2f9d64e7a.zip
WIP: minimum viable product for status.c
The absolute bare minimum, working C program that displays the capslock and numlock indicators in system tray. It has hardcoded values for icons and named pipes, and no config parsing. Possible config libraries include: inih, libini-config5, libminini, libiniparser1
Diffstat (limited to 'experimental/status.c')
-rw-r--r--experimental/status.c713
1 files changed, 712 insertions, 1 deletions
diff --git a/experimental/status.c b/experimental/status.c
index 6357b62..f968af1 100644
--- a/experimental/status.c
+++ b/experimental/status.c
@@ -7,18 +7,619 @@
* Title: Proof of Concept C utility for polling capslock and numlock
* Purpose: Demonstrate these can be done in C, with the eventual goal of rewriting keyboard-leds-trayicons entirely in C to avoid the "sleep 0.75" in ps output
* History:
+ * minimum viable product
* Usage:
* References:
* https://github.com/Cairo-Dock/cairo-dock-plug-ins/blob/master/keyboard-indicator/src/applet-xklavier.c#L124
* https://github.com/oco2000/xfce4-kbdleds-plugin/blob/fe753d9d0f8a720a35a32f5f556b8fbead798d20/panel-plugin/xkbleds.c
+ * https://stackoverflow.com/questions/60897833/programmatically-calling-mainint-argc-char-argv-in-c
+ * https://stackoverflow.com/questions/18649547/how-to-find-the-length-of-argv-in-c
+ * https://www.geeksforgeeks.org/fork-system-call/
+ * https://stackoverflow.com/questions/43326857/multiple-fork-in-c-program
+ * https://stackoverflow.com/questions/14173268/fifo-files-and-read-write
+ * https://ftp.gnu.org/old-gnu/Manuals/glibc-2.2.3/html_chapter/libc_15.html
* Improvements:
* Write main keyboard-led-trayicons logic, which includes parsing config file (libconfig?)
* Write pipe connectivity to mktrayicon or integrate it entirely
+ * https://qnaplus.com/c-program-to-sleep-in-milliseconds/
* Dependencies: libx11-dev
*/
+#include<ctype.h>
+#include<glib.h>
+#include<gtk/gtk.h>
#include<stdio.h>
+#include<stdlib.h>
#include<string.h>
+#include<sys/stat.h>
+#include<unistd.h>
#include<X11/XKBlib.h>
+#include<X11/Xlib.h>
+#include<fcntl.h>
+
+/*
+ * This function is made because it's needed to escape the '\' character
+ * The basic code has been taken from the man pages of the strncpy function
+ */
+char *strncpy_esc(char *dest, const char *src, size_t n) {
+ size_t i = 0;
+ size_t index = 0;
+ while (i < n && src[i] != '\0') {
+ if (src[i] == '\\' && src[i + 1] != '\0') {
+ dest[index] = src[i + 1];
+ index++;
+ i += 2;
+ } else {
+ dest[index] = src[i];
+ index++;
+ i++;
+ }
+ }
+ for (; index < n; index++) {
+ dest[index] = '\0';
+ }
+ return dest;
+}
+
+char *save_word(char *src, int i_del, int last) {
+ char *dest = malloc((i_del - last) * sizeof(char));
+ strncpy_esc(dest, src + last + 1, i_del - last - 1);
+ dest[i_del - last - 1] = '\0';
+ return dest;
+}
+
+/*
+ * Struct that stores the label names on the menu and
+ * their corresponding actions when the user selects them
+ */
+struct item {
+ char *name;
+ char *action;
+} * onmenu;
+char *onscrollup = NULL;
+char *onscrolldown = NULL;
+char *onmiddleclick = NULL;
+int menusize = 0; // number of menu entries
+GtkWidget *menu = NULL;
+
+GtkStatusIcon *icon;
+char *onclick = NULL;
+
+void tray_icon_on_click(GtkStatusIcon *status_icon, gpointer user_data) {
+ if (onclick != NULL && fork() == 0) {
+ execl("/bin/sh", "sh", "-c", onclick, (char *)NULL);
+ }
+}
+
+void tray_icon_on_middleclick(GtkStatusIcon *status_icon, GdkEventButton *event,
+ gpointer user_data) {
+ if (2 == event->button) {
+ if (onmiddleclick == NULL) {
+#ifdef DEBUG
+ printf("middleclick, but no command specified\n");
+#endif
+ } else {
+#ifdef DEBUG
+ printf("middleclick\n");
+#endif
+ if (onmiddleclick != NULL && fork() == 0) {
+ execl("/bin/sh", "sh", "-c", onmiddleclick, (char *)NULL);
+ }
+ }
+ }
+}
+
+/*
+ * Callback function for when an entry is selected from the menu
+ * We loop over all entry names to find what action to execute
+ */
+void click_menu_item(GtkMenuItem *menuitem, gpointer user_data) {
+ const char *label = gtk_menu_item_get_label(menuitem);
+ for (int i = 0; i < menusize; i++) {
+ if (strcmp(label, onmenu[i].name) == 0 && fork() == 0) {
+ execl("/bin/sh", "sh", "-c", onmenu[i].action, (char *)NULL);
+ }
+ }
+}
+
+void tray_icon_on_menu(GtkStatusIcon *status_icon, guint button,
+ guint activate_time, gpointer user_data) {
+#ifdef DEBUG
+ printf("Popup menu\n");
+#endif
+ if (menusize) {
+ gtk_menu_popup_at_pointer((GtkMenu *)menu, NULL);
+ }
+}
+
+void tray_icon_on_scroll(GtkStatusIcon *status_icon, GdkEventScroll *event,
+ gpointer user_data) {
+ char *i = NULL;
+ switch (event->direction) {
+ case GDK_SCROLL_UP:
+ i = "up";
+ if (onscrollup != NULL && fork() == 0)
+ execl("/bin/sh", "sh", "-c", onscrollup, (char *)NULL);
+ break;
+ case GDK_SCROLL_DOWN:
+ i = "down";
+ if (onscrolldown != NULL && fork() == 0)
+ execl("/bin/sh", "sh", "-c", onscrolldown, (char *)NULL);
+ break;
+ }
+ if (i != NULL) {
+#ifdef DEBUG
+ printf("scroll %s\n",i);
+#endif
+ }
+}
+
+gboolean set_tooltip(gpointer data) {
+ char *p = (char *)data;
+ if (*p == '\0') {
+#ifdef DEBUG
+ printf("Removing tooltip\n");
+#endif
+ gtk_status_icon_set_has_tooltip(icon, FALSE);
+ return FALSE;
+ }
+
+#ifdef DEBUG
+ printf("Setting tooltip to '%s'\n", p);
+#endif
+ gtk_status_icon_set_tooltip_text(icon, p);
+ free(data);
+ return FALSE;
+}
+
+gboolean set_icon(gpointer data) {
+ char *p = (char *)data;
+#ifdef DEBUG
+ printf("Setting icon to '%s'\n", p);
+#endif
+ if (strchr(p, '/')) {
+ gtk_status_icon_set_from_file(icon, p);
+ } else {
+ gtk_status_icon_set_from_icon_name(icon, p);
+ }
+ free(data);
+ return FALSE;
+}
+
+gboolean set_visible(gpointer data) {
+ gtk_status_icon_set_visible(icon, data == 0 ? FALSE : TRUE);
+ return FALSE;
+}
+
+gboolean do_quit(gpointer data) {
+ gtk_main_quit();
+ return FALSE;
+}
+
+gpointer watch_fifo(gpointer argv) {
+ char *buf = malloc(1024 * sizeof(char));
+ char cmd;
+ char quote;
+ char *param;
+ char *tmp = malloc(1024 * sizeof(char));
+ char *read;
+ size_t len, i;
+ char *fifo_path = (char *)argv;
+ FILE *fifo;
+ struct stat fifo_st;
+
+/* outer is for open */
+outer:
+ while (1) {
+ if (stat(fifo_path, &fifo_st) != 0) {
+ perror("FIFO does not exist, exiting\n");
+ gdk_threads_add_idle(do_quit, fifo);
+ return NULL;
+ }
+
+ fifo = fopen(fifo_path, "r");
+
+ if (fifo == NULL) {
+ perror("FIFO went away, exiting\n");
+ gdk_threads_add_idle(do_quit, fifo);
+ return NULL;
+ }
+
+ /* inner is for read */
+ while (1) {
+ read = fgets(buf, 1024 * sizeof(char), fifo);
+
+ if (read == NULL) {
+ /* no more data in pipe, reopen and block */
+ fclose(fifo);
+ goto outer;
+ }
+
+ /* trim string */
+ while ((*read == '\n' || *read == ' ' || *read == '\t') &&
+ *read != '\0') {
+ read++;
+ }
+
+ if (*read == '\0') {
+ /* empty command */
+ continue;
+ }
+
+ cmd = *read;
+ len = strlen(read);
+ if (len < 3) {
+ param = NULL;
+ } else if (*(read + 2) != '\'' && *(read + 2) != '"') {
+ // unquoted string
+ read += 2;
+ len -= 2;
+ // trim trailing whitespace
+ i = len - 1;
+ while (i > 0) {
+ if (!isspace(read[i])) {
+ len = i + 1;
+ read[len] = '\0';
+ break;
+ }
+ i -= 1;
+ }
+ param = malloc((len + 1) * sizeof(char));
+ strncpy(param, read, len + 1);
+ } else {
+ // quoted string
+ quote = *(read + 2);
+ read += 3;
+ len -= 3;
+ *tmp = '\0';
+ *(tmp + 1024 - 1) = '\0';
+ // keep track of what we have so far
+ strncpy(tmp, read, 1023);
+
+ // now keep reading until we have the end quote
+ while (1) {
+ // check for terminating '
+ if (len != 0) {
+ // search backwards past whitespace
+ i = len - 1;
+ while (i > 0) {
+ if (!isspace(tmp[i])) {
+ break;
+ }
+ i -= 1;
+ }
+ if (tmp[i] == quote) {
+ // maybe the end!
+ // let's make sure it isn't escaped
+ if (i >= 2 && tmp[i - 2] == '\\') {
+ } else {
+ // it's not!
+ // we're done.
+ // trim off the ' and
+ // any whitespace we walked past
+ len = i;
+ tmp[len] = '\0';
+ break;
+ }
+ }
+ }
+
+ if (len == 1023) {
+ // we can't read any more
+ // but also haven't found the end
+ // forcibly terminate the string
+ fprintf(stderr, "Quoted string too long (max 1023 chars)\n");
+ break;
+ }
+
+ // we don't have the end of the string yet
+ read = fgets(buf, 1024 * sizeof(char), fifo);
+ if (read == NULL) {
+ /* no more data in pipe, reopen and block */
+ fclose(fifo);
+ goto outer;
+ }
+ // note that we don't trim here, because we're
+ // in a quoted string.
+ strncpy(tmp + len, read, 1023 - len);
+ len += strlen(tmp + len);
+ }
+
+ // quoted string is now in param[0:len]
+ param = malloc((len + 1) * sizeof(char));
+ strncpy(param, tmp, len + 1);
+ }
+
+ switch (cmd) {
+ case 'q':
+ gdk_threads_add_idle(do_quit, param);
+ if (param != NULL) {
+ free(param);
+ }
+ break;
+ case 't': /* tooltip */
+ gdk_threads_add_idle(set_tooltip, param);
+ break;
+ case 'i': /* icon */
+ gdk_threads_add_idle(set_icon, param);
+ break;
+ case 'h': /* hide */
+ gdk_threads_add_idle(set_visible, (void *)0);
+ if (param != NULL) {
+ free(param);
+ }
+ break;
+ case 's': /* show */
+ gdk_threads_add_idle(set_visible, (void *)1);
+ if (param != NULL) {
+ free(param);
+ }
+ break;
+ case 'c': /* click */
+ if (onclick != NULL) {
+ free(onclick);
+ onclick = NULL;
+ }
+
+ if (param != NULL && *param == '\0') {
+#ifdef DEBUG
+ printf("Removing onclick handler\n");
+#endif
+ free(param);
+ break;
+ }
+
+ onclick = param;
+#ifdef DEBUG
+ printf("Setting onclick handler to '%s'\n", onclick);
+#endif
+ break;
+ case 'm': /* menu */
+ if (onmenu != NULL) {
+ // destroy the previous menu
+ for (int i = 0; i < menusize; i++) {
+ free(onmenu[i].name);
+ free(onmenu[i].action);
+ onmenu[i].name = NULL;
+ onmenu[i].action = NULL;
+ }
+ free(onmenu);
+ onmenu = NULL;
+ gtk_widget_destroy(menu);
+ menu = NULL;
+ }
+
+ menusize = 0;
+
+ if (!param) {
+ break;
+ } else if (*param == '\0') {
+#ifdef DEBUG
+ printf("Removing onmenu handler\n");
+#endif
+ free(param);
+ break;
+ }
+
+ // This block makes sure that the parameter after 'm' is ready to be
+ // processed We can't accept 2 straight commas, as it becomes ambiguous
+ int straight = 0;
+ int bars = 0;
+ for (int i = 0; i < len; i++) {
+ if (param[i] == ',' && param[i - 1] != '\\') {
+ straight++;
+ if (straight == 2) {
+ break;
+ }
+ } else if (param[i] == '|' && param[i - 1] != '\\') {
+ straight = 0;
+ bars++;
+ }
+ }
+ if (straight == 2) {
+ printf("Two straight ',' found. Use '\\' to escape\n");
+ free(param);
+ break;
+ }
+ // End of block that checks the parameter
+
+ // Create the onmenu array which stores structs with name, action
+ // properties
+ menusize = bars + 1;
+ onmenu = malloc(menusize * sizeof(struct item));
+ menu = gtk_menu_new();
+ int last = -1;
+ int item = 0;
+ char lastFound = '|'; // what was the last delimiter processed
+ for (int i = 0; i < len; i++) {
+ if (param[i] == ',' && param[i - 1] != '\\') {
+ onmenu[item].name = save_word(param, i, last);
+ last = i;
+ lastFound = ',';
+ } else if (param[i] == '|' && param[i - 1] != '\\') {
+ if (lastFound == ',') { // we have found a ',' so we read an action
+ onmenu[item].action = save_word(param, i, last);
+ } else { // this is a label-only entry
+ onmenu[item].name = save_word(param, i, last);
+ onmenu[item].action = malloc(1); // pointer has to be freeable
+ *onmenu[item].action = '\0';
+ }
+ last = i;
+ lastFound = '|';
+ item++;
+ }
+ }
+ if (item < menusize) { // haven't read all actions because last one
+ // didn't end with a '|'
+ if (lastFound == ',') {
+ onmenu[item].action = save_word(param, len, last);
+ } else {
+ onmenu[item].name = save_word(param, len, last);
+ onmenu[item].action = malloc(1);
+ *onmenu[item].action = '\0';
+ }
+ }
+
+ // Now create the menu item widgets and attach them on the menu
+ for (int i = 0; i < menusize; i++) {
+ GtkWidget *w;
+ if (0 == strlen(onmenu[i].name) || (!strncmp(onmenu[i].name, "-----", 5))) {
+ w = gtk_separator_menu_item_new() ;
+ } else {
+ w = gtk_menu_item_new_with_label(onmenu[i].name);
+ g_signal_connect(G_OBJECT(w), "activate", G_CALLBACK(click_menu_item),
+ NULL);
+ }
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), w);
+ }
+ gtk_widget_show_all(menu);
+ free(param);
+ break;
+ case 'R': /* mouse scroll up */
+ if (onscrollup != NULL) {
+ free(onscrollup);
+ }
+ if (!param || (*param == '\0')) {
+#ifdef DEBUG
+ printf("Removing scrollup command\n");
+ onscrollup = NULL;
+#endif
+ } else {
+#ifdef DEBUG
+ printf("Setting scrollup command\n");
+#endif
+ onscrollup = malloc(strlen(param));
+ strncpy(onscrollup, param, len + 1);
+ }
+ break;
+ case 'r': /* mouse scroll down */
+ if (onscrolldown != NULL) {
+ free(onscrolldown);
+ }
+ if (!param || (*param == '\0')) {
+#ifdef DEBUG
+ printf("Removing scrolldown command\n");
+ onscrolldown = NULL;
+#endif
+ } else {
+#ifdef DEBUG
+ printf("Setting scrolldown command\n");
+#endif
+ onscrolldown = malloc(strlen(param));
+ strncpy(onscrolldown, param, len + 1);
+ }
+ break;
+ case 'S': /* mouse middle click */
+ if (onmiddleclick != NULL) {
+ free(onmiddleclick);
+ }
+ if (!param || (*param == '\0')) {
+#ifdef DEBUG
+ printf("Removing middle click command\n");
+ onmiddleclick = NULL;
+#endif
+ } else {
+#ifdef DEBUG
+ printf("Setting middleclick command\n");
+#endif
+ onmiddleclick = malloc(strlen(param));
+ strncpy(onmiddleclick, param, len + 1);
+ }
+ break;
+ default:
+ fprintf(stderr, "Unknown command: '%c'\n", *buf);
+ if (param != NULL) {
+ free(param);
+ }
+ }
+
+ gdk_flush();
+ }
+ }
+ return NULL;
+}
+
+static GtkStatusIcon *create_tray_icon(char *start_icon) {
+ GtkStatusIcon *tray_icon;
+
+ if (strchr(start_icon, '/')) {
+ tray_icon = gtk_status_icon_new_from_file(start_icon);
+ } else {
+ tray_icon = gtk_status_icon_new_from_icon_name(start_icon);
+ }
+ g_signal_connect(G_OBJECT(tray_icon), "activate",
+ G_CALLBACK(tray_icon_on_click), NULL);
+ g_signal_connect(G_OBJECT(tray_icon), "popup-menu",
+ G_CALLBACK(tray_icon_on_menu), NULL);
+ g_signal_connect(G_OBJECT(tray_icon), "scroll-event",
+ G_CALLBACK(tray_icon_on_scroll), NULL);
+ g_signal_connect(G_OBJECT(tray_icon), "button-release-event",
+ G_CALLBACK(tray_icon_on_middleclick), NULL);
+ gtk_status_icon_set_visible(tray_icon, TRUE);
+
+ return tray_icon;
+}
+
+int print_usage(char **argv) {
+ printf("Usage: %s [-i ICON] [-t TOOLTIP] [-h] [FIFO]\n", *argv);
+ printf("Create a system tray icon as specified\n");
+ printf("\n");
+ printf(" -i ICON\tUse the specified ICON when initializing\n");
+ printf(" -t TOOLTIP\tUse the specified TOOLTIP when initializing\n");
+ printf(" -h \t\tDisplay this help message\n");
+ printf("\n");
+ printf("If a FIFO is not provided, mktrayicon will run until killed\n");
+ printf("Report bugs at https://github.com/jonhoo/mktrayicon\n");
+ return 0;
+}
+
+int fmain(int argc, char **argv) {
+ char *start_icon = "none";
+ char *tooltip = NULL;
+ char *pipe = NULL;
+ GThread *reader;
+
+ XInitThreads(); /* see http://stackoverflow.com/a/18690540/472927 */
+ gtk_init(&argc, &argv);
+
+ if (argc == 1) {
+ return print_usage(argv);
+ }
+
+ int c;
+ while ((c = getopt(argc, argv, "i:t:h")) != -1)
+ switch (c) {
+ case 'i':
+ start_icon = optarg;
+ break;
+ case 't':
+ tooltip = optarg;
+ break;
+ case 'h':
+ return print_usage(argv);
+ case '?':
+ fprintf(stderr, "Unknown option: %c\n", optopt);
+ return 1;
+ }
+
+ icon = create_tray_icon(start_icon);
+
+ if (tooltip) {
+ gtk_status_icon_set_tooltip_text(icon, tooltip);
+ }
+
+ /* optind holds the index of the next argument to be parsed */
+ /* getopt moved positional arguments (if there were any) to the end of the
+ * argv array, without parsing them */
+ /* so if there were only non-positional arguments, all arguments have been
+ * parsed and optind will be equal to argc */
+ if (optind < argc) {
+ pipe = argv[optind];
+ reader = g_thread_new("watch_fifo", watch_fifo, pipe);
+ }
+
+ gtk_main();
+ return 0;
+}
Display* dpy;
@@ -30,11 +631,121 @@ int get_indicator(Display* dpy, char* indicator) {
return st;
}
-int main() {
+int main(int argc, char **argv) {
+ FILE *stream;
dpy = XOpenDisplay( NULL );
int status_capslock = get_indicator(dpy, "Caps Lock");
int status_numlock = get_indicator(dpy, "Num Lock");
printf("Capslock: %d\tNumlock: %d\n",status_capslock,status_numlock);
+ char *fifo_name_C = "/tmp/fifo1";
+ char *fifo_name_N = "/tmp/fifo2";
printf("done\n");
+ char *_argv_C[] = { "fmain", fifo_name_C, NULL };
+ char *_argv_N[] = { "fmain", fifo_name_N, NULL };
+ int count_C = 0;
+ int count_N = 0;
+ int fd_C, fd_N;
+ struct stat st_C, st_N;
+ char *msg;
+ if (stat(fifo_name_C, &st_C) != 0)
+ mkfifo(fifo_name_C, 0666);
+ if (stat(fifo_name_N, &st_N) != 0)
+ mkfifo(fifo_name_N, 0666);
+ while (_argv_C[++count_C]);
+ while (_argv_N[++count_N]);
+ //fd_C = open(fifo_name_C, O_WRONLY);
+ if (fork() == 0) {
+ // parent1->child 1
+ if (fork() == 0) {
+ // parent1->child1->child1
+ fmain(count_C,_argv_C);
+ }
+ else {
+ // parent1->child1
+ fd_C = open(fifo_name_C, O_WRONLY);
+ stream = fdopen(fd_C,"w");
+ msg = "m quit,echo 'q' > /tmp/fifo1\n";
+ printf("sending to fd_C %d message %s",fd_C,msg);
+ fprintf(stream,msg);
+ if (status_capslock)
+ msg = "i /home/bgstack15/dev/keyboard-leds-trayicons/src/usr/share/icons/hicolor/scalable/status/capslock-on.svg\n";
+ else
+ msg = "i /home/bgstack15/dev/keyboard-leds-trayicons/src/usr/share/icons/hicolor/scalable/status/capslock-off.svg\n";
+ printf("sending to fd_C %d message %s",fd_C,msg);
+ fprintf(stream,msg);
+ fclose(stream);
+ };
+ }
+ else {
+ // parent 1
+ if (fork() == 0) {
+ // parent1->child2
+ fmain(count_N,_argv_N);
+ }
+ else {
+ // parent 1
+ fd_N = open(fifo_name_N, O_WRONLY);
+ stream = fdopen(fd_N,"w");
+ msg = "i battery\n";
+ printf("sending to fd_N %d message %s",fd_N,msg);
+ fprintf(stream,msg);
+ msg = "m say hello,yad 'hello'|quit,echo 'q' > /tmp/fifo2\n";
+ printf("sending to fd_N %d message %s",fd_N,msg);
+ fprintf(stream,msg);
+ fclose(stream);
+ };
+ // still parent 1
+ // main logic loop happens now
+ //while (access("/tmp/stop-keyboard-leds",F_OK) != 0) {
+ fd_C = open(fifo_name_C, O_WRONLY);
+ fd_N = open(fifo_name_N, O_WRONLY);
+ int status_caps_old = status_capslock;
+ int status_num_old = status_numlock;
+ while (1) {
+ //ueep(1000000); 1 second
+ //ueep( 1000); 1 millisecond
+ usleep( 100000); // WORKHERE: should be configurable
+ status_capslock = get_indicator(dpy, "Caps Lock");
+ status_numlock = get_indicator(dpy, "Num Lock");
+ //printf("Capslock: %d\tNumlock: %d\n",status_capslock,status_numlock);
+ if(status_capslock != status_caps_old) {
+ stream = fdopen(fd_C,"w");
+ if (stream > 0) {
+ if(0 == status_capslock) {
+ msg = "i /home/bgstack15/dev/keyboard-leds-trayicons/src/usr/share/icons/hicolor/scalable/status/capslock-off.svg\n";
+ //printf("sending to fd_C %d message %s",fd_C,msg);
+ printf("capslock off\n");
+ fprintf(stream,msg);
+ }
+ else {
+ msg = "i /home/bgstack15/dev/keyboard-leds-trayicons/src/usr/share/icons/hicolor/scalable/status/capslock-on.svg\n";
+ printf("capslock on\n");
+ fprintf(stream,msg);
+ };
+ status_caps_old = status_capslock;
+ fflush(stream);
+ //fclose(stream);
+ };
+ };
+ if(status_numlock != status_num_old) {
+ stream = fdopen(fd_N,"w");
+ if (stream > 0) {
+ if(0 == status_numlock) {
+ msg = "i /home/bgstack15/dev/keyboard-leds-trayicons/src/usr/share/icons/hicolor/scalable/status/numlock-off.svg\n";
+ //printf("sending to fd_N %d message %s",fd_N,msg);
+ printf("numlock off\n");
+ fprintf(stream,msg);
+ }
+ else {
+ msg = "i /home/bgstack15/dev/keyboard-leds-trayicons/src/usr/share/icons/hicolor/scalable/status/numlock-on.svg\n";
+ printf("numlock on\n");
+ fprintf(stream,msg);
+ };
+ status_num_old = status_numlock;
+ fflush(stream);
+ };
+ };
+ };
+ };
return 0;
}
bgstack15