Fix storage of window logos

Store by id not pointer since the pointers are not stable. And use two
hash maps by path and by id for fast lookup.
This commit is contained in:
Kovid Goyal
2021-12-03 17:43:45 +05:30
parent b8b495ac31
commit 6f48dda8b9
5 changed files with 92 additions and 38 deletions

View File

@@ -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;

View File

@@ -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, &region_desc) != 0) return false;
Py_INCREF((PyObject *) &RegionType);

View File

@@ -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;

View File

@@ -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, &current);
}
HASH_CLEAR(hh_path, (*table)->by_path);
free(*table); *table = NULL;
}

View File

@@ -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);