diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml new file mode 100644 index 0000000..c1c8b62 --- /dev/null +++ b/.github/workflows/c-cpp.yml @@ -0,0 +1,57 @@ +name: Continous CI + +permissions: + contents: write + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up variables + id: date + run: | + echo "GH_RELEASE_FILE=gxcapindicator-$(cat VERSION)-$(ldd --version | awk '/ldd/{print "-gnu-" $NF}')" >> $GITHUB_ENV + echo "GH_RELEASE_VERSION=$(cat VERSION)" >> $GITHUB_ENV + - name: Install Dependencies + run: | + sudo apt-get update + sudo apt-get install -y \ + build-essential \ + libgtk-3-dev \ + libayatana-appindicator3-dev \ + pkg-config \ + clang + + - name: Build with GCC + run: | + make CC=gcc + strip gxcapindicator + mv gxcapindicator ${{ env.GH_RELEASE_FILE }} + + - name: Build with Clang + run: | + make CC=clang + continue-on-error: true + + - name: Build with -Werror + run: | + make CFLAGS=-Werror + continue-on-error: true + + - name: Release + uses: softprops/action-gh-release@v2 + with: + name: Release ci-${{ env.GH_RELEASE_FILE }} + body: ${{ github.event.head_commit.message }} + tag_name: ${{ env.GH_RELEASE_FILE }} + files: | + ${{ env.GH_RELEASE_FILE }} \ No newline at end of file diff --git a/Makefile b/Makefile index aa06954..5ec4e89 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ -CC = gcc -CFLAGS = `pkg-config --cflags gtk+-3.0 ayatana-appindicator3-0.1` -Wall -lpthread -lX11 -LIBS = `pkg-config --libs gtk+-3.0 ayatana-appindicator3-0.1` -Wall -lpthread -lX11 +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 SRC = gxcapindicator.c OBJ = $(SRC:.c=.o) @@ -21,19 +21,17 @@ clean: rm -f $(OBJ) $(EXE) debug install: $(EXE) - install -Dm755 $(EXE) /usr/bin/$(EXE) - install -Dm755 gxcapindicator.desktop /usr/share/applications/gxcapindicator.desktop - install -Dm644 gxcapindicator.conf /etc/gxcapindicator.conf - install -Dm644 icons/keyboard-caps-disabled.svg /usr/share/icons/hicolor/32x32/devices/keyboard-caps-disabled.svg - install -Dm644 icons/keyboard-caps-enabled.svg /usr/share/icons/hicolor/32x32/devices/keyboard-caps-enabled.svg - install -Dm644 icons/keyboard-num-disabled.svg /usr/share/icons/hicolor/32x32/devices/keyboard-num-disabled.svg - install -Dm644 icons/keyboard-num-enabled.svg /usr/share/icons/hicolor/32x32/devices/keyboard-num-enabled.svg + install -Dm755 $(EXE) /usr/local/bin/$(EXE) + install -Dm755 gxcapindicator.desktop /usr/local/share/applications/gxcapindicator.desktop + install -Dm644 icons/keyboard-caps-disabled.svg /usr/local/share/icons/hicolor/32x32/devices/keyboard-caps-disabled.svg + install -Dm644 icons/keyboard-caps-enabled.svg /usr/local/share/icons/hicolor/32x32/devices/keyboard-caps-enabled.svg + install -Dm644 icons/keyboard-num-disabled.svg /usr/local/share/icons/hicolor/32x32/devices/keyboard-num-disabled.svg + install -Dm644 icons/keyboard-num-enabled.svg /usr/local/share/icons/hicolor/32x32/devices/keyboard-num-enabled.svg uninstall: - rm -f /usr/bin/$(EXE) - rm -f /usr/share/applications/gxcapindicator.desktop - rm -f /etc/gxcapindicator.conf - rm -f /usr/share/icons/hicolor/32x32/devices/keyboard-caps-disabled.svg - rm -f /usr/share/icons/hicolor/32x32/devices/keyboard-caps-enabled.svg - rm -f /usr/share/icons/hicolor/32x32/devices/keyboard-num-disabled.svg - rm -f /usr/share/icons/hicolor/32x32/devices/keyboard-num-enabled.svg + rm -f /usr/local/bin/$(EXE) + rm -f /usr/local/share/applications/gxcapindicator.desktop + 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 diff --git a/README.md b/README.md index 1ac52cc..9fa5ba3 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,8 @@ # gxcapindicator + +Description of Image + + Simple Cap/Num lock key indicator for x11 tray ## Features: diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..9459d4b --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +1.1 diff --git a/cfgmgr.h b/cfgmgr.h new file mode 100644 index 0000000..361ad0e --- /dev/null +++ b/cfgmgr.h @@ -0,0 +1,56 @@ +void cancelconfig() +{ + gtk_widget_destroy(dialog); +} + +void on_preferences(GtkWidget *button, gpointer data) +{ + dialog = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER); + gtk_window_set_title(GTK_WINDOW(dialog), "GXCapIndicator Settings"); + + theme = gtk_icon_theme_get_default(); + info = gtk_icon_theme_lookup_icon(theme, "keyboard-caps-enabled", 48, 0); + if (info != NULL) + { + icon = gtk_icon_info_load_icon(info, NULL); + gtk_window_set_icon(GTK_WINDOW(dialog), icon); + g_object_unref(icon); + g_object_unref(info); + } + + gtk_container_set_border_width(GTK_CONTAINER(dialog), 5); + + grid = gtk_grid_new(); + gtk_container_add(GTK_CONTAINER(dialog), grid); + gtk_grid_set_column_homogeneous(GTK_GRID(grid), TRUE); + gtk_grid_set_row_homogeneous(GTK_GRID(grid), TRUE); + + gshowcap = gtk_check_button_new(); + gshownum = gtk_check_button_new(); + gupdrate = gtk_entry_new(); + + btn_cancel = gtk_button_new_with_label("cancel"); + btn_savesettings = gtk_button_new_with_label("save"); + + gtk_grid_attach(GTK_GRID(grid), gtk_label_new("Show Caps Lock:"), 0, 0, 1, 1); + 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); + 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); + 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); + + char buffer[32]; + snprintf(buffer, sizeof(buffer), "%d", updrate); + gtk_entry_set_text(GTK_ENTRY(gupdrate), buffer); + + g_signal_connect(btn_cancel, "clicked", G_CALLBACK(cancelconfig), NULL); + g_signal_connect(btn_savesettings, "clicked", G_CALLBACK(saveconfig), dialog); + gtk_widget_show_all(dialog); + gtk_main(); +} diff --git a/gxcapindicator.c b/gxcapindicator.c index 9422796..109c17d 100644 --- a/gxcapindicator.c +++ b/gxcapindicator.c @@ -3,80 +3,6 @@ int main(int argc, char *argv[]) { readconf(); - - printf("num=%d cap=%d", shownum, showcap); - pthread_t thread_id; - if (pthread_create(&thread_id, NULL, check_caps_lock, NULL) != 0) - { - fprintf(stderr, "Error creating thread\n"); - return 1; - } - - if (pthread_create(&thread_id, NULL, check_num_lock, NULL) != 0) - { - fprintf(stderr, "Error creating thread\n"); - return 1; - } - gtk_init(&argc, &argv); - - // Cap Tray Icon - indicator = app_indicator_new("gxcapindicator-capslock", "GXCapIndicator", APP_INDICATOR_CATEGORY_APPLICATION_STATUS); - if (showcap) - { - app_indicator_set_status(indicator, APP_INDICATOR_STATUS_ACTIVE); - } - app_indicator_set_icon_full(indicator, "image-loading-symbolic", "Caps Lock"); - - traymenu = gtk_menu_new(); - traymenu_item1 = gtk_menu_item_new_with_label("Toggle Caps Lock"); - traymenu_item2 = gtk_menu_item_new_with_label("Settings"); - traymenu_item3 = gtk_menu_item_new_with_label("About"); - traymenu_item4 = gtk_menu_item_new_with_label("Quit"); - gtk_menu_shell_append(GTK_MENU_SHELL(traymenu), traymenu_item1); - gtk_menu_shell_append(GTK_MENU_SHELL(traymenu), traymenu_item2); - gtk_menu_shell_append(GTK_MENU_SHELL(traymenu), traymenu_item3); - gtk_menu_shell_append(GTK_MENU_SHELL(traymenu), traymenu_item4); - gtk_widget_show_all(traymenu); - app_indicator_set_menu(indicator, GTK_MENU(traymenu)); - - - // Num Tray Icon - indicator2 = app_indicator_new("gxcapindicator-numlock","GXCapIndicator",APP_INDICATOR_CATEGORY_APPLICATION_STATUS); - if (shownum) - { - app_indicator_set_status(indicator2, APP_INDICATOR_STATUS_ACTIVE); - } - app_indicator_set_label(indicator2, "Indicator 2", NULL); - app_indicator_set_icon_full(indicator2, "image-loading-symbolic", "Num Lock"); - - traymenu2 = gtk_menu_new(); - traymenu_item11 = gtk_menu_item_new_with_label("Toggle Num Lock"); - traymenu_item12 = gtk_menu_item_new_with_label("Settings"); - traymenu_item13 = gtk_menu_item_new_with_label("About"); - traymenu_item14 = gtk_menu_item_new_with_label("Quit"); - gtk_menu_shell_append(GTK_MENU_SHELL(traymenu2), traymenu_item11); - gtk_menu_shell_append(GTK_MENU_SHELL(traymenu2), traymenu_item12); - gtk_menu_shell_append(GTK_MENU_SHELL(traymenu2), traymenu_item13); - gtk_menu_shell_append(GTK_MENU_SHELL(traymenu2), traymenu_item14); - gtk_widget_show_all(traymenu2); - app_indicator_set_menu(indicator2, GTK_MENU(traymenu2)); - - - g_signal_connect(G_OBJECT(traymenu_item1), "activate", G_CALLBACK(toggle_cap), NULL); - g_signal_connect(G_OBJECT(traymenu_item2), "activate", G_CALLBACK(on_preferences), NULL); - g_signal_connect(G_OBJECT(traymenu_item3), "activate", G_CALLBACK(on_about), NULL); - g_signal_connect(G_OBJECT(traymenu_item4), "activate", G_CALLBACK(quit_app), NULL); - - g_signal_connect(G_OBJECT(traymenu_item11), "activate", G_CALLBACK(toggle_num), NULL); - g_signal_connect(G_OBJECT(traymenu_item12), "activate", G_CALLBACK(on_preferences), NULL); - g_signal_connect(G_OBJECT(traymenu_item13), "activate", G_CALLBACK(on_about), NULL); - g_signal_connect(G_OBJECT(traymenu_item14), "activate", G_CALLBACK(quit_app), NULL); - - gtk_main(); - - pthread_cancel(thread_id); - pthread_join(thread_id, NULL); - - return 0; -} + create_window(); +} \ No newline at end of file diff --git a/gxcapindicator.h b/gxcapindicator.h index de5ab4d..b1076d9 100644 --- a/gxcapindicator.h +++ b/gxcapindicator.h @@ -7,151 +7,27 @@ #define ML 256 -AppIndicator *indicator; -AppIndicator *indicator2; - GtkIconTheme *theme; GtkIconInfo *info; GdkPixbuf *icon; -GtkWidget *window, *traymenu, *traymenu_item1,*traymenu_item2, *traymenu_item3,*traymenu_item4, - *traymenu2, *traymenu_item11,*traymenu_item12, *traymenu_item13, *traymenu_item14; - -char *pver="1.0"; - -#include "settings.h" - -static void quit_app(GtkWidget *widget, gpointer data) -{ - gtk_main_quit(); -} - -void *toggle_cap() -{ - Display *d; - unsigned int state; - - d = XOpenDisplay(NULL); - if (d == NULL) - { - fprintf(stderr, "can't open display\n"); - } - - XkbGetIndicatorState(d, XkbUseCoreKbd, &state); - - int capsLock = (state & 0x01) != 0; +AppIndicator *capindicator, *numindicator; - XkbLockModifiers(d, XkbUseCoreKbd, LockMask, capsLock ? 0 : LockMask); - XCloseDisplay(d); - return NULL; -} +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, -void* check_caps_lock(void* arg) -{ - Display *d; - unsigned n; - XkbStateRec xkbState; +*window, *gshowcap, *gshownum, *gupdrate, *dialog, *btn_savesettings, *grid, *btn_cancel; - d = XOpenDisplay(NULL); - if (d == NULL) - { - fprintf(stderr, "can't open display\n"); - return NULL; - } +Display *d; - while (1) - { - XkbGetState(d, XkbUseCoreKbd, &xkbState); - n = (xkbState.locked_mods & LockMask) ? 1 : 0; - if (n) - { - app_indicator_set_icon_full(indicator, "keyboard-caps-enabled", "Caps Lock: Disabled"); - } - else - { - app_indicator_set_icon_full(indicator, "keyboard-caps-disabled", "Caps Lock: Enabled"); - } - sleep(updrate); - } - XCloseDisplay(d); - return NULL; -} +pthread_t cap_threadid, num_threadid; -void *toggle_num() -{ - Display *d; - unsigned int state; +guint capstate, numstate, showcap=1, shownum=1, updrate=1, nohome=0, capvisible, numvisible; - d = XOpenDisplay(NULL); - if (d == NULL) - { - fprintf(stderr, "can't open display\n"); - return NULL; - } +gchar *pver="1.1", config_file_path[ML]; - XkbGetIndicatorState(d, XkbUseCoreKbd, &state); - - int numLock = (state & 0x02) != 0; - - XkbLockModifiers(d, XkbUseCoreKbd, Mod2Mask, numLock ? 0 : Mod2Mask); - XCloseDisplay(d); - return NULL; -} - -void* check_num_lock(void* arg) -{ - Display *d; - unsigned int n; - XkbStateRec xkbState; - - d = XOpenDisplay(NULL); - if (d == NULL) - { - fprintf(stderr, "can't open display\n"); - return NULL; - } - - while (1) - { - XkbGetState(d, XkbUseCoreKbd, &xkbState); - n = (xkbState.locked_mods & Mod2Mask) ? 1 : 0; - - if (n) - { - app_indicator_set_icon_full(indicator2, "keyboard-num-enabled", "Num Lock: Enabled"); - } - else - { - app_indicator_set_icon_full(indicator2, "keyboard-num-disabled", "Num Lock: Disabled"); - } - sleep(updrate); - } - XCloseDisplay(d); - return NULL; -} - -void on_about(GtkMenuItem *menuitem, gpointer userdata) -{ - dialog = gtk_about_dialog_new(); - gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER); - theme = gtk_icon_theme_get_default(); - info = gtk_icon_theme_lookup_icon(theme, "keyboard-caps-enabled", 48, 0); - if (info != NULL) - { - icon = gtk_icon_info_load_icon(info, NULL); - gtk_window_set_icon(GTK_WINDOW(dialog), icon); - g_object_unref(icon); - g_object_unref(info); - } - gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(dialog), "GXCapIndicator"); - gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(dialog), "Copyright © 2024 ItzSelenux"); - gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(dialog), "Simple Cap/Num lock indicator for X11 Tray"); - gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(dialog), pver); - gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(dialog), "https://github.com/itzselenux/gxcapindicator"); - gtk_about_dialog_set_website_label(GTK_ABOUT_DIALOG(dialog), "Project WebSite"); - gtk_about_dialog_set_license_type(GTK_ABOUT_DIALOG(dialog),GTK_LICENSE_GPL_3_0); - gtk_about_dialog_set_logo_icon_name(GTK_ABOUT_DIALOG(dialog),"keyboard-caps-enabled"); - - gtk_dialog_run(GTK_DIALOG(dialog)); - gtk_widget_destroy(dialog); -} \ No newline at end of file +#include "threadmgr.h" +#include "keyhandler.h" +#include "settings.h" +#include "cfgmgr.h" +#include "mainwindow.h" \ No newline at end of file diff --git a/keyhandler.h b/keyhandler.h new file mode 100644 index 0000000..6b7726b --- /dev/null +++ b/keyhandler.h @@ -0,0 +1,51 @@ +void *toggle_cap() +{ + XkbGetIndicatorState(d, XkbUseCoreKbd, &capstate); + int capsLock = (capstate & 0x01) != 0; + XkbLockModifiers(d, XkbUseCoreKbd, LockMask, capsLock ? 0 : LockMask); + return NULL; +} + +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); + } + return NULL; +} + +void *toggle_num() +{ + XkbGetIndicatorState(d, XkbUseCoreKbd, &numstate); + int numLock = (numstate & 0x02) != 0; + XkbLockModifiers(d, XkbUseCoreKbd, Mod2Mask, numLock ? 0 : Mod2Mask); + return NULL; +} + +void *check_num(void *arg) +{ + unsigned int n; + XkbStateRec xkbState; + + 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"; + 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 diff --git a/mainwindow.h b/mainwindow.h new file mode 100644 index 0000000..d6bc670 --- /dev/null +++ b/mainwindow.h @@ -0,0 +1,119 @@ +void on_about(GtkMenuItem *menuitem, gpointer userdata) +{ + dialog = gtk_about_dialog_new(); + gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER); + theme = gtk_icon_theme_get_default(); + info = gtk_icon_theme_lookup_icon(theme, "keyboard-caps-enabled", 48, 0); + if (info != NULL) + { + icon = gtk_icon_info_load_icon(info, NULL); + gtk_window_set_icon(GTK_WINDOW(dialog), icon); + g_object_unref(icon); + g_object_unref(info); + } + gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(dialog), "GXCapIndicator"); + gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(dialog), "Copyright © 2024 ItzSelenux"); + gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(dialog), "Simple Cap/Num lock indicator for X11 Tray"); + gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(dialog), pver); + gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(dialog), "https://github.com/itzselenux/gxcapindicator"); + gtk_about_dialog_set_website_label(GTK_ABOUT_DIALOG(dialog), "Project WebSite"); + gtk_about_dialog_set_license_type(GTK_ABOUT_DIALOG(dialog),GTK_LICENSE_GPL_3_0); + gtk_about_dialog_set_logo_icon_name(GTK_ABOUT_DIALOG(dialog),"keyboard-caps-enabled"); + + gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); +} + +void create_cap_indicator() +{ + if (capvisible) + return; + capvisible = 1; + + capmenu = gtk_menu_new(); + capmenu_item_toggle = gtk_menu_item_new_with_label("Toggle Caps Lock"); + 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"); + gtk_menu_shell_append(GTK_MENU_SHELL(capmenu), capmenu_item_toggle); + if (!nohome) + gtk_menu_shell_append(GTK_MENU_SHELL(capmenu), capmenu_item_settings); + gtk_menu_shell_append(GTK_MENU_SHELL(capmenu), capmenu_item_about); + gtk_menu_shell_append(GTK_MENU_SHELL(capmenu), capmenu_item_quit); + gtk_widget_show_all(capmenu); + + 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"); + + 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); + g_signal_connect(G_OBJECT(capmenu_item_about), "activate", G_CALLBACK(on_about), NULL); + g_signal_connect(G_OBJECT(capmenu_item_quit), "activate", G_CALLBACK(gtk_main_quit), NULL); + if (pthread_create(&cap_threadid, NULL, check_cap, NULL) != 0) + { + g_error("Error creating thread."); + return; + } +} + +void create_num_indicator() +{ + if (numvisible) + return; + numvisible = 1; + nummenu = gtk_menu_new(); + nummenu_item_toggle = gtk_menu_item_new_with_label("Toggle Num Lock"); + 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); + if (!nohome) + gtk_menu_shell_append(GTK_MENU_SHELL(nummenu), nummenu_item_settings); + gtk_menu_shell_append(GTK_MENU_SHELL(nummenu), nummenu_item_about); + gtk_menu_shell_append(GTK_MENU_SHELL(nummenu), nummenu_item_quit); + gtk_widget_show_all(nummenu); + 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"); + + 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); + g_signal_connect(G_OBJECT(nummenu_item_quit), "activate", G_CALLBACK(gtk_main_quit), NULL); + if (pthread_create(&num_threadid, NULL, check_num, NULL) != 0) + { + g_error("Error creating thread."); + return; + } +} + +void create_window() +{ + d = XOpenDisplay(NULL); + if (d == NULL) + g_error("can't open display"); + + if (showcap) + create_cap_indicator(); + + + if (shownum) + create_num_indicator(); + + gtk_main(); + + if (showcap) + { + pthread_cancel(cap_threadid); + pthread_join(cap_threadid, NULL); + } + + if (shownum) + { + pthread_cancel(num_threadid); + pthread_join(num_threadid, NULL); + } +} \ No newline at end of file diff --git a/settings.h b/settings.h index 3b4a036..482c716 100644 --- a/settings.h +++ b/settings.h @@ -1,112 +1,76 @@ -int showcap, shownum, updrate; -char config_file_path[ML]; - -GtkWidget *gshowcap, *gshownum, *gupdrate, *dialog, -*box,*filechooser_syslinuxpath, *btn_savesettings,*notebook, *colorsgrid, *dialog, *grid, *btn_cancel; - - -void on_btn_cancel_clicked(GtkWidget *widget, gpointer data) -{ - gtk_widget_destroy(GTK_WIDGET(data)); -} +void create_num_indicator(); +void create_cap_indicator(); void readconf() { - //READ THE CONF char *home_dir = getenv("HOME"); if (home_dir == NULL) { - fprintf(stderr, "Error: HOME environment variable is not set.\n"); - exit(1); + g_warning("HOME environment variable is not set."); + nohome = 1; + return; } snprintf(config_file_path, sizeof(config_file_path), "%s/.config/gxcapindicator.conf", home_dir); FILE *file = fopen(config_file_path, "r"); + if (file == NULL) { + file = fopen(config_file_path, "w"); if (file == NULL) { - FILE *default_conf = fopen("/etc/gxcapindicator.conf", "r"); - if (default_conf == NULL) - { - fprintf(stderr, "Error: could not open default configuration file /etc/gxcapindicator.conf, please reinstall the program or put a config file in ~/.config/gxcapindicator.conf.\n"); - exit(1); - } - - file = fopen(config_file_path, "w"); - if (file == NULL) - { - fprintf(stderr, "Error: could not create %s for writing.\n", config_file_path); - exit(1); - } - - int ch; - while ((ch = fgetc(default_conf)) != EOF) - { - fputc(ch, file); - } - fclose(default_conf); - printf("Default configuration file copied to %s.\n", config_file_path); + g_warning("could not open %s for writing.", config_file_path); + nohome = 1; + return; } else { fclose(file); - printf("%s exists and can be read.\n", config_file_path); + return; } } char line[ML]; - if (file != NULL) + while (fgets(line, ML, file) != NULL) { - // Read each line from the file and parse the variable assignments - while (fgets(line, ML, file) != NULL) - { - char *name = strtok(line, "="); - char *value_str = strtok(NULL, "="); + char *name = strtok(line, "="); + char *value_str = strtok(NULL, "="); - if (name != NULL && value_str != NULL) - { - if (strcmp(name, "showcap") == 0) - showcap = atoi(value_str); - else if (strcmp(name, "shownum") == 0) - shownum = atoi(value_str); - else if (strcmp(name, "updrate") == 0) - updrate = atoi(value_str); - } + if (name != NULL && value_str != NULL) + { + if (strcmp(name, "showcap") == 0) + showcap = atoi(value_str); + else if (strcmp(name, "shownum") == 0) + shownum = atoi(value_str); + else if (strcmp(name, "updrate") == 0) + updrate = atoi(value_str); } - fclose(file); - } - else - { - printf("Error opening file"); } + fclose(file); } + void reset(GtkWidget *widget) { readconf(); + app_indicator_set_status(capindicator, showcap ? APP_INDICATOR_STATUS_ACTIVE : APP_INDICATOR_STATUS_PASSIVE); + app_indicator_set_status(numindicator, shownum ? APP_INDICATOR_STATUS_ACTIVE : APP_INDICATOR_STATUS_PASSIVE); - if (!showcap) + if (showcap) { - app_indicator_set_status(indicator, APP_INDICATOR_STATUS_PASSIVE); - } - else - { - app_indicator_set_status(indicator, APP_INDICATOR_STATUS_ACTIVE); + create_cap_indicator(); + cleanup_thread(&cap_threadid, &cap_thread_active); } - if (!shownum) - { - app_indicator_set_status(indicator2, APP_INDICATOR_STATUS_PASSIVE); - } - else + if (shownum) { - app_indicator_set_status(indicator2, APP_INDICATOR_STATUS_ACTIVE); + create_num_indicator(); + cleanup_thread(&num_threadid, &num_thread_active); } - } + void saveconfig() { const gchar *cshowcap = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gshowcap)) ? "1" : "0"; @@ -115,12 +79,21 @@ void saveconfig() if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gshowcap)) && !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gshownum))) { - GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(window), + dialog = gtk_message_dialog_new(GTK_WINDOW(window), GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "ERROR: Invalid Situation\n\nIs not possible to have both 'shownum' and 'showcap' as FALSE"); gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER); + + info = gtk_icon_theme_lookup_icon(theme, "dialog-error", 48, 0); + if (info != NULL) + { + icon = gtk_icon_info_load_icon(info, NULL); + gtk_window_set_icon(GTK_WINDOW(dialog), icon); + g_object_unref(icon); + g_object_unref(info); + } gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(dialog); return; @@ -130,78 +103,27 @@ void saveconfig() output = fopen(config_file_path, "w"); if (output == NULL) { - g_printerr("\033[1;31mERROR\033[0m: Process running but config does not exist, did you moved the file?\n"); - gtk_main_quit(); - } - else - { - fprintf(output, "[GXCapIndicator Configuration File, place default on /etc/gxcapindicator.conf]\n"); - fprintf(output, "showcap=%s\n", cshowcap); - fprintf(output, "shownum=%s\n", cshownum); - - if (strlen(cupdrate) > 0) + output = fopen(config_file_path, "w"); + if (output == NULL) { - fprintf(output, "updrate=%s\n", cupdrate); + g_warning("could not open %s for writing.", config_file_path); + nohome = 1; + return; } else { - fprintf(output, "updrate=1\n"); + fclose(output); + return; } + } + else + { + fprintf(output, "[GXCapIndicator Configuration File]\n"); + fprintf(output, "showcap=%s\n", cshowcap); + fprintf(output, "shownum=%s\n", cshownum); + fprintf(output, "updrate=%s\n", strlen(cupdrate) > 0 ? cupdrate : "1"); fclose(output); } reset(window); gtk_widget_destroy(GTK_WIDGET(dialog)); -} - -void on_preferences(GtkWidget *button, gpointer data) -{ - gtk_init(NULL, NULL); - dialog = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER); - gtk_window_set_title(GTK_WINDOW(dialog), "GXCapIndicator Settings"); - - theme = gtk_icon_theme_get_default(); - info = gtk_icon_theme_lookup_icon(theme, "keyboard-caps-enabled", 48, 0); - if (info != NULL) - { - icon = gtk_icon_info_load_icon(info, NULL); - gtk_window_set_icon(GTK_WINDOW(dialog), icon); - g_object_unref(icon); - g_object_unref(info); - } - g_signal_connect(dialog, "destroy", G_CALLBACK(gtk_main_quit), NULL); - gtk_container_set_border_width(GTK_CONTAINER(dialog), 5); - - grid = gtk_grid_new(); - gtk_container_add(GTK_CONTAINER(dialog), grid); - gtk_grid_set_column_homogeneous(GTK_GRID(grid), TRUE); - gtk_grid_set_row_homogeneous(GTK_GRID(grid), TRUE); - - gshowcap = gtk_check_button_new(); - gshownum = gtk_check_button_new(); - gupdrate = gtk_entry_new(); - - btn_cancel = gtk_button_new_with_label("cancel"); - btn_savesettings = gtk_button_new_with_label("save"); - - gtk_grid_attach(GTK_GRID(grid), gtk_label_new("Show Caps Lock:"), 0, 0, 1, 1); - 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); - 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); - 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); - - char buffer[32]; - snprintf(buffer, sizeof(buffer), "%d", updrate); - gtk_entry_set_text(GTK_ENTRY(gupdrate), buffer); - - g_signal_connect(btn_cancel, "clicked", G_CALLBACK(on_btn_cancel_clicked), dialog); - g_signal_connect(btn_savesettings, "clicked", G_CALLBACK(saveconfig), dialog); - gtk_widget_show_all(dialog); - gtk_main(); } \ No newline at end of file diff --git a/threadmgr.h b/threadmgr.h new file mode 100644 index 0000000..e49ba1b --- /dev/null +++ b/threadmgr.h @@ -0,0 +1,28 @@ + gboolean cap_thread_active = FALSE; + gboolean num_thread_active = FALSE; + +void create_cap_thread(void *(*start_routine)(void *)) +{ + if (pthread_create(&cap_threadid, NULL, start_routine, NULL) == 0) + { + cap_thread_active = TRUE; + } +} + +void create_num_thread(void *(*start_routine)(void *)) +{ + if (pthread_create(&num_threadid, NULL, start_routine, NULL) == 0) + { + num_thread_active = TRUE; + } +} + +void cleanup_thread(pthread_t *thread, gboolean *active) +{ + if (*active) + { + pthread_cancel(*thread); + pthread_join(*thread, NULL); + *active = TRUE; + } +}