diff --git a/meson.build b/meson.build index 0f84ae8..43871d8 100644 --- a/meson.build +++ b/meson.build @@ -6,6 +6,7 @@ pkgcfg = import('pkgconfig') inc = include_directories('inc') gtk = dependency('gtk+-3.0') wayland = dependency('wayland-client') +threads = dependency('threads') dl = cc.find_library('dl') hg = find_program('hg', native : true, required : false) @@ -30,7 +31,7 @@ sources = ['src/config.c', 'proto/xdg-output-unstable-v1-protocol.c', 'proto/xdg-shell-protocol.c'] -deps = [gtk, wayland, dl] +deps = [gtk, wayland, dl, threads] if get_option('enable_run') sources += 'modes/run.c' diff --git a/modes/drun.c b/modes/drun.c index 4da080e..d6cda41 100644 --- a/modes/drun.c +++ b/modes/drun.c @@ -32,12 +32,13 @@ static const char* arg_names[] = {"print_command", "display_generic"}; static struct mode* mode; -struct node { - struct widget* widget; +struct desktop_entry { + char* full_path; struct wl_list link; }; -static struct wl_list widgets; +static struct map* entries; +static struct wl_list desktop_entries; static bool print_command; static bool display_generic; @@ -191,7 +192,46 @@ static char* get_id(char* path) { return id; } -static void insert_dir(char* app_dir, struct map* entries) { +static struct widget* create_widget(char* full_path) { + char* id = get_id(full_path); + + if(map_contains(entries, id)) { + free(id); + free(full_path); + return NULL; + } + + size_t action_count; + char** text = get_action_text(full_path, &action_count); + map_put(entries, id, "true"); + if(text == NULL) { + wofi_remove_cache(mode, full_path); + free(id); + free(full_path); + return NULL; + } + + char** actions = get_action_actions(full_path, &action_count); + + char* search_text = get_search_text(full_path); + + struct widget* ret = wofi_create_widget(mode, text, search_text, actions, action_count); + + for(size_t count = 0; count < action_count; ++count) { + free(actions[count]); + free(text[count]); + } + + free(id); + free(text); + free(actions); + free(full_path); + free(search_text); + + return ret; +} + +static void insert_dir(char* app_dir) { DIR* dir = opendir(app_dir); if(dir == NULL) { return; @@ -207,7 +247,7 @@ static void insert_dir(char* app_dir, struct map* entries) { struct stat info; stat(full_path, &info); if(S_ISDIR(info.st_mode)) { - insert_dir(full_path, entries); + insert_dir(full_path); free(id); free(full_path); continue; @@ -217,33 +257,12 @@ static void insert_dir(char* app_dir, struct map* entries) { free(full_path); continue; } - size_t action_count; - char** text = get_action_text(full_path, &action_count); - map_put(entries, id, "true"); - if(text == NULL) { - free(id); - free(full_path); - continue; - } - char** actions = get_action_actions(full_path, &action_count); - - char* search_text = get_search_text(full_path); - - struct node* node = malloc(sizeof(struct node)); - node->widget = wofi_create_widget(mode, text, search_text, actions, action_count); - wl_list_insert(&widgets, &node->link); - - for(size_t count = 0; count < action_count; ++count) { - free(actions[count]); - free(text[count]); - } + struct desktop_entry* entry = malloc(sizeof(struct desktop_entry)); + entry->full_path = full_path; + wl_list_insert(&desktop_entries, &entry->link); free(id); - free(text); - free(actions); - free(search_text); - free(full_path); } closedir(dir); } @@ -312,49 +331,24 @@ void wofi_drun_init(struct mode* this, struct map* config) { print_command = strcmp(config_get(config, "print_command", "false"), "true") == 0; display_generic = strcmp(config_get(config, "display_generic", "false"), "true") == 0; - struct map* entries = map_init(); + entries = map_init(); struct wl_list* cache = wofi_read_cache(mode); - wl_list_init(&widgets); + wl_list_init(&desktop_entries); struct cache_line* node, *tmp; wl_list_for_each_safe(node, tmp, cache, link) { if(should_invalidate_cache(node->line)) { wofi_remove_cache(mode, node->line); + free(node->line); goto cache_cont; } - size_t action_count; - char** text = get_action_text(node->line, &action_count); - if(text == NULL) { - wofi_remove_cache(mode, node->line); - goto cache_cont; - } - - char** actions = get_action_actions(node->line, &action_count); - - char* search_text = get_search_text(node->line); - struct node* widget = malloc(sizeof(struct node)); - widget->widget = wofi_create_widget(mode, text, search_text, actions, action_count); - wl_list_insert(&widgets, &widget->link); - - char* id = get_id(node->line); - - map_put(entries, id, "true"); - - free(id); - - free(search_text); - - for(size_t count = 0; count < action_count; ++count) { - free(text[count]); - free(actions[count]); - } - free(text); - free(actions); + struct desktop_entry* entry = malloc(sizeof(struct desktop_entry)); + entry->full_path = node->line; + wl_list_insert(&desktop_entries, &entry->link); cache_cont: - free(node->line); wl_list_remove(&node->link); free(node); } @@ -371,19 +365,21 @@ void wofi_drun_init(struct mode* this, struct map* config) { char* str = strtok_r(dirs, ":", &save_ptr); do { char* app_dir = utils_concat(2, str, "/applications"); - insert_dir(app_dir, entries); + insert_dir(app_dir); free(app_dir); } while((str = strtok_r(NULL, ":", &save_ptr)) != NULL); free(dirs); - map_free(entries); } struct widget* wofi_drun_get_widget(void) { - struct node* node, *tmp; - wl_list_for_each_reverse_safe(node, tmp, &widgets, link) { - struct widget* widget = node->widget; + struct desktop_entry* node, *tmp; + wl_list_for_each_reverse_safe(node, tmp, &desktop_entries, link) { + struct widget* widget = create_widget(node->full_path); wl_list_remove(&node->link); free(node); + if(widget == NULL) { + continue; + } return widget; } return NULL; diff --git a/src/wofi.c b/src/wofi.c index 562c3cd..3cbe716 100644 --- a/src/wofi.c +++ b/src/wofi.c @@ -100,6 +100,8 @@ static GdkRectangle resolution = {0}; static bool resize_expander = false; static uint32_t line_count = 0; static bool dynamic_lines; +static struct wl_list mode_list; +static pthread_t mode_thread; static struct map* keys; @@ -568,9 +570,9 @@ static gboolean _insert_widget(gpointer data) { } static gboolean insert_all_widgets(gpointer data) { + pthread_join(mode_thread, NULL); struct wl_list* modes = data; if(modes->prev == modes) { - free(modes); return FALSE; } else { struct mode* mode = wl_container_of(modes->prev, mode, link); @@ -1420,6 +1422,22 @@ static struct mode* add_mode(char* _mode) { return mode_ptr; } +static void* start_mode_thread(void* data) { + char* mode = data; + if(strchr(mode, ',') != NULL) { + char* save_ptr; + char* str = strtok_r(mode, ",", &save_ptr); + do { + struct mode* mode_ptr = add_mode(str); + wl_list_insert(&mode_list, &mode_ptr->link); + } while((str = strtok_r(NULL, ",", &save_ptr)) != NULL); + } else { + struct mode* mode_ptr = add_mode(mode); + wl_list_insert(&mode_list, &mode_ptr->link); + } + return NULL; +} + static void parse_mods(char* key, void (*action)(void)) { char* tmp = strdup(key); char* save_ptr; @@ -1743,21 +1761,11 @@ void wofi_init(struct map* _config) { do_percent_size(geo_str); } - struct wl_list* modes = malloc(sizeof(struct wl_list)); - wl_list_init(modes); + wl_list_init(&mode_list); - if(strchr(mode, ',') != NULL) { - char* save_ptr; - char* str = strtok_r(mode, ",", &save_ptr); - do { - struct mode* mode_ptr = add_mode(str); - wl_list_insert(modes, &mode_ptr->link); - } while((str = strtok_r(NULL, ",", &save_ptr)) != NULL); - } else { - struct mode* mode_ptr = add_mode(mode); - wl_list_insert(modes, &mode_ptr->link); - } - gdk_threads_add_idle(insert_all_widgets, modes); + pthread_create(&mode_thread, NULL, start_mode_thread, mode); + + gdk_threads_add_idle(insert_all_widgets, &mode_list); gtk_window_set_title(GTK_WINDOW(window), prompt); gtk_widget_show_all(window);