=> f6aea1fd30c97e9e799ae324ae7a32a66d6f6572
[1mdiff --git a/src/app.c b/src/app.c[m [1mindex 7dae4b2f..590913cf 100644[m [1m--- a/src/app.c[m [1m+++ b/src/app.c[m [36m@@ -2283,6 +2283,7 @@[m [mvoid refresh_App(void) {[m init_PtrArray(&windows);[m listWindows_App_(d, &windows);[m /* Destroy pending widgets. */ {[m [32m+[m[32m clearRecentlyDeleted_Widget();[m iConstForEach(PtrArray, j, &windows) {[m iWindow *win = j.ptr;[m setCurrent_Window(win);[m [1mdiff --git a/src/ui/command.c b/src/ui/command.c[m [1mindex 307fd44c..49a4ad60 100644[m [1m--- a/src/ui/command.c[m [1m+++ b/src/ui/command.c[m [36m@@ -21,6 +21,7 @@[m [mANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT[m SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */[m [m #include "command.h"[m [32m+[m[32m#include "widget.h"[m #include "app.h"[m [m #include[m [36m@@ -122,7 +123,12 @@[m [mvoid *pointerLabel_Command(const char *cmd, const char *label) {[m }[m [m void *pointer_Command(const char *cmd) {[m [31m- return pointerLabel_Command(cmd, "ptr");[m [32m+[m[32m void *ptr = pointerLabel_Command(cmd, "ptr");[m [32m+[m[32m if (isRecentlyDeleted_Widget(ptr)) {[m [32m+[m[32m /* This widget has been marked as deleted, so we cannot reference it any more. */[m [32m+[m[32m return NULL;[m [32m+[m[32m }[m [32m+[m[32m return ptr;[m }[m [m const char *suffixPtr_Command(const char *cmd, const char *label) {[m [1mdiff --git a/src/ui/widget.c b/src/ui/widget.c[m [1mindex 2ba742be..014cad64 100644[m [1m--- a/src/ui/widget.c[m [1m+++ b/src/ui/widget.c[m [36m@@ -52,6 +52,32 @@[m [mstruct Impl_WidgetDrawBuffer {[m iInt2 oldOrigin;[m };[m [m [32m+[m[32miDeclareType(RecentlyDeleted)[m [32m+[m [32m+[m[32m/* Keep track of widgets that were recently deleted, so events related to them can be ignored. */[m [32m+[m[32mstruct Impl_RecentlyDeleted {[m [32m+[m[32m iMutex mtx; /* async callbacks must not post events related to deleted widgets */[m [32m+[m[32m iPtrSet * objs;[m [32m+[m[32m};[m [32m+[m[32mstatic iRecentlyDeleted recentlyDeleted_;[m [32m+[m [32m+[m[32mstatic void maybeInit_RecentlyDeleted_(iRecentlyDeleted *d) {[m [32m+[m[32m if (!d->objs) {[m [32m+[m[32m init_Mutex(&d->mtx);[m [32m+[m[32m d->objs = new_PtrSet();[m [32m+[m[32m }[m [32m+[m[32m}[m [32m+[m [32m+[m[32mstatic iBool contains_RecentlyDeleted_(iRecentlyDeleted *d, const iAnyObject *obj) {[m [32m+[m[32m if (d->objs && obj) {[m [32m+[m[32m lock_Mutex(&d->mtx);[m [32m+[m[32m const iBool wasDel = contains_PtrSet(d->objs, obj);[m [32m+[m[32m unlock_Mutex(&d->mtx);[m [32m+[m[32m return wasDel;[m [32m+[m[32m }[m [32m+[m[32m return iFalse;[m [32m+[m[32m}[m [32m+[m static void init_WidgetDrawBuffer(iWidgetDrawBuffer *d) {[m d->texture = NULL;[m d->size = zero_I2();[m [36m@@ -175,6 +201,7 @@[m [mstatic int treeSize_Widget_(const iWidget *d, int n) {[m }[m [m void deinit_Widget(iWidget *d) {[m [32m+[m[32m addRecentlyDeleted_Widget(d);[m if (d->flags2 & usedAsPeriodicContext_WidgetFlag2) {[m remove_Periodic(periodic_App(), d); /* periodic context being deleted */[m }[m [36m@@ -2401,6 +2428,9 @@[m [miWidget *mouseGrab_Widget(void) {[m }[m [m void postCommand_Widget(const iAnyObject *d, const char *cmd, ...) {[m [32m+[m[32m if (isRecentlyDeleted_Widget(d)) {[m [32m+[m[32m return; /* invalid context */[m [32m+[m[32m }[m iString str;[m init_String(&str); {[m va_list args;[m [36m@@ -2547,3 +2577,21 @@[m [mvoid identify_Widget(const iWidget *d) {[m printf("Root %d: %p\n", 1 + (d->root == get_Window()->roots[1]), d->root);[m fflush(stdout);[m }[m [32m+[m [32m+[m[32mvoid addRecentlyDeleted_Widget(iAnyObject *obj) {[m [32m+[m[32m /* We sometimes include pointers to widgets in command events. Before an event is processed,[m [32m+[m[32m it is possible that the referened widget has been destroyed. Keeping track of recently[m [32m+[m[32m deleted widgets allows ignoring these events. */[m [32m+[m[32m maybeInit_RecentlyDeleted_(&recentlyDeleted_);[m [32m+[m[32m iGuardMutex(&recentlyDeleted_.mtx, insert_PtrSet(recentlyDeleted_.objs, obj));[m [32m+[m[32m}[m [32m+[m [32m+[m[32mvoid clearRecentlyDeleted_Widget(void) {[m [32m+[m[32m if (recentlyDeleted_.objs) {[m [32m+[m[32m iGuardMutex(&recentlyDeleted_.mtx, clear_PtrSet(recentlyDeleted_.objs));[m [32m+[m[32m }[m [32m+[m[32m}[m [32m+[m [32m+[m[32miBool isRecentlyDeleted_Widget(const iAnyObject *obj) {[m [32m+[m[32m return contains_RecentlyDeleted_(&recentlyDeleted_, obj);[m [32m+[m[32m}[m [1mdiff --git a/src/ui/widget.h b/src/ui/widget.h[m [1mindex 940604df..61fafe35 100644[m [1m--- a/src/ui/widget.h[m [1m+++ b/src/ui/widget.h[m [36m@@ -357,3 +357,8 @@[m [miBool hasVisibleChildOnTop_Widget[m (const iWidget *parent);[m void printTree_Widget (const iWidget *);[m void identify_Widget (const iWidget *); /* prints to stdout */[m [32m+[m [32m+[m[32mvoid addRecentlyDeleted_Widget (iAnyObject *obj);[m [32m+[m[32miBool isRecentlyDeleted_Widget (const iAnyObject *obj);[m [32m+[m[32mvoid clearRecentlyDeleted_Widget (void);[m [41m+ [m
text/gemini; charset=utf-8
This content has been proxied by September (3851b).