Update to version 2.0. Port to GTK4.

This commit is contained in:
2024-09-13 01:49:48 +02:00
parent 18e6f1a70f
commit c24db4dcbd
6 changed files with 216 additions and 135 deletions
+11 -8
View File
@@ -2,8 +2,11 @@
CC = gcc CC = gcc
# Compiler and optimization flags # Compiler and optimization flags
CFLAGS = `pkg-config --cflags gtk+-3.0` -O3 CFLAGS ?= -Wall -O2
LDFLAGS = `pkg-config --libs gtk+-3.0` CFLAGS += $(shell pkg-config --cflags gtk4)
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
@@ -35,15 +38,15 @@ $(RESOURCE_C) $(RESOURCE_H): $(RESOURCE_XML)
# Install target # Install target
install: $(TARGET) install: $(TARGET)
install -d $(BINDIR) install -d $(DESTDIR)$(BINDIR)
install -m 755 $(TARGET) $(BINDIR) install -m 755 $(TARGET) $(DESTDIR)$(BINDIR)
install -d $(DATADIR) install -d $(DESTDIR)$(DATADIR)
install -m 644 $(RESOURCE_XML) $(DATADIR) install -m 644 $(RESOURCE_XML) $(DESTDIR)$(DATADIR)
# Uninstall target # Uninstall target
uninstall: uninstall:
rm -f $(BINDIR)/$(TARGET) rm -f $(DESTDIR)$(BINDIR)/$(TARGET)
rm -rf $(DATADIR) rm -rf $(DESTDIR)$(DATADIR)
# Clean target # Clean target
clean: clean:
+12 -8
View File
@@ -1,12 +1,14 @@
# ssdd: Simple Shutdown Dialog for Openbox # ssdd: Simple Shutdown Dialog for Openbox
A simple Shutdown Dialog for Openbox written in C using GTK A simple Shutdown Dialog for Openbox written in C using GTK 4
![Project Screenshot](ssdd.png) ![Project Screenshot](ssdd.png)
![Settings screenshot](ssdd-settings.png) ![Settings screenshot](ssdd-settings.png)
**Simple Shutdown Dialog (ssdd)** is a simple yet stylish shutdown dialog for Openbox, crafted in C using GTK. ![Settings screenshot](ssdd-about.png)
**Simple Shutdown Dialog (ssdd)** is a simple yet stylish shutdown dialog for Openbox, crafted in C using GTK 4.
## Why ssdd? ## Why ssdd?
@@ -16,15 +18,16 @@ Inspired by the elegant `ssd` from Sawfish, I decided to create my own tailored
## Features ## Features
* **Clean and Intuitive Interface:** ssdd presents a clear choice between Shutdown, Reboot, Logout, and Exit options. - **Clean and Intuitive Interface:** ssdd presents clear options for Logout, Reboot, Shutdown, Switch User, Suspend, Hibernate, Settings, and Exit.
* **Clean and minimal code:** `ssdd` is built on a clean and minimal codebase, making it easy to maintain, understand, and extend. - **Configurable Commands:** Easily customize the commands executed for each action via the settings dialog.
* **Lightweight and Efficient:** ssdd is designed to be fast and resource-friendly, perfectly suited for Openbox's minimalist philosophy. - **Lightweight and Efficient:** 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+ 3.0 * GTK 4 development libraries
* Glib 2 development libraries * Glib 2 development libraries
* gcc or clang * gcc or clang
@@ -49,10 +52,10 @@ First generate the resources.
```bash ```bash
# Using GCC: # Using GCC:
% gcc ssdd.c resources.c -o ssdd `pkg-config --cflags --libs gtk+-3.0` % gcc ssdd.c resources.c -o ssdd `pkg-config --cflags --libs gtk4`
# Using Clang: # Using Clang:
% clang ssdd.c resources.c -o ssdd `pkg-config --cflags --libs gtk+-3.0` % clang ssdd.c resources.c -o ssdd `pkg-config --cflags --libs gtk4`
``` ```
Place the `ssdd` binary in your `$PATH` (e.g., `~/bin`). Place the `ssdd` binary in your `$PATH` (e.g., `~/bin`).
@@ -80,3 +83,4 @@ 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.
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 35 KiB

+192 -118
View File
@@ -1,74 +1,93 @@
#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 (prototypes) // Function declarations
static void execute_command(const gchar *command); static void execute_command(const gchar *command, GtkWindow *parent);
static void show_settings_dialog(GtkWidget *widget); static void show_settings_dialog(GtkWindow *parent);
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_press(GtkWidget *widget, GdkEventKey *event, gpointer data); static gboolean on_key_pressed(GtkEventControllerKey *controller, guint keyval, guint keycode, GdkModifierType state, gpointer user_data);
static void show_confirmation_dialog(GtkWidget *widget, const gchar *label, const gchar *command); static void show_confirmation_dialog(GtkWindow *parent_window, 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);
#define CONFIG_PATH g_build_filename(g_get_home_dir(), ".config/ssdd/config", NULL) static gchar *get_config_dir(void) {
#define CONFIG_DIR g_build_filename(g_get_home_dir(), ".config/ssdd", NULL) return g_build_filename(g_get_user_config_dir(), "ssdd", NULL);
}
static void execute_command(const gchar *command) { static gchar *get_config_path(void) {
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) {
GtkWidget *dialog; gchar *error_message = g_strdup_printf("Error executing command '%s': %s", command, error->message);
dialog = gtk_message_dialog_new(NULL,
GTK_DIALOG_DESTROY_WITH_PARENT, GtkWidget *dialog = gtk_message_dialog_new(parent,
GTK_MESSAGE_ERROR, GTK_DIALOG_MODAL,
GTK_BUTTONS_CLOSE, GTK_MESSAGE_ERROR,
"Error executing command: %s\n%s", GTK_BUTTONS_CLOSE,
command, "%s", error_message);
error->message); g_signal_connect(dialog, "response", G_CALLBACK(gtk_window_destroy), NULL);
gtk_dialog_run(GTK_DIALOG(dialog)); gtk_window_present(GTK_WINDOW(dialog));
gtk_widget_destroy(dialog);
g_free(error_message);
g_error_free(error); g_error_free(error);
} }
} }
static void show_settings_dialog(GtkWidget *widget) { static void show_settings_dialog(GtkWindow *parent) {
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_with_buttons("Settings", dialog = gtk_dialog_new();
NULL, gtk_window_set_title(GTK_WINDOW(dialog), "Settings");
GTK_DIALOG_DESTROY_WITH_PARENT, gtk_window_set_transient_for(GTK_WINDOW(dialog), parent);
NULL); gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); gtk_window_set_destroy_with_parent(GTK_WINDOW(dialog), TRUE);
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_pack_start(GTK_BOX(content_area), notebook, TRUE, TRUE, 0); gtk_box_append(GTK_BOX(content_area), notebook);
settings_tab = gtk_box_new(GTK_ORIENTATION_VERTICAL, 10); settings_tab = gtk_box_new(GTK_ORIENTATION_VERTICAL, 10);
gtk_container_set_border_width(GTK_CONTAINER(settings_tab), 10); gtk_widget_set_margin_top(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_container_set_border_width(GTK_CONTAINER(about_tab), 10); gtk_widget_set_margin_top(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);
close_button = gtk_button_new_with_label("Close"); GtkWidget *close_button = gtk_button_new_with_label("Close");
g_signal_connect_swapped(close_button, "clicked", G_CALLBACK(gtk_widget_destroy), dialog); gtk_box_append(GTK_BOX(content_area), close_button);
gtk_box_pack_start(GTK_BOX(content_area), close_button, FALSE, FALSE, 10); g_signal_connect_swapped(close_button, "clicked", G_CALLBACK(gtk_window_destroy), dialog);
gtk_widget_show_all(dialog); gtk_window_present(GTK_WINDOW(dialog));
} }
static void show_settings_tab(GtkWidget *box) { static void show_settings_tab(GtkWidget *box) {
@@ -85,133 +104,146 @@ 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); // Space between rows gtk_grid_set_row_spacing(GTK_GRID(grid), 10);
gtk_grid_set_column_spacing(GTK_GRID(grid), 10); // Space between columns gtk_grid_set_column_spacing(GTK_GRID(grid), 10);
gtk_box_pack_start(GTK_BOX(box), grid, TRUE, TRUE, 0); gtk_box_append(GTK_BOX(box), grid);
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_entry_set_text(GTK_ENTRY(entry), commands[i]); gtk_editable_set_text(GTK_EDITABLE(entry), commands[i]);
gtk_widget_set_hexpand(entry, TRUE); // Allow the entry to expand gtk_widget_set_hexpand(entry, TRUE);
gtk_widget_set_halign(label, GTK_ALIGN_END); // Align the label to the end gtk_widget_set_halign(label, GTK_ALIGN_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> 1.6\n" "<b>Version:</b> 2.0\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> This is a Simple ShutDown Dialog for Openbox.\n"; "<b>Description:</b> 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_pack_start(GTK_BOX(box), image, FALSE, FALSE, 0); gtk_box_append(GTK_BOX(box), image);
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_pack_start(GTK_BOX(box), label, TRUE, TRUE, 0); gtk_box_append(GTK_BOX(box), label);
} }
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(g_object_get_data(G_OBJECT(widget), "app"))); g_application_quit(G_APPLICATION(app));
return; return;
} }
if (g_strcmp0(command, "settings") == 0) { if (g_strcmp0(command, "settings") == 0) {
show_settings_dialog(widget); show_settings_dialog(parent_window);
} else { } else {
GtkWidget *window = gtk_widget_get_toplevel(widget); show_confirmation_dialog(parent_window, label, command);
show_confirmation_dialog(window, label, command);
} }
} }
static gboolean on_key_press(GtkWidget *widget, GdkEventKey *event, gpointer data) { static gboolean on_key_pressed(GtkEventControllerKey *controller, guint keyval, guint keycode, GdkModifierType state, gpointer user_data) {
if (event->keyval == GDK_KEY_Escape) { if (keyval == GDK_KEY_Escape) {
g_application_quit(G_APPLICATION(data)); GtkApplication *app = GTK_APPLICATION(user_data);
return TRUE; // Event handled g_application_quit(G_APPLICATION(app));
return TRUE;
} }
return FALSE; // Event not handled return FALSE;
} }
static void show_confirmation_dialog(GtkWidget *parent_window, const gchar *label, const gchar *command) { static void show_confirmation_dialog(GtkWindow *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_dialog_new(); dialog = gtk_message_dialog_new(parent_window,
gtk_window_set_title(GTK_WINDOW(dialog), "Confirmation"); GTK_DIALOG_MODAL,
GTK_MESSAGE_QUESTION,
GTK_BUTTONS_YES_NO,
"%s", message);
gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(parent_window)); // Pass the command via g_object_set_data
g_object_set_data_full(G_OBJECT(dialog), "command", g_strdup(command), g_free);
gtk_window_set_modal(GTK_WINDOW(dialog), TRUE); g_signal_connect(dialog, "response", G_CALLBACK(on_confirmation_response), NULL);
gtk_window_set_destroy_with_parent(GTK_WINDOW(dialog), TRUE);
GtkWidget *content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); gtk_window_present(GTK_WINDOW(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);
if (response == GTK_RESPONSE_YES) {
execute_command(command);
}
} }
static void create_button(GtkWidget *grid, GtkApplication *app, const gchar *label_text, const gchar *icon_name, const gchar *command, int pos) { static void on_confirmation_response(GtkDialog *dialog, gint response_id, gpointer user_data) {
if (response_id == GTK_RESPONSE_YES) {
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,
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();
box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 10); gtk_widget_set_hexpand(button, TRUE); // Allow button to expand horizontally
gtk_container_add(GTK_CONTAINER(button), box); gtk_widget_set_vexpand(button, TRUE); // Allow button to expand vertically
image = gtk_image_new_from_icon_name(icon_name, GTK_ICON_SIZE_BUTTON); box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); // Set spacing to 0 for tighter layout
gtk_box_pack_start(GTK_BOX(box), image, TRUE, TRUE, 0); gtk_widget_set_valign(box, GTK_ALIGN_CENTER); // Center the content vertically
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_pack_start(GTK_BOX(box), label, TRUE, TRUE, 0); gtk_box_append(GTK_BOX(box), label);
// 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);
@@ -220,12 +252,16 @@ 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;
g_mkdir_with_parents(CONFIG_DIR, 0755); gchar *config_dir = get_config_dir();
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]);
@@ -235,7 +271,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);
@@ -243,15 +279,20 @@ 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",
@@ -263,17 +304,33 @@ static void load_configuration(gchar *commands[]) {
save_configuration(default_commands); save_configuration(default_commands);
} }
g_file_get_contents(CONFIG_PATH, &config_data, NULL, &error); if (!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) {
@@ -286,12 +343,32 @@ 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) {
@@ -323,33 +400,30 @@ 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_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
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), 0); gtk_grid_set_row_spacing(GTK_GRID(grid), 2); // Reduce vertical spacing between grid rows
gtk_grid_set_column_spacing(GTK_GRID(grid), 0); gtk_grid_set_column_spacing(GTK_GRID(grid), 2); // Reduce horizontal spacing between grid columns
gtk_container_add(GTK_CONTAINER(window), grid); gtk_widget_set_margin_top(grid, 10);
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]); // Free the memory allocated for commands g_free(commands[i]);
} }
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);
gtk_widget_show_all(window); // Key event handling
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
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 15 KiB