Compare commits

..

No commits in common. "master" and "v1.6" have entirely different histories.
master ... v1.6

6 changed files with 133 additions and 214 deletions

View File

@ -2,11 +2,8 @@
CC = gcc CC = gcc
# Compiler and optimization flags # Compiler and optimization flags
CFLAGS ?= -Wall -O2 CFLAGS = `pkg-config --cflags gtk+-3.0` -O3
CFLAGS += $(shell pkg-config --cflags gtk4) LDFLAGS = `pkg-config --libs gtk+-3.0`
CFLAGS += -DGDK_VERSION_MAX_ALLOWED=GDK_VERSION_4_0 -DGDK_VERSION_MIN_REQUIRED=GDK_VERSION_4_0
LDFLAGS ?=
LDFLAGS += $(shell pkg-config --libs gtk4)
# Source files # Source files
SRC = ssdd.c resources.c SRC = ssdd.c resources.c
@ -38,15 +35,15 @@ $(RESOURCE_C) $(RESOURCE_H): $(RESOURCE_XML)
# Install target # Install target
install: $(TARGET) install: $(TARGET)
install -d $(DESTDIR)$(BINDIR) install -d $(BINDIR)
install -m 755 $(TARGET) $(DESTDIR)$(BINDIR) install -m 755 $(TARGET) $(BINDIR)
install -d $(DESTDIR)$(DATADIR) install -d $(DATADIR)
install -m 644 $(RESOURCE_XML) $(DESTDIR)$(DATADIR) install -m 644 $(RESOURCE_XML) $(DATADIR)
# Uninstall target # Uninstall target
uninstall: uninstall:
rm -f $(DESTDIR)$(BINDIR)/$(TARGET) rm -f $(BINDIR)/$(TARGET)
rm -rf $(DESTDIR)$(DATADIR) rm -rf $(DATADIR)
# Clean target # Clean target
clean: clean:

View File

@ -1,14 +1,12 @@
# ssdd: Simple Shutdown Dialog for Openbox # ssdd: Simple Shutdown Dialog for Openbox
A simple Shutdown Dialog for Openbox written in C using GTK 4 A simple Shutdown Dialog for Openbox written in C using GTK
![Project Screenshot](ssdd.png) ![Project Screenshot](ssdd.png)
![Settings screenshot](ssdd-settings.png) ![Settings screenshot](ssdd-settings.png)
![Settings screenshot](ssdd-about.png) **Simple Shutdown Dialog (ssdd)** is a simple yet stylish shutdown dialog for Openbox, crafted in C using GTK.
**Simple Shutdown Dialog (ssdd)** is a simple yet stylish shutdown dialog for Openbox, crafted in C using GTK 4.
## Why ssdd? ## Why ssdd?
@ -18,16 +16,15 @@ Inspired by the elegant `ssd` from Sawfish, I decided to create my own tailored
## Features ## Features
- **Clean and Intuitive Interface:** ssdd presents clear options for Logout, Reboot, Shutdown, Switch User, Suspend, Hibernate, Settings, and Exit. * **Clean and Intuitive Interface:** ssdd presents a clear choice between Shutdown, Reboot, Logout, and Exit options.
- **Configurable Commands:** Easily customize the commands executed for each action via the settings dialog. * **Clean and minimal code:** `ssdd` is built on a clean and minimal codebase, making it easy to maintain, understand, and extend.
- **Lightweight and Efficient:** Designed to be fast and resource-friendly, perfectly suited for Openbox's minimalist philosophy. * **Lightweight and Efficient:** ssdd is designed to be fast and resource-friendly, perfectly suited for Openbox's minimalist philosophy.
- **Modern GTK 4 Interface:** Built with GTK 4 for a modern look and feel.
## Dependencies and Compilation ## Dependencies and Compilation
ssdd requires: ssdd requires:
* GTK 4 development libraries * GTK+ 3.0
* Glib 2 development libraries * Glib 2 development libraries
* gcc or clang * gcc or clang
@ -52,10 +49,10 @@ First generate the resources.
```bash ```bash
# Using GCC: # Using GCC:
% gcc ssdd.c resources.c -o ssdd `pkg-config --cflags --libs gtk4` % gcc ssdd.c resources.c -o ssdd `pkg-config --cflags --libs gtk+-3.0`
# Using Clang: # Using Clang:
% clang ssdd.c resources.c -o ssdd `pkg-config --cflags --libs gtk4` % clang ssdd.c resources.c -o ssdd `pkg-config --cflags --libs gtk+-3.0`
``` ```
Place the `ssdd` binary in your `$PATH` (e.g., `~/bin`). Place the `ssdd` binary in your `$PATH` (e.g., `~/bin`).
@ -83,4 +80,3 @@ Place the `ssdd` binary in your `$PATH` (e.g., `~/bin`).
### Contributing ### Contributing
Contributions are welcome! Feel free to open issues or submit pull requests. Contributions are welcome! Feel free to open issues or submit pull requests.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 30 KiB

302
ssdd.c
View File

@ -1,93 +1,74 @@
#include <gtk/gtk.h> #include <gtk/gtk.h>
#include <glib.h>
#include <glib/gstdio.h> #include <glib/gstdio.h>
#include <stdlib.h>
#include <string.h>
#include "resources.h" #include "resources.h"
// Function declarations // Function declarations (prototypes)
static void execute_command(const gchar *command, GtkWindow *parent); static void execute_command(const gchar *command);
static void show_settings_dialog(GtkWindow *parent); static void show_settings_dialog(GtkWidget *widget);
static void show_about_tab(GtkWidget *box); static void show_about_tab(GtkWidget *box);
static void show_settings_tab(GtkWidget *box); static void show_settings_tab(GtkWidget *box);
static void button_clicked(GtkWidget *widget, gpointer data); static void button_clicked(GtkWidget *widget, gpointer data);
static gboolean on_key_pressed(GtkEventControllerKey *controller, guint keyval, guint keycode, GdkModifierType state, gpointer user_data); static gboolean on_key_press(GtkWidget *widget, GdkEventKey *event, gpointer data);
static void show_confirmation_dialog(GtkWindow *parent_window, const gchar *label, const gchar *command); static void show_confirmation_dialog(GtkWidget *widget, const gchar *label, const gchar *command);
static void create_button(GtkWidget *grid, GtkApplication *app, const gchar *label_text, const gchar *icon_name, const gchar *command, int pos); static void create_button(GtkWidget *grid, GtkApplication *app, const gchar *label_text, const gchar *icon_name, const gchar *command, int pos);
static void save_configuration(const gchar *commands[]); static void save_configuration(const gchar *commands[]);
static void load_configuration(gchar *commands[]); static void load_configuration(gchar *commands[]);
static gchar *get_config_path(void);
static gchar *get_config_dir(void);
static void on_save_button_clicked(GtkButton *button, gpointer user_data);
static void on_confirmation_response(GtkDialog *dialog, gint response_id, gpointer user_data);
static gchar *get_config_dir(void) { #define CONFIG_PATH g_build_filename(g_get_home_dir(), ".config/ssdd/config", NULL)
return g_build_filename(g_get_user_config_dir(), "ssdd", NULL); #define CONFIG_DIR g_build_filename(g_get_home_dir(), ".config/ssdd", NULL)
}
static gchar *get_config_path(void) { static void execute_command(const gchar *command) {
return g_build_filename(g_get_user_config_dir(), "ssdd", "config", NULL);
}
static void execute_command(const gchar *command, GtkWindow *parent) {
GError *error = NULL; GError *error = NULL;
gboolean ret = g_spawn_command_line_async(command, &error); gboolean ret = g_spawn_command_line_async(command, &error);
if (!ret) { if (!ret) {
gchar *error_message = g_strdup_printf("Error executing command '%s': %s", command, error->message); GtkWidget *dialog;
dialog = gtk_message_dialog_new(NULL,
GtkWidget *dialog = gtk_message_dialog_new(parent, GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_DIALOG_MODAL,
GTK_MESSAGE_ERROR, GTK_MESSAGE_ERROR,
GTK_BUTTONS_CLOSE, GTK_BUTTONS_CLOSE,
"%s", error_message); "Error executing command: %s\n%s",
g_signal_connect(dialog, "response", G_CALLBACK(gtk_window_destroy), NULL); command,
gtk_window_present(GTK_WINDOW(dialog)); error->message);
gtk_dialog_run(GTK_DIALOG(dialog));
g_free(error_message); gtk_widget_destroy(dialog);
g_error_free(error); g_error_free(error);
} }
} }
static void show_settings_dialog(GtkWindow *parent) { static void show_settings_dialog(GtkWidget *widget) {
GtkWidget *dialog; GtkWidget *dialog;
GtkWidget *content_area; GtkWidget *content_area;
GtkWidget *notebook; GtkWidget *notebook;
GtkWidget *settings_tab; GtkWidget *settings_tab;
GtkWidget *about_tab; GtkWidget *about_tab;
GtkWidget *close_button;
dialog = gtk_dialog_new(); dialog = gtk_dialog_new_with_buttons("Settings",
gtk_window_set_title(GTK_WINDOW(dialog), "Settings"); NULL,
gtk_window_set_transient_for(GTK_WINDOW(dialog), parent); GTK_DIALOG_DESTROY_WITH_PARENT,
gtk_window_set_modal(GTK_WINDOW(dialog), TRUE); NULL);
gtk_window_set_destroy_with_parent(GTK_WINDOW(dialog), TRUE); content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
content_area = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
gtk_window_set_child(GTK_WINDOW(dialog), content_area);
notebook = gtk_notebook_new(); notebook = gtk_notebook_new();
gtk_box_append(GTK_BOX(content_area), notebook); gtk_box_pack_start(GTK_BOX(content_area), notebook, TRUE, TRUE, 0);
settings_tab = gtk_box_new(GTK_ORIENTATION_VERTICAL, 10); settings_tab = gtk_box_new(GTK_ORIENTATION_VERTICAL, 10);
gtk_widget_set_margin_top(settings_tab, 10); gtk_container_set_border_width(GTK_CONTAINER(settings_tab), 10);
gtk_widget_set_margin_bottom(settings_tab, 10);
gtk_widget_set_margin_start(settings_tab, 10);
gtk_widget_set_margin_end(settings_tab, 10);
gtk_notebook_append_page(GTK_NOTEBOOK(notebook), settings_tab, gtk_label_new("Settings")); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), settings_tab, gtk_label_new("Settings"));
about_tab = gtk_box_new(GTK_ORIENTATION_VERTICAL, 10); about_tab = gtk_box_new(GTK_ORIENTATION_VERTICAL, 10);
gtk_widget_set_margin_top(about_tab, 10); gtk_container_set_border_width(GTK_CONTAINER(about_tab), 10);
gtk_widget_set_margin_bottom(about_tab, 10);
gtk_widget_set_margin_start(about_tab, 10);
gtk_widget_set_margin_end(about_tab, 10);
gtk_notebook_append_page(GTK_NOTEBOOK(notebook), about_tab, gtk_label_new("About")); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), about_tab, gtk_label_new("About"));
show_settings_tab(settings_tab); show_settings_tab(settings_tab);
show_about_tab(about_tab); show_about_tab(about_tab);
GtkWidget *close_button = gtk_button_new_with_label("Close"); close_button = gtk_button_new_with_label("Close");
gtk_box_append(GTK_BOX(content_area), close_button); g_signal_connect_swapped(close_button, "clicked", G_CALLBACK(gtk_widget_destroy), dialog);
g_signal_connect_swapped(close_button, "clicked", G_CALLBACK(gtk_window_destroy), dialog); gtk_box_pack_start(GTK_BOX(content_area), close_button, FALSE, FALSE, 10);
gtk_window_present(GTK_WINDOW(dialog)); gtk_widget_show_all(dialog);
} }
static void show_settings_tab(GtkWidget *box) { static void show_settings_tab(GtkWidget *box) {
@ -104,146 +85,133 @@ static void show_settings_tab(GtkWidget *box) {
load_configuration(commands); load_configuration(commands);
GtkWidget *grid = gtk_grid_new(); GtkWidget *grid = gtk_grid_new();
gtk_grid_set_row_spacing(GTK_GRID(grid), 10); gtk_grid_set_row_spacing(GTK_GRID(grid), 10); // Space between rows
gtk_grid_set_column_spacing(GTK_GRID(grid), 10); gtk_grid_set_column_spacing(GTK_GRID(grid), 10); // Space between columns
gtk_box_append(GTK_BOX(box), grid); gtk_box_pack_start(GTK_BOX(box), grid, TRUE, TRUE, 0);
GtkWidget **entries = g_new(GtkWidget*, 6);
for (int i = 0; i < 6; i++) { for (int i = 0; i < 6; i++) {
GtkWidget *label = gtk_label_new(labels[i]); GtkWidget *label = gtk_label_new(labels[i]);
GtkWidget *entry = gtk_entry_new(); GtkWidget *entry = gtk_entry_new();
gtk_editable_set_text(GTK_EDITABLE(entry), commands[i]); gtk_entry_set_text(GTK_ENTRY(entry), commands[i]);
gtk_widget_set_hexpand(entry, TRUE); gtk_widget_set_hexpand(entry, TRUE); // Allow the entry to expand
gtk_widget_set_halign(label, GTK_ALIGN_END); gtk_widget_set_halign(label, GTK_ALIGN_END); // Align the label to the end
gtk_grid_attach(GTK_GRID(grid), label, 0, i, 1, 1); gtk_grid_attach(GTK_GRID(grid), label, 0, i, 1, 1);
gtk_grid_attach(GTK_GRID(grid), entry, 1, i, 1, 1); gtk_grid_attach(GTK_GRID(grid), entry, 1, i, 1, 1);
entries[i] = entry;
} }
GtkWidget *save_button = gtk_button_new_with_label("Save");
g_object_set_data_full(G_OBJECT(save_button), "entries", entries, (GDestroyNotify)g_free);
g_signal_connect(save_button, "clicked", G_CALLBACK(on_save_button_clicked), NULL);
gtk_box_append(GTK_BOX(box), save_button);
for (int i = 0; i < 6; i++) { for (int i = 0; i < 6; i++) {
g_free(commands[i]); g_free(commands[i]);
} }
} }
static void on_save_button_clicked(GtkButton *button, gpointer user_data) {
GtkWidget **entries = g_object_get_data(G_OBJECT(button), "entries");
const gchar *commands[6];
for (int i = 0; i < 6; i++) {
commands[i] = gtk_editable_get_text(GTK_EDITABLE(entries[i]));
}
save_configuration(commands);
}
static void show_about_tab(GtkWidget *box) { static void show_about_tab(GtkWidget *box) {
GtkWidget *label; GtkWidget *label;
GtkWidget *image; GtkWidget *image;
const gchar *about_text = const gchar *about_text =
"\n<b>About Simple ShutDown Dialog</b>\n\n" "\n<b>About Simple ShutDown Dialog</b>\n\n"
"<b>Version:</b> 2.0\n" "<b>Version:</b> 1.6\n"
"<b>Author:</b> kekePower\n" "<b>Author:</b> kekePower\n"
"<b>URL: </b><a href=\"https://git.kekepower.com/kekePower/ssdd\">https://git.kekepower.com/kekePower/ssdd</a>\n" "<b>URL: </b><a href=\"https://git.kekepower.com/kekePower/ssdd\">https://git.kekepower.com/kekePower/ssdd</a>\n"
"<b>Description:</b> A Simple ShutDown Dialog for Openbox.\n"; "<b>Description:</b> This is a Simple ShutDown Dialog for Openbox.\n";
image = gtk_image_new_from_resource("/org/gtk/ssdd/ssdd-icon.png"); image = gtk_image_new_from_resource("/org/gtk/ssdd/ssdd-icon.png");
gtk_image_set_pixel_size(GTK_IMAGE(image), 250); gtk_image_set_pixel_size(GTK_IMAGE(image), 250);
gtk_box_append(GTK_BOX(box), image); gtk_box_pack_start(GTK_BOX(box), image, FALSE, FALSE, 0);
label = gtk_label_new(NULL); label = gtk_label_new(NULL);
gtk_label_set_markup(GTK_LABEL(label), about_text); gtk_label_set_markup(GTK_LABEL(label), about_text);
gtk_label_set_selectable(GTK_LABEL(label), TRUE); gtk_label_set_selectable(GTK_LABEL(label), TRUE);
gtk_widget_set_halign(label, GTK_ALIGN_START); gtk_widget_set_halign(label, GTK_ALIGN_START);
gtk_widget_set_valign(label, GTK_ALIGN_START); gtk_widget_set_valign(label, GTK_ALIGN_START);
gtk_box_append(GTK_BOX(box), label); gtk_box_pack_start(GTK_BOX(box), label, TRUE, TRUE, 0);
} }
static void button_clicked(GtkWidget *widget, gpointer data) { static void button_clicked(GtkWidget *widget, gpointer data) {
const gchar *command = (const gchar *)data; const gchar *command = (const gchar *)data;
const gchar *label = g_object_get_data(G_OBJECT(widget), "label"); const gchar *label = g_object_get_data(G_OBJECT(widget), "label");
GtkApplication *app = g_object_get_data(G_OBJECT(widget), "app");
GtkWindow *parent_window = GTK_WINDOW(gtk_widget_get_root(widget));
if (g_strcmp0(command, "exit") == 0) { if (g_strcmp0(command, "exit") == 0) {
g_application_quit(G_APPLICATION(app)); g_application_quit(G_APPLICATION(g_object_get_data(G_OBJECT(widget), "app")));
return; return;
} }
if (g_strcmp0(command, "settings") == 0) { if (g_strcmp0(command, "settings") == 0) {
show_settings_dialog(parent_window); show_settings_dialog(widget);
} else { } else {
show_confirmation_dialog(parent_window, label, command); GtkWidget *window = gtk_widget_get_toplevel(widget);
show_confirmation_dialog(window, label, command);
} }
} }
static gboolean on_key_pressed(GtkEventControllerKey *controller, guint keyval, guint keycode, GdkModifierType state, gpointer user_data) { static gboolean on_key_press(GtkWidget *widget, GdkEventKey *event, gpointer data) {
if (keyval == GDK_KEY_Escape) { if (event->keyval == GDK_KEY_Escape) {
GtkApplication *app = GTK_APPLICATION(user_data); g_application_quit(G_APPLICATION(data));
g_application_quit(G_APPLICATION(app)); return TRUE; // Event handled
return TRUE;
} }
return FALSE; return FALSE; // Event not handled
} }
static void show_confirmation_dialog(GtkWindow *parent_window, const gchar *label, const gchar *command) { static void show_confirmation_dialog(GtkWidget *parent_window, const gchar *label, const gchar *command) {
GtkWidget *dialog; GtkWidget *dialog;
gint response;
gchar *message = g_strdup_printf("Are you sure you want to %s?", label); gchar *message = g_strdup_printf("Are you sure you want to %s?", label);
dialog = gtk_message_dialog_new(parent_window, dialog = gtk_dialog_new();
GTK_DIALOG_MODAL, gtk_window_set_title(GTK_WINDOW(dialog), "Confirmation");
GTK_MESSAGE_QUESTION,
GTK_BUTTONS_YES_NO,
"%s", message);
// Pass the command via g_object_set_data gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(parent_window));
g_object_set_data_full(G_OBJECT(dialog), "command", g_strdup(command), g_free);
g_signal_connect(dialog, "response", G_CALLBACK(on_confirmation_response), NULL); gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
gtk_window_set_destroy_with_parent(GTK_WINDOW(dialog), TRUE);
gtk_window_present(GTK_WINDOW(dialog)); GtkWidget *content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
GtkWidget *box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10);
gtk_container_add(GTK_CONTAINER(content_area), box);
GtkWidget *image = gtk_image_new_from_icon_name("dialog-warning", GTK_ICON_SIZE_DIALOG);
gtk_box_pack_start(GTK_BOX(box), image, FALSE, FALSE, 0);
GtkWidget *label_widget = gtk_label_new(message);
gtk_box_pack_start(GTK_BOX(box), label_widget, TRUE, TRUE, 0);
gtk_dialog_add_buttons(GTK_DIALOG(dialog),
"Yes", GTK_RESPONSE_YES,
"No", GTK_RESPONSE_NO,
NULL);
GtkWidget *button_box = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
gtk_box_set_spacing(GTK_BOX(button_box), 10);
gtk_widget_set_margin_top(button_box, 10);
gtk_widget_show_all(dialog);
response = gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
g_free(message); g_free(message);
}
static void on_confirmation_response(GtkDialog *dialog, gint response_id, gpointer user_data) { if (response == GTK_RESPONSE_YES) {
if (response_id == GTK_RESPONSE_YES) { execute_command(command);
const gchar *command = g_object_get_data(G_OBJECT(dialog), "command");
GtkWindow *parent = GTK_WINDOW(gtk_window_get_transient_for(GTK_WINDOW(dialog)));
execute_command(command, parent);
} }
gtk_window_destroy(GTK_WINDOW(dialog));
} }
static void create_button(GtkWidget *grid, GtkApplication *app, const gchar *label_text, static void create_button(GtkWidget *grid, GtkApplication *app, const gchar *label_text, const gchar *icon_name, const gchar *command, int pos) {
const gchar *icon_name, const gchar *command, int pos) {
GtkWidget *button; GtkWidget *button;
GtkWidget *box; GtkWidget *box;
GtkWidget *image; GtkWidget *image;
GtkWidget *label; GtkWidget *label;
button = gtk_button_new(); button = gtk_button_new();
gtk_widget_set_hexpand(button, TRUE); // Allow button to expand horizontally box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 10);
gtk_widget_set_vexpand(button, TRUE); // Allow button to expand vertically gtk_container_add(GTK_CONTAINER(button), box);
box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); // Set spacing to 0 for tighter layout image = gtk_image_new_from_icon_name(icon_name, GTK_ICON_SIZE_BUTTON);
gtk_widget_set_valign(box, GTK_ALIGN_CENTER); // Center the content vertically gtk_box_pack_start(GTK_BOX(box), image, TRUE, TRUE, 0);
gtk_widget_set_halign(box, GTK_ALIGN_CENTER); // Center the content horizontally
gtk_button_set_child(GTK_BUTTON(button), box);
image = gtk_image_new_from_icon_name(icon_name);
gtk_box_append(GTK_BOX(box), image);
label = gtk_label_new(label_text); label = gtk_label_new(label_text);
gtk_box_append(GTK_BOX(box), label); gtk_box_pack_start(GTK_BOX(box), label, TRUE, TRUE, 0);
// Reduce margins around the button content
gtk_widget_set_margin_top(box, 5); gtk_widget_set_margin_top(box, 5);
gtk_widget_set_margin_bottom(box, 5); gtk_widget_set_margin_bottom(box, 5);
gtk_widget_set_margin_start(box, 5); gtk_widget_set_margin_start(box, 5);
@ -252,16 +220,12 @@ static void create_button(GtkWidget *grid, GtkApplication *app, const gchar *lab
g_object_set_data(G_OBJECT(button), "app", app); g_object_set_data(G_OBJECT(button), "app", app);
g_object_set_data(G_OBJECT(button), "label", (gpointer)label_text); g_object_set_data(G_OBJECT(button), "label", (gpointer)label_text);
g_signal_connect(button, "clicked", G_CALLBACK(button_clicked), (gpointer)command); g_signal_connect(button, "clicked", G_CALLBACK(button_clicked), (gpointer)command);
gtk_grid_attach(GTK_GRID(grid), button, pos % 4, pos / 4, 1, 1); gtk_grid_attach(GTK_GRID(grid), button, pos % 4, pos / 4, 1, 1);
} }
static void save_configuration(const gchar *commands[]) { static void save_configuration(const gchar *commands[]) {
GError *error = NULL; GError *error = NULL;
gchar *config_dir = get_config_dir(); g_mkdir_with_parents(CONFIG_DIR, 0755);
gchar *config_path = get_config_path();
g_mkdir_with_parents(config_dir, 0755);
GString *config_data = g_string_new(NULL); GString *config_data = g_string_new(NULL);
g_string_append_printf(config_data, "LOGOUT_COMMAND=%s\n", commands[0]); g_string_append_printf(config_data, "LOGOUT_COMMAND=%s\n", commands[0]);
@ -271,7 +235,7 @@ static void save_configuration(const gchar *commands[]) {
g_string_append_printf(config_data, "SUSPEND_COMMAND=%s\n", commands[4]); g_string_append_printf(config_data, "SUSPEND_COMMAND=%s\n", commands[4]);
g_string_append_printf(config_data, "HIBERNATE_COMMAND=%s\n", commands[5]); g_string_append_printf(config_data, "HIBERNATE_COMMAND=%s\n", commands[5]);
g_file_set_contents(config_path, config_data->str, -1, &error); g_file_set_contents(CONFIG_PATH, config_data->str, -1, &error);
if (error) { if (error) {
g_warning("Failed to save configuration: %s", error->message); g_warning("Failed to save configuration: %s", error->message);
@ -279,20 +243,15 @@ static void save_configuration(const gchar *commands[]) {
} }
g_string_free(config_data, TRUE); g_string_free(config_data, TRUE);
g_free(config_dir);
g_free(config_path);
} }
static void load_configuration(gchar *commands[]) { static void load_configuration(gchar *commands[]) {
GError *error = NULL; GError *error = NULL;
gchar *config_data = NULL; gchar *config_data = NULL;
gchar *config_dir = get_config_dir();
gchar *config_path = get_config_path();
g_mkdir_with_parents(config_dir, 0755); g_mkdir_with_parents(CONFIG_DIR, 0755);
if (!g_file_test(config_path, G_FILE_TEST_EXISTS)) { if (!g_file_test(CONFIG_PATH, G_FILE_TEST_EXISTS)) {
g_warning("Configuration file not found. Generating a default configuration.");
const gchar *default_commands[] = { const gchar *default_commands[] = {
"openbox --exit", "openbox --exit",
"systemctl reboot", "systemctl reboot",
@ -304,33 +263,17 @@ static void load_configuration(gchar *commands[]) {
save_configuration(default_commands); save_configuration(default_commands);
} }
if (!g_file_get_contents(config_path, &config_data, NULL, &error)) { g_file_get_contents(CONFIG_PATH, &config_data, NULL, &error);
if (error) {
g_warning("Failed to load configuration: %s", error->message); g_warning("Failed to load configuration: %s", error->message);
g_error_free(error); g_error_free(error);
g_free(config_dir);
g_free(config_path);
return; return;
} }
gchar **lines = g_strsplit(config_data, "\n", -1); gchar **lines = g_strsplit(config_data, "\n", -1);
for (int i = 0; i < 6; i++) { for (int i = 0; i < 6; i++) {
gchar **key_value = g_strsplit(lines[i], "=", 2); gchar **key_value = g_strsplit(lines[i], "=", 2);
if (!key_value[0] || !key_value[1]) {
g_warning("Invalid entry in configuration file at line %d. Using default command.", i + 1);
const gchar *default_commands[] = {
"openbox --exit",
"systemctl reboot",
"systemctl poweroff",
"dm-tool switch-to-greeter",
"systemctl suspend",
"systemctl hibernate"
};
commands[i] = g_strdup(default_commands[i]);
g_strfreev(key_value);
continue;
}
if (g_strcmp0(key_value[0], "LOGOUT_COMMAND") == 0) { if (g_strcmp0(key_value[0], "LOGOUT_COMMAND") == 0) {
commands[0] = g_strdup(key_value[1]); commands[0] = g_strdup(key_value[1]);
} else if (g_strcmp0(key_value[0], "REBOOT_COMMAND") == 0) { } else if (g_strcmp0(key_value[0], "REBOOT_COMMAND") == 0) {
@ -343,32 +286,12 @@ static void load_configuration(gchar *commands[]) {
commands[4] = g_strdup(key_value[1]); commands[4] = g_strdup(key_value[1]);
} else if (g_strcmp0(key_value[0], "HIBERNATE_COMMAND") == 0) { } else if (g_strcmp0(key_value[0], "HIBERNATE_COMMAND") == 0) {
commands[5] = g_strdup(key_value[1]); commands[5] = g_strdup(key_value[1]);
} else {
g_warning("Unknown key in configuration: %s", key_value[0]);
} }
g_strfreev(key_value); g_strfreev(key_value);
} }
for (int i = 0; i < 6; i++) {
if (commands[i] == NULL || g_strcmp0(commands[i], "") == 0) {
g_warning("Command at index %d is invalid. Assigning default value.", i);
const gchar *default_commands[] = {
"openbox --exit",
"systemctl reboot",
"systemctl poweroff",
"dm-tool switch-to-greeter",
"systemctl suspend",
"systemctl hibernate"
};
commands[i] = g_strdup(default_commands[i]);
}
}
g_strfreev(lines); g_strfreev(lines);
g_free(config_data); g_free(config_data);
g_free(config_dir);
g_free(config_path);
} }
static void activate(GtkApplication *app, gpointer user_data) { static void activate(GtkApplication *app, gpointer user_data) {
@ -400,30 +323,33 @@ static void activate(GtkApplication *app, gpointer user_data) {
window = gtk_application_window_new(app); window = gtk_application_window_new(app);
gtk_window_set_title(GTK_WINDOW(window), "Simple ShutDown Dialog"); gtk_window_set_title(GTK_WINDOW(window), "Simple ShutDown Dialog");
gtk_window_set_resizable(GTK_WINDOW(window), FALSE); gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
GError *error = NULL;
GdkPixbuf *icon_pixbuf = gdk_pixbuf_new_from_resource("/org/gtk/ssdd/ssdd-icon.png", &error);
if (icon_pixbuf) {
gtk_window_set_icon(GTK_WINDOW(window), icon_pixbuf);
g_object_unref(icon_pixbuf);
} else {
g_warning("Failed to load icon: %s", error->message);
g_error_free(error);
}
g_signal_connect(window, "key-press-event", G_CALLBACK(on_key_press), app);
grid = gtk_grid_new(); grid = gtk_grid_new();
gtk_grid_set_row_spacing(GTK_GRID(grid), 2); // Reduce vertical spacing between grid rows gtk_grid_set_row_spacing(GTK_GRID(grid), 0);
gtk_grid_set_column_spacing(GTK_GRID(grid), 2); // Reduce horizontal spacing between grid columns gtk_grid_set_column_spacing(GTK_GRID(grid), 0);
gtk_widget_set_margin_top(grid, 10); gtk_container_add(GTK_CONTAINER(window), grid);
gtk_widget_set_margin_bottom(grid, 10);
gtk_widget_set_margin_start(grid, 10);
gtk_widget_set_margin_end(grid, 10);
gtk_window_set_child(GTK_WINDOW(window), grid);
for (int i = 0; i < 6; i++) { for (int i = 0; i < 6; i++) {
create_button(grid, app, labels[i], icons[i], commands[i], i); create_button(grid, app, labels[i], icons[i], commands[i], i);
g_free(commands[i]); g_free(commands[i]); // Free the memory allocated for commands
} }
create_button(grid, app, labels[6], icons[6], "settings", 6); create_button(grid, app, labels[6], icons[6], "settings", 6);
create_button(grid, app, labels[7], icons[7], "exit", 7); create_button(grid, app, labels[7], icons[7], "exit", 7);
// Key event handling gtk_widget_show_all(window);
GtkEventController *key_controller = gtk_event_controller_key_new();
gtk_widget_add_controller(window, key_controller);
g_signal_connect(key_controller, "key-pressed", G_CALLBACK(on_key_pressed), app);
gtk_window_present(GTK_WINDOW(window));
} }
int main(int argc, char **argv) { int main(int argc, char **argv) {

BIN
ssdd.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 16 KiB