diff --git a/kitty/shaders.c b/kitty/shaders.c index 18c8ad58a..57dbd32d8 100644 --- a/kitty/shaders.c +++ b/kitty/shaders.c @@ -860,7 +860,7 @@ draw_cells(ssize_t vao_idx, ssize_t gvao_idx, GLfloat xstart, GLfloat ystart, GL #undef SCALE bool has_underlying_image = has_bgimage(os_window); WindowLogoRenderData *wl = &window->window_logo; - if (wl->instance && wl->instance->load_from_disk_ok) { + if (wl->id && (wl->instance = find_window_logo(global_state.all_window_logos, wl->id)) && wl->instance && wl->instance->load_from_disk_ok) { has_underlying_image = true; set_on_gpu_state(window->window_logo.instance, true); } else wl = NULL; diff --git a/kitty/state.c b/kitty/state.c index 29d30de50..4853f99f0 100644 --- a/kitty/state.c +++ b/kitty/state.c @@ -228,14 +228,17 @@ static bool set_window_logo(Window *w, const char *path, const ImageAnchorPosition pos, bool is_default) { bool ok = false; if (path && path[0]) { - WindowLogo *wl = find_or_create_window_logo(&global_state.all_window_logos, path); + window_logo_id_t wl = find_or_create_window_logo(global_state.all_window_logos, path); if (wl) { - w->window_logo.instance = wl; + w->window_logo.id = wl; w->window_logo.position = pos; ok = true; } } else { - decref_window_logo(&global_state.all_window_logos, &w->window_logo.instance); + if (w->window_logo.id) { + decref_window_logo(global_state.all_window_logos, w->window_logo.id); + w->window_logo.id = 0; + } ok = true; } w->window_logo.using_default = is_default; @@ -313,7 +316,10 @@ destroy_window(Window *w) { Py_CLEAR(w->render_data.screen); Py_CLEAR(w->title); free(w->title_bar_data.buf); w->title_bar_data.buf = NULL; release_gpu_resources_for_window(w); - decref_window_logo(&global_state.all_window_logos, &w->window_logo.instance); + if (w->window_logo.id) { + decref_window_logo(global_state.all_window_logos, w->window_logo.id); + w->window_logo.id = 0; + } } static void @@ -1281,6 +1287,7 @@ finalize(void) { // the GPU driver should take care of it when the OpenGL context is // destroyed. free_bgimage(&global_state.bgimage, false); + free_window_logo_table(&global_state.all_window_logos); global_state.bgimage = NULL; free_url_prefixes(); free(OPT(select_by_word_characters)); OPT(select_by_word_characters) = NULL; @@ -1296,6 +1303,8 @@ init_state(PyObject *module) { #define DPI 96.0 #endif global_state.default_dpi.x = DPI; global_state.default_dpi.y = DPI; + global_state.all_window_logos = alloc_window_logo_table(); + if (!global_state.all_window_logos) { PyErr_NoMemory(); return false; } if (PyModule_AddFunctions(module, module_methods) != 0) return false; if (PyStructSequence_InitType2(&RegionType, ®ion_desc) != 0) return false; Py_INCREF((PyObject *) &RegionType); diff --git a/kitty/state.h b/kitty/state.h index b84eb5950..c3c306b72 100644 --- a/kitty/state.h +++ b/kitty/state.h @@ -83,6 +83,7 @@ typedef struct { } Options; typedef struct WindowLogoRenderData { + window_logo_id_t id; WindowLogo *instance; ImageAnchorPosition position; bool using_default; @@ -230,7 +231,7 @@ typedef struct { int active_drag_button; CloseRequest quit_request; bool redirect_mouse_handling; - WindowLogo *all_window_logos; + WindowLogoTable *all_window_logos; } GlobalState; extern GlobalState global_state; diff --git a/kitty/window_logo.c b/kitty/window_logo.c index dd0d24e62..7b952dde6 100644 --- a/kitty/window_logo.c +++ b/kitty/window_logo.c @@ -10,58 +10,93 @@ typedef struct WindowLogoItem { - WindowLogoHead + WindowLogo wl; unsigned int refcnt; char *path; - UT_hash_handle hh; + window_logo_id_t id; + UT_hash_handle hh_id; + UT_hash_handle hh_path; } WindowLogoItem; +struct WindowLogoTable { + WindowLogoItem *by_id, *by_path; +}; static void -free_window_logo(WindowLogoItem **head, WindowLogoItem **itemref) { +free_window_logo(WindowLogoTable *table, WindowLogoItem **itemref) { WindowLogoItem *item = *itemref; free(item->path); - free(item->bitmap); - if (item->texture_id) free_texture(&item->texture_id); - HASH_DEL(*head, item); + free(item->wl.bitmap); + if (item->wl.texture_id) free_texture(&item->wl.texture_id); + HASH_DELETE(hh_id, table->by_id, item); + HASH_DELETE(hh_path, table->by_path, item); free(item); itemref = NULL; } static void -send_logo_to_gpu(WindowLogoItem *s) { +send_logo_to_gpu(WindowLogo *s) { send_image_to_gpu(&s->texture_id, s->bitmap, s->width, s->height, false, true, true, REPEAT_CLAMP); + free(s->bitmap); s->bitmap = NULL; } void -set_on_gpu_state(WindowLogo *x, bool on_gpu) { - WindowLogoItem *s = (WindowLogoItem*)x; +set_on_gpu_state(WindowLogo *s, bool on_gpu) { if (s->load_from_disk_ok) { if (on_gpu) { if (!s->texture_id) send_logo_to_gpu(s); } else if (s->texture_id) free_texture(&s->texture_id); } } -WindowLogo* -find_or_create_window_logo(WindowLogo **head_, const char *path) { - WindowLogoItem **head = (WindowLogoItem**)head_; +window_logo_id_t +find_or_create_window_logo(WindowLogoTable *head, const char *path) { WindowLogoItem *s = NULL; - HASH_FIND_STR(*head, path, s); - if (s) return (WindowLogo*)s; + unsigned _uthash_hfstr_keylen = (unsigned)uthash_strlen(path); + HASH_FIND(hh_path, head->by_path, path, _uthash_hfstr_keylen, s); + if (s) return s->id; s = calloc(1, sizeof *s); size_t size; - if (!s) { PyErr_NoMemory(); return NULL; } + if (!s) { PyErr_NoMemory(); return 0; } s->path = strdup(path); - if (!s->path) { free(s->bitmap); free(s); PyErr_NoMemory(); return NULL; } - if (png_path_to_bitmap(path, &s->bitmap, &s->width, &s->height, &size)) s->load_from_disk_ok = true; + if (!s->path) { free(s); PyErr_NoMemory(); return 0; } + if (png_path_to_bitmap(path, &s->wl.bitmap, &s->wl.width, &s->wl.height, &size)) s->wl.load_from_disk_ok = true; s->refcnt++; - HASH_ADD_KEYPTR(hh, *head, s->path, strlen(s->path), s); - return (WindowLogo*)s; + static window_logo_id_t idc = 0; + s->id = ++idc; + HASH_ADD(hh_id, head->by_id, id, sizeof(window_logo_id_t), s); + HASH_ADD_KEYPTR(hh_path, head->by_path, s->path, strlen(s->path), s); + return s->id; +} + +WindowLogo* +find_window_logo(WindowLogoTable *table, window_logo_id_t id) { + WindowLogoItem *s = NULL; + HASH_FIND(hh_id, table->by_id, &id, sizeof(window_logo_id_t), s); + return s ? &s->wl : NULL; } void -decref_window_logo(WindowLogo **head_, WindowLogo** logo) { - WindowLogoItem **head = (WindowLogoItem**)head_; - WindowLogoItem **s = (WindowLogoItem**)logo; - if (*s) { if ((*s)->refcnt < 2) free_window_logo(head, s); else (*s)->refcnt--; } +decref_window_logo(WindowLogoTable *table, window_logo_id_t id) { + WindowLogoItem *s = NULL; + HASH_FIND(hh_id, table->by_id, &id, sizeof(window_logo_id_t), s); + if (s) { + if (s->refcnt < 2) free_window_logo(table, &s); + else s->refcnt--; + } +} + +WindowLogoTable* +alloc_window_logo_table(void) { + return calloc(1, sizeof(WindowLogoTable)); +} + +void +free_window_logo_table(WindowLogoTable **table) { + WindowLogoItem *current, *tmp; + HASH_ITER(hh_id, (*table)->by_id, current, tmp) { + HASH_DELETE(hh_id, (*table)->by_id, current); + free_window_logo(*table, ¤t); + } + HASH_CLEAR(hh_path, (*table)->by_path); + free(*table); *table = NULL; } diff --git a/kitty/window_logo.h b/kitty/window_logo.h index 686307399..711b46e24 100644 --- a/kitty/window_logo.h +++ b/kitty/window_logo.h @@ -8,22 +8,31 @@ #include "kitty-uthash.h" -#define WindowLogoHead \ - unsigned int height, width; \ - bool load_from_disk_ok; \ - uint32_t texture_id; \ - uint8_t* bitmap; - +typedef unsigned int window_logo_id_t; typedef struct WindowLogo { - WindowLogoHead + unsigned int height, width; + bool load_from_disk_ok; + uint32_t texture_id; + uint8_t* bitmap; } WindowLogo; +typedef struct WindowLogoTable WindowLogoTable; + +window_logo_id_t +find_or_create_window_logo(WindowLogoTable *table, const char *path); + WindowLogo* -find_or_create_window_logo(WindowLogo **head, const char *path); +find_window_logo(WindowLogoTable *table, window_logo_id_t id); void -decref_window_logo(WindowLogo **head, WindowLogo** logo); +decref_window_logo(WindowLogoTable *table, window_logo_id_t id); void set_on_gpu_state(WindowLogo *logo, bool on_gpu); + +WindowLogoTable* +alloc_window_logo_table(void); + +void +free_window_logo_table(WindowLogoTable **table);