This repository has been archived on 2023-11-26. You can view files and clone it, but cannot push or open issues or pull requests.
FeedbackD-Configuration/src/main.c

310 lines
10 KiB
C

#include <stdlib.h>
#include <json-glib/json-glib.h>
#include <gtk/gtk.h>
#include <handy.h>
#include "main.h"
#include "dialog.h"
#include "util.h"
static void on_startup() {
hdy_init();
}
#define CONFIG_JSON_URI "admin:///usr/share/feedbackd/themes/default.json"
JsonNode *root = NULL;
// Extracts Profile Obj From JSON Root (Only Runs In Init)
static JsonArray *get_profile(gchar *name) {
if (root != NULL) {
JsonObject *obj = json_node_get_object(root);
if (obj != NULL) {
JsonArray *profiles = json_object_get_array_member(obj, "profiles");
if (profiles != NULL) {
int length = json_array_get_length(profiles);
for (int i = 0; i < length; i++) {
JsonObject *element = json_array_get_object_element(profiles, i);
if (element != NULL) {
const gchar *elementName = json_object_get_string_member(element, "name");
if (g_strcmp0(name, elementName) == 0) {
return json_object_get_array_member(element, "feedbacks");
}
}
}
}
}
}
return NULL;
}
#define LABEL_MARGIN 16
// Event Delete Handler
static void on_delete(__attribute__((unused)) GtkButton *button, struct event_location *data) {
json_array_remove_element(data->profile, data->id);
reload_profiles(1);
}
// Handler For Freeing Userdata
void free_userdata(__attribute__((unused)) GtkWidget *widget, void *userdata) {
free(userdata);
}
// Edit Event Row Handler
static void on_edit(GtkWidget *button, struct event_location *data) {
open_dialog(button, data, 0);
}
// Remove Widget Handler
static void remove_widget(GtkWidget *widget, __attribute__((unused)) void *data) {
gtk_widget_destroy(widget);
}
// Load Profile Into List
static void load_profile(GtkListBox *list) {
char *name = profile_list_to_name(list);
gtk_container_foreach(GTK_CONTAINER(list), remove_widget, NULL);
JsonArray *profile = name_to_profile(name);
if (profile != NULL && list != NULL) {
int length = json_array_get_length(profile);
for (int i = 0; i < length; i++) {
JsonObject *event = json_array_get_object_element(profile, i);
if (event != NULL) {
const gchar *event_name = json_object_get_string_member(event, "event-name");
if (event_name != NULL) {
GtkWidget *row = gtk_list_box_row_new();
gtk_widget_set_visible(row, 1);
GtkWidget *box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
gtk_widget_set_visible(box, 1);
gtk_widget_set_halign(box, GTK_ALIGN_FILL);
GtkWidget *label = gtk_label_new(event_name);
gtk_widget_set_visible(label, 1);
gtk_label_set_xalign(GTK_LABEL(label), 0);
gtk_label_set_lines(GTK_LABEL(label), 2);
gtk_label_set_line_wrap(GTK_LABEL(label), 1);
gtk_label_set_line_wrap_mode(GTK_LABEL(label), PANGO_WRAP_WORD_CHAR);
gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_END);
gtk_widget_set_margin_start(label, LABEL_MARGIN);
gtk_widget_set_margin_end(label, LABEL_MARGIN);
gtk_widget_set_margin_top(label, LABEL_MARGIN);
gtk_widget_set_margin_bottom(label, LABEL_MARGIN);
gtk_box_pack_start(GTK_BOX(box), label, 0, 0, 0);
GtkWidget *edit_button = gtk_button_new_with_label("Edit");
gtk_widget_set_visible(edit_button, 1);
gtk_widget_set_halign(edit_button, GTK_ALIGN_END);
gtk_widget_set_valign(edit_button, GTK_ALIGN_CENTER);
struct event_location *location = malloc(sizeof (struct event_location));
location->profile = profile;
location->id = i;
g_signal_connect(edit_button, "clicked", G_CALLBACK(on_edit), location);
gtk_widget_set_margin_end(edit_button, LABEL_MARGIN);
gtk_widget_set_margin_top(edit_button, LABEL_MARGIN);
gtk_widget_set_margin_bottom(edit_button, LABEL_MARGIN);
GtkWidget *delete_button = gtk_button_new_with_label("Delete");
gtk_widget_set_visible(delete_button, 1);
gtk_widget_set_halign(delete_button, GTK_ALIGN_END);
gtk_widget_set_valign(delete_button, GTK_ALIGN_CENTER);
g_signal_connect(delete_button, "clicked", G_CALLBACK(on_delete), location);
gtk_widget_set_margin_end(delete_button, LABEL_MARGIN);
gtk_widget_set_margin_top(delete_button, LABEL_MARGIN);
gtk_widget_set_margin_bottom(delete_button, LABEL_MARGIN);
gtk_box_pack_end(GTK_BOX(box), delete_button, 0, 0, 0);
gtk_box_pack_end(GTK_BOX(box), edit_button, 0, 0, 0);
gtk_container_add(GTK_CONTAINER(row), box);
g_signal_connect(row, "destroy", G_CALLBACK(free_userdata), location);
gtk_container_add(GTK_CONTAINER(list), row);
}
}
}
}
}
// JSON GIO File
GFile *file = NULL;
// Reload And Save Profiles
void reload_profiles(int save) {
load_profile(get_app_data()->full_list);
load_profile(get_app_data()->quiet_list);
load_profile(get_app_data()->silent_list);
if (save) {
JsonGenerator *generator = json_generator_new();
json_generator_set_root(generator, root);
json_generator_set_pretty(generator, 1);
json_generator_set_indent(generator, 4);
json_generator_set_indent_char(generator, ' ');
// Open JSON
GError *open_err = NULL;
GFileOutputStream *stream = g_file_replace(file, NULL, 0, G_FILE_CREATE_NONE, NULL, &open_err);
if (stream == NULL) {
g_error("Error Opening File Stream: %s", open_err->message);
}
// Write JSON
GError *write_err = NULL;
if (json_generator_to_stream(generator, G_OUTPUT_STREAM(stream), NULL, &write_err) == 0) {
g_error("Error Saving JSON: %s", write_err->message);
}
// Close JSON
GError *close_err = NULL;
if (g_output_stream_close(G_OUTPUT_STREAM(stream), NULL, &close_err) == 0) {
g_error("Error Closing File Stream: %s", close_err->message);
}
g_object_unref(stream);
// Restart FeedbackD
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-result"
system("killall feedbackd");
#pragma GCC diagnostic pop
g_object_unref(generator);
}
}
// New Event Handler
void on_new_event(GtkButton *button, GtkStack *stack) {
struct event_location *location = malloc(sizeof (struct event_location));
location->id = -1;
GtkListBox *visible_widget = GTK_LIST_BOX(gtk_stack_get_visible_child(stack));
location->profile = name_to_profile(profile_list_to_name(visible_widget));
open_dialog(GTK_WIDGET(button), location, 1);
}
// Finish Mount Handler
static void finish_mount(__attribute__((unused)) GObject *object, GAsyncResult *result, __attribute__((unused)) gpointer user_data) {
GError *err = NULL;
if (g_file_mount_enclosing_volume_finish(file, result, &err) == 0) {
g_error("Error Mounting GVFS: %s", err->message);
}
// Open JSON
GError *open_err = NULL;
GFileInputStream *stream = g_file_read(file, NULL, &open_err);
if (stream == NULL) {
g_error("Error Opening File Stream: %s", open_err->message);
}
// Create JSON Parser
JsonParser *parser = json_parser_new();
// Load JSON
GError *json_err = NULL;
if (json_parser_load_from_stream(parser, G_INPUT_STREAM(stream), NULL, &json_err) == 0) {
g_error("Error Parsing JSON: %s", json_err->message);
}
// Store JSON Data
root = json_node_copy(json_parser_get_root(parser));
// Free JSON Parser
g_object_unref(parser);
// Close JSON
GError *close_err = NULL;
if (g_input_stream_close(G_INPUT_STREAM(stream), NULL, &close_err) == 0) {
g_error("Error Closing File Stream: %s", close_err->message);
}
g_object_unref(stream);
// Cache JSON Objects
get_app_data()->full = get_profile("full");
get_app_data()->quiet = get_profile("quiet");
get_app_data()->silent = get_profile("silent");
// Reload Widgets
reload_profiles(0);
}
// App Start Handler
static void on_activate(GtkApplication *app) {
g_assert(GTK_IS_APPLICATION(app));
GtkWindow *window = gtk_application_get_active_window(app);
if (window == NULL) {
GtkBuilder *builder = gtk_builder_new();
// Load Window
GError *err = NULL;
if (gtk_builder_add_from_resource(builder, "/main_window.glade", &err) == 0) {
g_error("Error Loading UI: %s", err->message);
}
window = GTK_WINDOW(gtk_builder_get_object(builder, "main_window"));
gtk_builder_connect_signals(builder, NULL);
file = g_file_new_for_uri(CONFIG_JSON_URI);
init_app_data();
get_app_data()->full_list = GTK_LIST_BOX(gtk_builder_get_object(builder, "full"));
get_app_data()->quiet_list = GTK_LIST_BOX(gtk_builder_get_object(builder, "quiet"));
get_app_data()->silent_list = GTK_LIST_BOX(gtk_builder_get_object(builder, "silent"));
g_object_unref(builder);
gtk_window_set_application(window, app);
// Mount File
GMountOperation *operation = gtk_mount_operation_new(window);
g_file_mount_enclosing_volume(file, G_MOUNT_MOUNT_NONE, operation, NULL, finish_mount, NULL);
g_object_unref(operation);
}
gtk_window_present(window);
}
// Memory Cleanup
static void cleanup() {
if (root != NULL) {
json_node_free(root);
}
free_app_data();
if (file != NULL) {
g_object_unref(file);
}
}
// Main
int main(int argc, char *argv[]) {
GtkApplication *app = gtk_application_new("com.thebrokenrail.FeedbackD-Configuration", G_APPLICATION_FLAGS_NONE);
g_signal_connect(app, "startup", G_CALLBACK(on_startup), NULL);
g_signal_connect(app, "activate", G_CALLBACK(on_activate), NULL);
int ret = g_application_run(G_APPLICATION(app), argc, argv);
cleanup();
g_object_unref(app);
return ret;
}