#include #include #include #include #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; }