diff --git a/Entry.c b/Entry.c index f9fe6d5..650d481 100644 --- a/Entry.c +++ b/Entry.c @@ -1,7 +1,9 @@ #include #include +#include "launcher.h" #include "Entry.h" +#include "util.h" Entry * Entry_new() { Entry * entry = malloc(sizeof(Entry)); @@ -10,8 +12,9 @@ Entry * Entry_new() { entry->image_path = NULL; entry->exec = NULL; entry->cd = NULL; - entry->image = NULL; entry->steam_id = 0; + entry->image = NULL; + entry->event_box = NULL; return entry; } @@ -51,6 +54,8 @@ void Entries_delete_all(Entries * entries) { Entry * entry = node->entry; g_free(entry->name); g_free(entry->image_path); + if (entry->image) g_object_unref(entry->image); + if (entry->event_box) g_object_unref(entry->event_box); if (entry->exec) g_free(entry->exec); if (entry->cd) g_free(entry->cd); free(entry); @@ -60,3 +65,28 @@ void Entries_delete_all(Entries * entries) { } } +Entries * Entries_clear_container(GtkContainer * container, Entries * entries) { + Node * node = entries->head; + for (Node * next = node; next; node = next) { + gtk_container_remove(container, node->entry->event_box); + next = node->next; + } +} + +Entries * Entries_filter(Entries * entries, const char * filter) { + char * uc_filter = g_utf8_strup(filter, -1); + Entries * filtered = Entries_new(); + Node * node = entries->head; + for (Node * next = node; next; node = next) { + Entry * e = node->entry; + char * uc_entry_name = g_utf8_strup(e->name, -1); + if (starts_with(uc_entry_name, uc_filter)) { + if (debug) printf(" %s\n", e->name); + Entries_insert(filtered, e); + } + g_free(uc_entry_name); + next = node->next; + } + return filtered; +} + diff --git a/Entry.h b/Entry.h index b697437..c56ff5d 100644 --- a/Entry.h +++ b/Entry.h @@ -15,6 +15,7 @@ struct Entry_struct { char * cd; char * steam_id; GtkWidget * image; + GtkWidget * event_box; }; Entry * Entry_new(); @@ -38,4 +39,7 @@ void Entries_insert(Entries * entries, Entry * entry); void Entries_delete(Entries * entries); void Entries_delete_all(Entries * entries); +Entries * Entries_filter(Entries * entries, const char * filter); +Entries * Entries_clear_container(GtkContainer * container, Entries * entries); + #endif diff --git a/Makefile b/Makefile index 57015fc..bcad6ff 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ EXEC=banner_launcher all: $(EXEC) -$(EXEC): launcher.c Entry.c steam.c +$(EXEC): launcher.c Entry.c steam.c util.c gcc -g `pkg-config --cflags gtk+-3.0` -o $@ $^ `pkg-config --libs gtk+-3.0` clean: diff --git a/launcher.c b/launcher.c index 5bdb20b..8149916 100644 --- a/launcher.c +++ b/launcher.c @@ -8,6 +8,12 @@ #include "launcher.h" #include "steam.h" +GtkWidget * window; +GtkWidget * layout; +GtkWidget * filter; +GtkWidget * scroll; +GtkWidget * grid; + bool load_config(const gchar * path) { bool error = false; if (debug) printf("Loading config from %s\n", path); @@ -55,6 +61,7 @@ bool load_entries(Entries * entries, const gchar * path) { g_key_file_get_string(ini, groups[i], "image", NULL), NULL); entry->image = gtk_image_new_from_file(image_file); + g_object_ref(entry->image); if (debug) { printf(" Entry: %s\n \"%s\"\n", groups[i], entry->name @@ -74,6 +81,36 @@ void entry_click(GtkWidget * widget, GdkEvent * event, gpointer data) { if (debug) printf("Run: %s\n", ((Entry *) data)->name); } +void add_entries_to_grid(Entries * entries) { + int row = 0; + int col = 0; + int cols = GRID_WIDTH; + for (Node * n = entries->head; n; n = n->next) { + Entry * e = n->entry; + gtk_grid_attach(GTK_GRID(grid), e->event_box, col, row, 1, 1); + if (++col >= cols) { + row++; + col = 0; + } + } +} + +void filter_changed(GtkEntryBuffer * b) { + const char * filter = gtk_entry_buffer_get_text(b); + if (debug) printf("Filter: %s\n", filter); + Entries_clear_container(GTK_CONTAINER(grid), visable_entries); + if (visable_entries != all_entries) { + Entries_delete(visable_entries); + } + if (filter[0]) { + visable_entries = Entries_filter(all_entries, filter); + } else { + if (debug) printf(" \n"); + visable_entries = all_entries; + } + add_entries_to_grid(visable_entries); +} + static void activate(GtkApplication * app, gpointer user_data) { config_dir = g_build_filename( g_get_user_config_dir(), @@ -92,18 +129,12 @@ static void activate(GtkApplication * app, gpointer user_data) { "config.ini", NULL); all_entries = Entries_new(); - visable_entries = Entries_new(); + visable_entries = NULL; load_entries(all_entries, entries_file); load_config(config_file); steam_entries = Entries_new(); load_steam_entries(steam_path, steam_entries); - GtkWidget * window; - GtkWidget * layout; - GtkWidget * search; - GtkWidget * scroll; - GtkWidget * grid; - window = gtk_application_window_new(app); gtk_window_set_resizable(GTK_WINDOW(window), false); gtk_window_set_title(GTK_WINDOW(window), APP_NAME); @@ -111,8 +142,21 @@ static void activate(GtkApplication * app, gpointer user_data) { layout = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); gtk_container_add(GTK_CONTAINER(window), layout); - search = gtk_entry_new(); - gtk_container_add(GTK_CONTAINER(layout), search); + GtkEntryBuffer * filter_buffer = gtk_entry_buffer_new("", -1); + filter = gtk_entry_new_with_buffer(filter_buffer); + g_signal_connect( + G_OBJECT(filter_buffer), + "inserted-text", + G_CALLBACK(filter_changed), + NULL + ); + g_signal_connect( + G_OBJECT(filter_buffer), + "deleted-text", + G_CALLBACK(filter_changed), + NULL + ); + gtk_container_add(GTK_CONTAINER(layout), filter); scroll = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_min_content_height(GTK_SCROLLED_WINDOW(scroll), BANNER_HIGHT * 4); @@ -120,12 +164,11 @@ static void activate(GtkApplication * app, gpointer user_data) { grid = gtk_grid_new(); gtk_container_add(GTK_CONTAINER(scroll), grid); - int row = 0; - int col = 0; - int cols = GRID_WIDTH; for (Node * n = all_entries->head; n; n = n->next) { Entry * e = n->entry; GtkWidget * event_box = gtk_event_box_new(); + e->event_box = event_box; + g_object_ref(event_box); gtk_widget_set_events(event_box, GDK_BUTTON_RELEASE_MASK); g_signal_connect( G_OBJECT(event_box), @@ -134,18 +177,17 @@ static void activate(GtkApplication * app, gpointer user_data) { (gpointer) e ); gtk_container_add(GTK_CONTAINER(event_box), e->image); - gtk_grid_attach(GTK_GRID(grid), event_box, col, row, 1, 1); - if (++col >= cols) { - row++; - col = 0; - } } + visable_entries = all_entries; + add_entries_to_grid(visable_entries); + gtk_widget_show_all(window); } int main(int argc, char * argv[]) { debug = true; + visable_entries = NULL; GtkApplication * app; int status; @@ -155,7 +197,7 @@ int main(int argc, char * argv[]) { status = g_application_run(G_APPLICATION(app), argc, argv); g_object_unref(app); - Entries_delete(visable_entries); + if (visable_entries != all_entries) Entries_delete(visable_entries); Entries_delete_all(all_entries); Entries_delete_all(steam_entries); g_free(config_dir); diff --git a/steam.c b/steam.c index e0d2387..9d8ea70 100644 --- a/steam.c +++ b/steam.c @@ -4,24 +4,9 @@ #include -#include "launcher.h" +#include "util.h" #include "steam.h" - -bool starts_with(char * string, char * prefix) { - size_t i = 0; - char string_char, prefix_char; - while (true) { - string_char = string[i]; - prefix_char = prefix[i]; - if (!prefix_char) { - return true; - } - if (string_char != prefix_char) { - return false; - } - i++; - } -} +#include "launcher.h" void load_steam_entries(char * steam_path, Entries * steam_entries) { diff --git a/util.c b/util.c new file mode 100644 index 0000000..e3ebefa --- /dev/null +++ b/util.c @@ -0,0 +1,18 @@ +#include "util.h" + +bool starts_with(const char * string, const char * prefix) { + size_t i = 0; + char string_char, prefix_char; + while (true) { + string_char = string[i]; + prefix_char = prefix[i]; + if (!prefix_char) { + return true; + } + if (string_char != prefix_char) { + return false; + } + i++; + } +} + diff --git a/util.h b/util.h new file mode 100644 index 0000000..b437797 --- /dev/null +++ b/util.h @@ -0,0 +1,4 @@ +#include +#include + +bool starts_with(const char * string, const char * prefix);