From f82c3149c18d88398f47909f15b6d5201ddb6895 Mon Sep 17 00:00:00 2001 From: ItzSelenux Date: Tue, 17 Sep 2024 14:51:38 -0600 Subject: [PATCH] Implement Evdev --- .github/workflows/c-cpp.yml | 14 ++++- Makefile | 15 ++++- README.md | 64 +++++++++++++------ VERSION | 2 +- cfgmgr.h | 11 ++++ evdevintegrity.h | 77 +++++++++++++++++++++++ gxcapindicator.c | 11 ++++ gxcapindicator.conf | 6 +- gxcapindicator.h | 30 ++++++--- keyhandler.h | 121 +++++++++++++++++++++++++++++------- mainwindow.h | 29 +++++++-- settings.h | 8 +++ 12 files changed, 328 insertions(+), 60 deletions(-) create mode 100644 evdevintegrity.h mode change 100644 => 100755 gxcapindicator.conf diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml index aab5f39..8ed4827 100644 --- a/.github/workflows/c-cpp.yml +++ b/.github/workflows/c-cpp.yml @@ -29,17 +29,24 @@ jobs: libgtk-3-dev \ libayatana-appindicator3-dev \ pkg-config \ + libudev-dev \ + libinput-dev \ + libevdev-dev \ clang - name: Build with GCC run: | - make CC=gcc + make CC=gcc strip gxcapindicator - mv gxcapindicator ${{ env.GH_RELEASE_FILE }} + mv gxcapindicator ${{ env.GH_RELEASE_FILE }}-Evdev + make CC=gcc WITHX11=1 + strip gxcapindicator + mv gxcapindicator ${{ env.GH_RELEASE_FILE }}-X11 - name: Build with Clang run: | make CC=clang + make CC=clang WITHX11=1 continue-on-error: true - name: Build with -Werror @@ -54,4 +61,5 @@ jobs: body: ${{ github.event.head_commit.message }} tag_name: ${{ env.GH_RELEASE_VERSION }} files: | - ${{ env.GH_RELEASE_FILE }} \ No newline at end of file + ${{ env.GH_RELEASE_FILE }}-Evdev + ${{ env.GH_RELEASE_FILE }}-X11 \ No newline at end of file diff --git a/Makefile b/Makefile index 5ec4e89..05b55cd 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,15 @@ +WITHX11 ?= 0 + +ifeq ($(WITHX11), 0) + XLIB = -ludev -linput -levdev -I/usr/include/libevdev-1.0/ +else + XLIB = -lX11 + FLAGS +=-DWITHX11 +endif + CC = cc -CFLAGS = `pkg-config --cflags gtk+-3.0 ayatana-appindicator3-0.1` -Wall -LIBS = `pkg-config --libs gtk+-3.0 ayatana-appindicator3-0.1` -lpthread -lX11 +CFLAGS = `pkg-config --cflags gtk+-3.0 ayatana-appindicator3-0.1` $(FLAGS) $(XLIB) +LIBS = `pkg-config --libs gtk+-3.0 ayatana-appindicator3-0.1` -lpthread $(XLIB) SRC = gxcapindicator.c OBJ = $(SRC:.c=.o) @@ -34,4 +43,4 @@ uninstall: rm -f /usr/local/share/icons/hicolor/32x32/devices/keyboard-caps-disabled.svg rm -f /usr/local/share/icons/hicolor/32x32/devices/keyboard-caps-enabled.svg rm -f /usr/local/share/icons/hicolor/32x32/devices/keyboard-num-disabled.svg - rm -f /usr/local/share/icons/hicolor/32x32/devices/keyboard-num-enabled.svg \ No newline at end of file + rm -f /usr/local/share/icons/hicolor/32x32/devices/keyboard-num-enabled.svg diff --git a/README.md b/README.md index 9fa5ba3..1afea91 100644 --- a/README.md +++ b/README.md @@ -1,28 +1,56 @@ -# gxcapindicator +# GXCapIndicator -Description of Image +GXCapIndicator Logo +**GXCapIndicator** is a simple tool for indicating the status of Caps Lock and Num Lock keys in the system tray. -Simple Cap/Num lock key indicator for x11 tray +## Features -## Features: +- [x] Monitor Caps Lock and Num Lock keys +- [x] Toggle Caps Lock and Num Lock with an on-screen button +- [x] Hideable indicators +- [x] Adjustable update rate +- [x] Wayland support (with `Evdev`) -- [x] Monitor Cap/Num Keys -- [x] Toggle Cap/Num Keys with a on-screen button -- [x] Hiddeable indicators -- [x] Choose update rate -- [ ] Wayland support +## Installation -## Configuration - -| Item | Description | Possible values| Default Value| example -| --- | --- | --- | --- | --- | -| showcap | Enables "Caps Lock" key indicator | 0, 1 | 1 | showcap=1| -| shownum | Enables "Num Lock" key indicator | 0, 1 | 1 | shownum=1 | -| updrate | Set update rate | (Number) | 0 | updrate=0 | +To build GXCapIndicator, choose the backend you want to use: -## Build +### With Evdev Backend +```sh +make ``` -make gxcapindicator + +### With X11 Backend + +```sh +make WITHX11=1 ``` + +## Backend Differences + +GXCapIndicator supports two backends for fetching key status: X11 and Evdev. Each backend has its own capabilities and limitations. + +### X11 Backend +- Uses `XkbGetState` to fetch the key status. +- Some options are not available: + - **Initial Visual State**: Cannot set the initial visual state of Caps Lock/Num Lock (unnecessary with XkbGetState). + +### Evdev Backend +- Uses `libinput_event_get_keyboard_event` to fetch the key status. +- Some options are not available: + - **Update Rate**: Polling rate is fixed and cannot be adjusted. + - **Toggle Functionality**: Can't be implemented without root access. + +## Configuration + +You can configure GXCapIndicator with the integrated GUI (`settings` in indicator menu) or by editing` $HOME/.config/gxcapindicator` using the following options: + +| Item | Description | Possible Values | Default Value | Example | Scope | +|-------------|--------------------------------------|-----------------|---------------|-------------|---------| +| `showcap` | Enables the Caps Lock key indicator | `0`, `1` | `1` | `showcap=1` | All | +| `shownum` | Enables the Num Lock key indicator | `0`, `1` | `1` | `shownum=1` | All | +| `updrate` | Sets the update rate | (Number) | `0` | `updrate=0` | X11 | +| `vcapstate` | Sets the initial visual state of Caps Lock | `0`, `1` | `0` | `vcapstate=0` | Evdev | +| `vnumstate` | Sets the initial visual state of Num Lock | `0`, `1` | `0` | `vnumstate=0` | Evdev | \ No newline at end of file diff --git a/VERSION b/VERSION index 9459d4b..5625e59 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.1 +1.2 diff --git a/cfgmgr.h b/cfgmgr.h index 361ad0e..8e9e758 100644 --- a/cfgmgr.h +++ b/cfgmgr.h @@ -28,6 +28,8 @@ void on_preferences(GtkWidget *button, gpointer data) gshowcap = gtk_check_button_new(); gshownum = gtk_check_button_new(); + gcapstate = gtk_check_button_new(); + gnumstate = gtk_check_button_new(); gupdrate = gtk_entry_new(); btn_cancel = gtk_button_new_with_label("cancel"); @@ -37,13 +39,22 @@ void on_preferences(GtkWidget *button, gpointer data) gtk_grid_attach(GTK_GRID(grid), gshowcap, 1, 0, 1, 1); gtk_grid_attach(GTK_GRID(grid), gtk_label_new("Show Num Lock:"), 0, 1, 1, 1); gtk_grid_attach(GTK_GRID(grid), gshownum, 1, 1, 1, 1); + #ifdef WITHX11 gtk_grid_attach(GTK_GRID(grid), gtk_label_new("Update rate (seconds):"), 0, 2, 1, 1); gtk_grid_attach(GTK_GRID(grid), gupdrate, 1, 2, 1, 1); + #else + gtk_grid_attach(GTK_GRID(grid), gtk_label_new("Start with caps lock \n visually enabled:"), 0, 2, 1, 1); + gtk_grid_attach(GTK_GRID(grid), gcapstate, 1, 2, 1, 1); + gtk_grid_attach(GTK_GRID(grid), gtk_label_new("Start with num lock \n visually enabled:"), 0, 3, 1, 1); + gtk_grid_attach(GTK_GRID(grid), gnumstate, 1, 3, 1, 1); + #endif gtk_grid_attach(GTK_GRID(grid), btn_cancel, 0, 6, 1, 1); gtk_grid_attach(GTK_GRID(grid), btn_savesettings, 1, 6, 1, 1); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gshowcap), !!showcap); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gshownum), !!shownum); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gcapstate), !!vcapstate); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gnumstate), !!vnumstate); char buffer[32]; snprintf(buffer, sizeof(buffer), "%d", updrate); diff --git a/evdevintegrity.h b/evdevintegrity.h new file mode 100644 index 0000000..7a89ef1 --- /dev/null +++ b/evdevintegrity.h @@ -0,0 +1,77 @@ +// Restricted file access functions for libinput + int open_restricted(const char *path, int flags, void *user_data) +{ + int fd = open(path, flags); + if (fd < 0) + { + perror("Failed to open restricted path"); + } + return fd < 0 ? -errno : fd; +} + + void close_restricted(int fd, void *user_data) +{ + close(fd); +} + + const struct libinput_interface interface = +{ + .open_restricted = open_restricted, + .close_restricted = close_restricted, +}; + +void check_udev() +{ +struct udev *udev = udev_new(); + if (udev == NULL) + { + g_error("Failed to initialize udev."); + return; + } + + libinput = libinput_udev_create_context(&interface, NULL, udev); + if (!libinput) + { + g_error("Failed to initialize libinput from udev."); + udev_unref(udev); + return; + } + + if (libinput_udev_assign_seat(libinput, "seat0") != 0) + { + g_error("Failed to set seat."); + libinput_unref(libinput); + udev_unref(udev); + return; + } +} + +gboolean check_permissions(const gchar* group_name) +{ + gid_t *groups; + int ngroups; + struct group *grp; + gid_t gid; + + ngroups = getgroups(0, NULL); + groups = g_malloc(ngroups * sizeof(gid_t)); + getgroups(ngroups, groups); + + grp = getgrnam(group_name); + if (!grp) { + g_free(groups); + return FALSE; + } + gid = grp->gr_gid; + + for (int i = 0; i < ngroups; i++) { + if (groups[i] == gid) { + g_free(groups); + return TRUE; + } + } + + g_free(groups); + g_error("User is likely not in input group, please add your user to input group or compile this program with -DWITHX11 if you're running X11"); + return FALSE; +} \ No newline at end of file diff --git a/gxcapindicator.c b/gxcapindicator.c index 109c17d..3bfc98e 100644 --- a/gxcapindicator.c +++ b/gxcapindicator.c @@ -2,7 +2,18 @@ int main(int argc, char *argv[]) { + isx11 = (strcmp(getenv("XDG_SESSION_TYPE"), "wayland") != 0); readconf(); + + #ifdef WITHX11 + g_print("Running with X11 backend"); + #else + g_print("Running with Evdev backend"); + + check_udev(); + check_permissions("input"); + #endif + gtk_init(&argc, &argv); create_window(); } \ No newline at end of file diff --git a/gxcapindicator.conf b/gxcapindicator.conf old mode 100644 new mode 100755 index 8abb23c..38a6bb5 --- a/gxcapindicator.conf +++ b/gxcapindicator.conf @@ -1,4 +1,6 @@ -[GXCapIndicator Configuration File, place default on /etc/gxcapindicator.conf] +[GXCapIndicator Configuration File] showcap=1 shownum=1 -updrate=0 +vcapstate=1 +vnumstate=1 +updrate=1 diff --git a/gxcapindicator.h b/gxcapindicator.h index b1076d9..29d39f3 100644 --- a/gxcapindicator.h +++ b/gxcapindicator.h @@ -1,12 +1,29 @@ #include #include -#include -#include + +#ifdef WITHX11 + #include + #include + Display *d; + XkbStateRec xkbcapstate; + XkbStateRec xkbnumstate; +#else + #include + #include + #include + #include + #include + struct libinput *libinput; + #include "evdevintegrity.h" + +#endif #include #define ML 256 +#define BUFFER_SIZE 1024 + GtkIconTheme *theme; GtkIconInfo *info; GdkPixbuf *icon; @@ -16,15 +33,12 @@ AppIndicator *capindicator, *numindicator; GtkWidget *capmenu, *capmenu_item_toggle,*capmenu_item_settings, *capmenu_item_about, *capmenu_item_quit, *nummenu, *nummenu_item_toggle,*nummenu_item_settings, *nummenu_item_about, *nummenu_item_quit, -*window, *gshowcap, *gshownum, *gupdrate, *dialog, *btn_savesettings, *grid, *btn_cancel; - -Display *d; +*window, *gshowcap, *gshownum, *gupdrate, *gnumstate, *gcapstate, *dialog, *btn_savesettings, *grid, *btn_cancel; pthread_t cap_threadid, num_threadid; +guint capstate=0, numstate=0, vcapstate=0, vnumstate=0, showcap=1, shownum=1, updrate=1, nohome=0, capvisible, numvisible, isx11; -guint capstate, numstate, showcap=1, shownum=1, updrate=1, nohome=0, capvisible, numvisible; - -gchar *pver="1.1", config_file_path[ML]; +gchar *pver="1.2", config_file_path[ML]; #include "threadmgr.h" #include "keyhandler.h" diff --git a/keyhandler.h b/keyhandler.h index 6b7726b..af26fb6 100644 --- a/keyhandler.h +++ b/keyhandler.h @@ -1,51 +1,130 @@ +#ifndef WITHX11 + + +// Event printing functions +static int print_key_event(struct libinput_event *event) +{ + struct libinput_event_keyboard *keyboard = libinput_event_get_keyboard_event(event); + + guint32 key_code = libinput_event_keyboard_get_key(keyboard); + enum libinput_key_state state_code = libinput_event_keyboard_get_key_state(keyboard); + + // Define el código de KEY_CAPSLOCK según libevdev + const guint32 KEY_CAPSLOCK_CODE = KEY_CAPSLOCK; // Asegúrate de incluir el header correcto para que KEY_CAPSLOCK esté definido + const guint32 KEY_NUMLOCK_CODE = KEY_NUMLOCK; + + if (showcap && key_code == KEY_CAPSLOCK_CODE && state_code == LIBINPUT_KEY_STATE_RELEASED) + { + capstate ^= 1; + const gchar *icon_name = capstate ? "keyboard-caps-enabled" : "keyboard-caps-disabled"; + const gchar *status_message = capstate ? "Caps Lock: Enabled" : "Caps Lock: Disabled"; + app_indicator_set_icon_full(capindicator, icon_name, status_message); + app_indicator_set_title(capindicator, status_message); + } + else if (shownum && key_code == KEY_NUMLOCK_CODE && state_code == LIBINPUT_KEY_STATE_RELEASED) + { + numstate ^=1; + const gchar *icon_name = numstate ? "keyboard-num-enabled" : "keyboard-num-disabled"; + const gchar *status_message = numstate ? "Num Lock: Enabled" : "Num Lock: Disabled"; + app_indicator_set_icon_full(numindicator, icon_name, status_message); + app_indicator_set_title(numindicator, status_message); + } + return 0; +} + + +static int handle_events(struct libinput *libinput) +{ + struct libinput_event *event; + + if (libinput_dispatch(libinput) < 0) + return -1; + + while ((event = libinput_get_event(libinput)) != NULL) + { + switch (libinput_event_get_type(event)) + { + case LIBINPUT_EVENT_KEYBOARD_KEY: + print_key_event(event); + break; + default: + break; + } + libinput_event_destroy(event); + } + return 0; +} + +static int run_mainloop(struct libinput *libinput) +{ + struct pollfd fd; + fd.fd = libinput_get_fd(libinput); + fd.events = POLLIN; + + while (poll(&fd, 1, -1) > -1) + handle_events(libinput); + return 0; +} +#endif + void *toggle_cap() { + #ifdef WITHX11 XkbGetIndicatorState(d, XkbUseCoreKbd, &capstate); int capsLock = (capstate & 0x01) != 0; XkbLockModifiers(d, XkbUseCoreKbd, LockMask, capsLock ? 0 : LockMask); return NULL; + #else + g_warning("not, implemented"); + #endif } void *check_cap() { - unsigned n; - XkbStateRec xkbState; - - while (1) - { - XkbGetState(d, XkbUseCoreKbd, &xkbState); - n = (xkbState.locked_mods & LockMask) ? 1 : 0; - const char *icon_name = n ? "keyboard-caps-enabled" : "keyboard-caps-disabled"; - const char *status_message = n ? "Caps Lock: Enabled" : "Caps Lock: Disabled"; - app_indicator_set_icon_full(capindicator, icon_name, status_message); - app_indicator_set_title(capindicator, status_message); - sleep(updrate); - } + #ifdef WITHX11 + XkbStateRec xkbState; + while (1) + { + XkbGetState(d, XkbUseCoreKbd, &xkbState); + capstate = (xkbState.locked_mods & LockMask) ? 1 : 0; + const gchar *icon_name = capstate ? "keyboard-caps-enabled" : "keyboard-caps-disabled"; + const gchar *status_message = capstate ? "Caps Lock: Enabled" : "Caps Lock: Disabled"; + app_indicator_set_icon_full(capindicator, icon_name, status_message); + app_indicator_set_title(capindicator, status_message); + sleep(updrate); + } + #else + run_mainloop(libinput); + #endif return NULL; } void *toggle_num() { + #ifdef WITHX11 XkbGetIndicatorState(d, XkbUseCoreKbd, &numstate); int numLock = (numstate & 0x02) != 0; XkbLockModifiers(d, XkbUseCoreKbd, Mod2Mask, numLock ? 0 : Mod2Mask); return NULL; + #else + g_warning("not, implemented"); + #endif } + void *check_num(void *arg) { - unsigned int n; - XkbStateRec xkbState; - +#ifdef WITHX11 while (1) { - XkbGetState(d, XkbUseCoreKbd, &xkbState); - n = (xkbState.locked_mods & Mod2Mask) ? 1 : 0; - const char *icon_name = n ? "keyboard-num-enabled" : "keyboard-num-disabled"; - const char *status_message = n ? "Num Lock: Enabled" : "Num Lock: Disabled"; + XkbGetState(d, XkbUseCoreKbd, &xkbnumstate); + numstate = (xkbnumstate.locked_mods & Mod2Mask) ? 1 : 0; + const gchar *icon_name = numstate ? "keyboard-num-enabled" : "keyboard-num-disabled"; + const gchar *status_message = numstate ? "Num Lock: Enabled" : "Num Lock: Disabled"; app_indicator_set_icon_full(numindicator, icon_name, status_message); app_indicator_set_title(numindicator, status_message); sleep(updrate); } return NULL; -} \ No newline at end of file +#endif +} diff --git a/mainwindow.h b/mainwindow.h index d6bc670..9aa0810 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -35,7 +35,9 @@ void create_cap_indicator() capmenu_item_settings = gtk_menu_item_new_with_label("Settings"); capmenu_item_about = gtk_menu_item_new_with_label("About"); capmenu_item_quit = gtk_menu_item_new_with_label("Quit"); + #ifdef WITHX11 gtk_menu_shell_append(GTK_MENU_SHELL(capmenu), capmenu_item_toggle); + #endif if (!nohome) gtk_menu_shell_append(GTK_MENU_SHELL(capmenu), capmenu_item_settings); gtk_menu_shell_append(GTK_MENU_SHELL(capmenu), capmenu_item_about); @@ -45,7 +47,14 @@ void create_cap_indicator() capindicator = app_indicator_new("gxcapindicator-capslock", "GXCapIndicator", APP_INDICATOR_CATEGORY_APPLICATION_STATUS); app_indicator_set_menu(capindicator, GTK_MENU(capmenu)); app_indicator_set_status(capindicator, APP_INDICATOR_STATUS_ACTIVE); - app_indicator_set_icon_full(capindicator, "image-loading-symbolic", "Caps Lock"); + #ifdef WITHX11 + app_indicator_set_icon_full(capindicator, "image-loading-symbolic", "Caps Lock"); + #else + const gchar *icon_name = vcapstate ? "keyboard-caps-enabled" : "keyboard-caps-disabled"; + const gchar *status_message = vcapstate ? "Caps Lock: Enabled" : "Caps Lock: Disabled"; + app_indicator_set_icon_full(capindicator, icon_name, status_message); + app_indicator_set_title(capindicator, status_message); + #endif g_signal_connect(G_OBJECT(capmenu_item_toggle), "activate", G_CALLBACK(toggle_cap), NULL); g_signal_connect(G_OBJECT(capmenu_item_settings), "activate", G_CALLBACK(on_preferences), NULL); @@ -68,7 +77,9 @@ void create_num_indicator() nummenu_item_settings = gtk_menu_item_new_with_label("Settings"); nummenu_item_about = gtk_menu_item_new_with_label("About"); nummenu_item_quit = gtk_menu_item_new_with_label("Quit"); - gtk_menu_shell_append(GTK_MENU_SHELL(nummenu), nummenu_item_toggle); + #ifdef WITHX11 + gtk_menu_shell_append(GTK_MENU_SHELL(nummenu), nummenu_item_toggle); + #endif if (!nohome) gtk_menu_shell_append(GTK_MENU_SHELL(nummenu), nummenu_item_settings); gtk_menu_shell_append(GTK_MENU_SHELL(nummenu), nummenu_item_about); @@ -77,8 +88,14 @@ void create_num_indicator() numindicator = app_indicator_new("gxcapindicator-numlock","GXCapIndicator",APP_INDICATOR_CATEGORY_APPLICATION_STATUS); app_indicator_set_menu(numindicator, GTK_MENU(nummenu)); app_indicator_set_status(numindicator, APP_INDICATOR_STATUS_ACTIVE); - app_indicator_set_icon_full(numindicator, "image-loading-symbolic", "Num Lock"); - + #ifdef WITHX11 + app_indicator_set_icon_full(numindicator, "image-loading-symbolic", "Num Lock"); + #else + const gchar *icon_name = vnumstate ? "keyboard-num-enabled" : "keyboard-num-disabled"; + const gchar *status_message = vnumstate ? "Num Lock: Enabled" : "Num Lock: Disabled"; + app_indicator_set_icon_full(numindicator, icon_name, status_message); + app_indicator_set_title(numindicator, status_message); + #endif g_signal_connect(G_OBJECT(nummenu_item_toggle), "activate", G_CALLBACK(toggle_num), NULL); g_signal_connect(G_OBJECT(nummenu_item_settings), "activate", G_CALLBACK(on_preferences), NULL); g_signal_connect(G_OBJECT(nummenu_item_about), "activate", G_CALLBACK(on_about), NULL); @@ -92,9 +109,11 @@ void create_num_indicator() void create_window() { + #ifdef WITHX11 d = XOpenDisplay(NULL); if (d == NULL) g_error("can't open display"); + #endif if (showcap) create_cap_indicator(); @@ -111,9 +130,11 @@ void create_window() pthread_join(cap_threadid, NULL); } + #ifdef WITHX11 if (shownum) { pthread_cancel(num_threadid); pthread_join(num_threadid, NULL); } + #endif } \ No newline at end of file diff --git a/settings.h b/settings.h index 482c716..d8269b7 100644 --- a/settings.h +++ b/settings.h @@ -45,6 +45,10 @@ void readconf() shownum = atoi(value_str); else if (strcmp(name, "updrate") == 0) updrate = atoi(value_str); + else if (strcmp(name, "vcapstate") == 0) + vcapstate = atoi(value_str); + else if (strcmp(name, "vnumstate") == 0) + vnumstate = atoi(value_str); } } fclose(file); @@ -76,6 +80,8 @@ void saveconfig() const gchar *cshowcap = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gshowcap)) ? "1" : "0"; const gchar *cshownum = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gshownum)) ? "1" : "0"; const gchar *cupdrate = gtk_entry_get_text(GTK_ENTRY(gupdrate)); + const gchar *cvcapstate = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gcapstate)) ? "1" : "0"; + const gchar *cvnumstate = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gnumstate)) ? "1" : "0"; if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gshowcap)) && !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gshownum))) { @@ -121,6 +127,8 @@ void saveconfig() fprintf(output, "[GXCapIndicator Configuration File]\n"); fprintf(output, "showcap=%s\n", cshowcap); fprintf(output, "shownum=%s\n", cshownum); + fprintf(output, "vcapstate=%s\n", cvcapstate); + fprintf(output, "vnumstate=%s\n", cvnumstate); fprintf(output, "updrate=%s\n", strlen(cupdrate) > 0 ? cupdrate : "1"); fclose(output); }