aboutsummaryrefslogtreecommitdiff
path: root/experimental/status.c
diff options
context:
space:
mode:
authorB. Stack <bgstack15@gmail.com>2022-09-30 16:38:40 -0400
committerB. Stack <bgstack15@gmail.com>2022-09-30 16:40:46 -0400
commit29fa73d2f5013c9502934bc8252014a211d7f7a8 (patch)
tree33a0854ed05537ca4515f784f84889c5e0ee77b6 /experimental/status.c
parentWIP: minimum viable product for status.c (diff)
downloadkeyboard-leds-trayicons-29fa73d2f5013c9502934bc8252014a211d7f7a8.tar.gz
keyboard-leds-trayicons-29fa73d2f5013c9502934bc8252014a211d7f7a8.tar.bz2
keyboard-leds-trayicons-29fa73d2f5013c9502934bc8252014a211d7f7a8.zip
added major C improvements
* use libinih to read config file * handle SIGPIPE gracefully (when a trayicon exits) * exit when both trayicons have exited I wanted to try using libini-config5 but it was not documented at all, and I need useful examples.
Diffstat (limited to 'experimental/status.c')
-rw-r--r--experimental/status.c751
1 files changed, 0 insertions, 751 deletions
diff --git a/experimental/status.c b/experimental/status.c
deleted file mode 100644
index f968af1..0000000
--- a/experimental/status.c
+++ /dev/null
@@ -1,751 +0,0 @@
-/*
- * File: status.c
- * Location: https://bgstack15.ddns.net/cgit/keyboard-leds-trayicons/
- * Author: bgstack15
- * Startdate: 2022-09-28-4 13:30
- * SPDX-License-Identifier: GPL-3.0
- * 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;
-
-int get_indicator(Display* dpy, char* indicator) {
- // where indicator is one of ["Num Lock", "Caps Lock"]
- Atom lockIndicator = XInternAtom(dpy, indicator, False);
- int st;
- XkbGetNamedIndicator(dpy, lockIndicator, NULL, &st, NULL, NULL);
- return st;
-}
-
-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