* shr using `make-xwidget' incorrectly
[not found] <87sfw31mok.fsf.ref@yahoo.com>
@ 2021-11-11 1:54 ` Po Lu
2021-11-11 3:26 ` Lars Ingebrigtsen
2021-11-11 6:58 ` shr using `make-xwidget' incorrectly Eli Zaretskii
0 siblings, 2 replies; 23+ messages in thread
From: Po Lu @ 2021-11-11 1:54 UTC (permalink / raw)
To: emacs-devel; +Cc: larsi
Lars, you might want to know that `make-xwidget', invoked without a
buffer argument, will create an xwidget attached to the current buffer.
That xwidget won't be killed until you kill the buffer it's attached to.
So you should either try to re-use existing xwidgets (see
`get-buffer-xwidgets'), or to kill the buffer the xwidget is attached
to. Otherwise, every re-render will cause more xwidgets to be created,
leading to undesirable resource consumption (WebKit widgets are heavy!).
Which reminds me of another problem (in the Emacs 28 xwidget code as
well): If an xwidget's buffer is killed, but references to it still
exist somewhere, crashes can happen, because the GTK resources allocated
to the xwidget are killed in `kill_buffer_xwidgets' and not during
garbage collection.
I think the best thing to do in this case would be to introduce a
`dead' state for xwidgets, not unlike killed buffers and dead frames,
which an xwidget is set to after being killed.
Then, performing any sort of operation on a killed xwidget can either
throw an error, or do nothing.
But I'd like the others to chime in as well. Thanks.
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: shr using `make-xwidget' incorrectly
2021-11-11 1:54 ` shr using `make-xwidget' incorrectly Po Lu
@ 2021-11-11 3:26 ` Lars Ingebrigtsen
2021-11-11 3:38 ` Po Lu
2021-11-11 6:37 ` Introduce "killed" state for xwidgets (Re: shr using `make-xwidget' incorrectly) Po Lu
2021-11-11 6:58 ` shr using `make-xwidget' incorrectly Eli Zaretskii
1 sibling, 2 replies; 23+ messages in thread
From: Lars Ingebrigtsen @ 2021-11-11 3:26 UTC (permalink / raw)
To: Po Lu; +Cc: emacs-devel
Po Lu <luangruo@yahoo.com> writes:
> Lars, you might want to know that `make-xwidget', invoked without a
> buffer argument, will create an xwidget attached to the current buffer.
>
> That xwidget won't be killed until you kill the buffer it's attached to.
Can't we fix that, though? The xwidget code could check whether it's
still displayed and then kill itself it it's not. It could work along
the lines of the `evaporate' overlay property mechanism, perhaps.
> Which reminds me of another problem (in the Emacs 28 xwidget code as
> well): If an xwidget's buffer is killed, but references to it still
> exist somewhere, crashes can happen, because the GTK resources allocated
> to the xwidget are killed in `kill_buffer_xwidgets' and not during
> garbage collection.
Yes, I've experienced that once already while testing.
> I think the best thing to do in this case would be to introduce a
> `dead' state for xwidgets, not unlike killed buffers and dead frames,
> which an xwidget is set to after being killed.
>
> Then, performing any sort of operation on a killed xwidget can either
> throw an error, or do nothing.
Sounds good to me.
--
(domestic pets only, the antidote for overdose, milk.)
bloggy blog: http://lars.ingebrigtsen.no
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: shr using `make-xwidget' incorrectly
2021-11-11 3:26 ` Lars Ingebrigtsen
@ 2021-11-11 3:38 ` Po Lu
2021-11-11 3:41 ` Lars Ingebrigtsen
2021-11-11 6:37 ` Introduce "killed" state for xwidgets (Re: shr using `make-xwidget' incorrectly) Po Lu
1 sibling, 1 reply; 23+ messages in thread
From: Po Lu @ 2021-11-11 3:38 UTC (permalink / raw)
To: Lars Ingebrigtsen; +Cc: emacs-devel
Lars Ingebrigtsen <larsi@gnus.org> writes:
>> Lars, you might want to know that `make-xwidget', invoked without a
>> buffer argument, will create an xwidget attached to the current buffer.
>>
>> That xwidget won't be killed until you kill the buffer it's attached to.
> Can't we fix that, though? The xwidget code could check whether it's
> still displayed and then kill itself it it's not. It could work along
> the lines of the `evaporate' overlay property mechanism, perhaps.
It's not a bug, but how xwidgets are designed, not unlike asynch
processes that have a buffer.
I find nothing wrong with this design of the xwidget system.
However, randomly killing xwidgets based on whether or not they are
displayed would be undesirable: xwidgets have a lot of state that cannot
be reconstituted through recreating them, and creating them takes a long
time and a lot of memory.
>> I think the best thing to do in this case would be to introduce a
>> `dead' state for xwidgets, not unlike killed buffers and dead frames,
>> which an xwidget is set to after being killed.
>>
>> Then, performing any sort of operation on a killed xwidget can either
>> throw an error, or do nothing.
> Sounds good to me.
Nice, I'll start working on it. Thanks.
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: shr using `make-xwidget' incorrectly
2021-11-11 3:38 ` Po Lu
@ 2021-11-11 3:41 ` Lars Ingebrigtsen
2021-11-11 3:43 ` Lars Ingebrigtsen
2021-11-11 4:46 ` Po Lu
0 siblings, 2 replies; 23+ messages in thread
From: Lars Ingebrigtsen @ 2021-11-11 3:41 UTC (permalink / raw)
To: Po Lu; +Cc: emacs-devel
Po Lu <luangruo@yahoo.com> writes:
> It's not a bug, but how xwidgets are designed, not unlike asynch
> processes that have a buffer.
I don't see the similarity -- killing the buffer will kill the xwidgets,
while killing the buffer won't kill the process. On the other hand,
deleting text in a buffer won't make the process become unavailable.
> I find nothing wrong with this design of the xwidget system.
>
> However, randomly killing xwidgets based on whether or not they are
> displayed would be undesirable: xwidgets have a lot of state that cannot
> be reconstituted through recreating them, and creating them takes a long
> time and a lot of memory.
There's nothing random about it. If the caller has marked the widgets
as being evaporable, then the caller wants those xwidgets to go away if
they're no longer displayed.
--
(domestic pets only, the antidote for overdose, milk.)
bloggy blog: http://lars.ingebrigtsen.no
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: shr using `make-xwidget' incorrectly
2021-11-11 3:41 ` Lars Ingebrigtsen
@ 2021-11-11 3:43 ` Lars Ingebrigtsen
2021-11-11 4:46 ` Po Lu
1 sibling, 0 replies; 23+ messages in thread
From: Lars Ingebrigtsen @ 2021-11-11 3:43 UTC (permalink / raw)
To: Po Lu; +Cc: emacs-devel
Lars Ingebrigtsen <larsi@gnus.org> writes:
> I don't see the similarity -- killing the buffer will kill the xwidgets,
> while killing the buffer won't kill the process.
Sorry, that's not correct (if that's the process-buffer of the process).
--
(domestic pets only, the antidote for overdose, milk.)
bloggy blog: http://lars.ingebrigtsen.no
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: shr using `make-xwidget' incorrectly
2021-11-11 3:41 ` Lars Ingebrigtsen
2021-11-11 3:43 ` Lars Ingebrigtsen
@ 2021-11-11 4:46 ` Po Lu
2021-11-11 4:56 ` Lars Ingebrigtsen
1 sibling, 1 reply; 23+ messages in thread
From: Po Lu @ 2021-11-11 4:46 UTC (permalink / raw)
To: Lars Ingebrigtsen; +Cc: emacs-devel
Lars Ingebrigtsen <larsi@gnus.org> writes:
> I don't see the similarity -- killing the buffer will kill the xwidgets,
> while killing the buffer won't kill the process. On the other hand,
> deleting text in a buffer won't make the process become unavailable.
Sorry, I meant only processes with associated buffers. This is how it
would make sense for xwidgets to behave as well.
BTW, it's impossible to cause an xwidget to become unavailable by
deleting text in a buffer: it'll always be available via
get-buffer-xwidgets, and there could be references to the xwidget in
other places.
At present, the only way to kill an xwidget (and to make it potentially
unavailable) is to kill the buffer it's associated with.
So even if we were to introduce an "evaporable" xwidget type, I think it
would only make sense to have it done as part of garbage collection.
>> However, randomly killing xwidgets based on whether or not they are
>> displayed would be undesirable: xwidgets have a lot of state that cannot
>> be reconstituted through recreating them, and creating them takes a long
>> time and a lot of memory.
> There's nothing random about it. If the caller has marked the widgets
> as being evaporable, then the caller wants those xwidgets to go away if
> they're no longer displayed.
Making xwidgets "evaporable" would cause a lot of overhead, I think.
For example, WebKitGTK may elect to save or delete cached resources, if
the reference count of the context and settings reaches zero.
(Which will always happen if the widget did not have another widget
passed to it as the `related' parameter to make-xwidget, and may happen
regardless.)
Another solution (that doesn't involve attaching xwidgets to the buffer
currently being rendered in) would be have shr attach xwidgets to a
buffer used only for shr to manage xwidgets, and for shr to "recycle"
the xwidgets each time something is rendered.
Please tell me if I'm missing anything, or you have more comments to
make.
Thanks in advance!
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: shr using `make-xwidget' incorrectly
2021-11-11 4:46 ` Po Lu
@ 2021-11-11 4:56 ` Lars Ingebrigtsen
2021-11-11 5:10 ` Po Lu
0 siblings, 1 reply; 23+ messages in thread
From: Lars Ingebrigtsen @ 2021-11-11 4:56 UTC (permalink / raw)
To: Po Lu; +Cc: emacs-devel
Po Lu <luangruo@yahoo.com> writes:
> BTW, it's impossible to cause an xwidget to become unavailable by
> deleting text in a buffer: it'll always be available via
> get-buffer-xwidgets, and there could be references to the xwidget in
> other places.
The same is true for overlays -- you can use `overlays-in' to find all
the overlays in the buffer, even if they aren't otherwise available. I
think modelling xwidget behaviour on overlays makes a lot of sense from
an UI point of view.
> Making xwidgets "evaporable" would cause a lot of overhead, I think.
>
> For example, WebKitGTK may elect to save or delete cached resources, if
> the reference count of the context and settings reaches zero.
>
> (Which will always happen if the widget did not have another widget
> passed to it as the `related' parameter to make-xwidget, and may happen
> regardless.)
I'm not sure what you mean here. Are you saying that a widget in a
buffer might just spontaneously disappear?
> Another solution (that doesn't involve attaching xwidgets to the buffer
> currently being rendered in) would be have shr attach xwidgets to a
> buffer used only for shr to manage xwidgets, and for shr to "recycle"
> the xwidgets each time something is rendered.
I don't think the functions that use xwidgets should have to know about
any of this stuff. Imagine if you'd have to jump through these hoops to
display images?
--
(domestic pets only, the antidote for overdose, milk.)
bloggy blog: http://lars.ingebrigtsen.no
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: shr using `make-xwidget' incorrectly
2021-11-11 4:56 ` Lars Ingebrigtsen
@ 2021-11-11 5:10 ` Po Lu
2021-11-11 12:33 ` Lars Ingebrigtsen
0 siblings, 1 reply; 23+ messages in thread
From: Po Lu @ 2021-11-11 5:10 UTC (permalink / raw)
To: Lars Ingebrigtsen; +Cc: emacs-devel
Lars Ingebrigtsen <larsi@gnus.org> writes:
> The same is true for overlays -- you can use `overlays-in' to find all
> the overlays in the buffer, even if they aren't otherwise available. I
> think modelling xwidget behaviour on overlays makes a lot of sense from
> an UI point of view.
Hmm, I will try to think of a reasonable way to implement this. But
IMO, it should be optional -- the existing behavior makes sense for many
use-cases.
> I'm not sure what you mean here. Are you saying that a widget in a
> buffer might just spontaneously disappear?
No, that killing a widget might take an unreasonable amount of time and
be surprising to be implemented like evaporating overlays are.
Imagine if the erasure of a few characters took upwards of 1 second,
deleting dozens of on-disk cache files. That is a situation that might
result from implementing evaporation of xwidgets like with overlays.
> I don't think the functions that use xwidgets should have to know about
> any of this stuff. Imagine if you'd have to jump through these hoops to
> display images?
Better comparison: imagine if `struct image' was a Lisp object (and not
an internal structure created on the basis of an image spec), held tens
of megabytes of memory, a lot of non-replicable state, an entire
language interpreter, and control over many cache files on-disk.
Then would it still be reasonable to delete `struct image's as part of
some routine pruning operation such as flushing the image cache, or the
erasure of a few characters in a buffer? I think not.
Thanks. But I will try my best to find an acceptable solution to this
problem.
^ permalink raw reply [flat|nested] 23+ messages in thread
* Introduce "killed" state for xwidgets (Re: shr using `make-xwidget' incorrectly)
2021-11-11 3:26 ` Lars Ingebrigtsen
2021-11-11 3:38 ` Po Lu
@ 2021-11-11 6:37 ` Po Lu
2021-11-11 7:59 ` Eli Zaretskii
2021-11-11 12:23 ` Lars Ingebrigtsen
1 sibling, 2 replies; 23+ messages in thread
From: Po Lu @ 2021-11-11 6:37 UTC (permalink / raw)
To: Lars Ingebrigtsen; +Cc: emacs-devel
[-- Attachment #1: Type: text/plain, Size: 369 bytes --]
Lars Ingebrigtsen <larsi@gnus.org> writes:
>> I think the best thing to do in this case would be to introduce a
>> `dead' state for xwidgets, not unlike killed buffers and dead frames,
>> which an xwidget is set to after being killed.
>>
>> Then, performing any sort of operation on a killed xwidget can either
>> throw an error, or do nothing.
> Sounds good to me.
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Prevent-crashes-in-xwidgets-whose-buffers-have-been-.patch --]
[-- Type: text/x-patch, Size: 12941 bytes --]
From 7db8a74c8eb463db9b4db20fb5c3964b28f1c521 Mon Sep 17 00:00:00 2001
From: Po Lu <luangruo@yahoo.com>
Date: Thu, 11 Nov 2021 14:29:12 +0800
Subject: [PATCH] Prevent crashes in xwidgets whose buffers have been killed
* doc/lispref/display.texi (Xwidgets): Explain meaning of killed
xwidgets.
* src/xwidget.c (Fxwidget_live_p): New function.
(Fxwidget_perform_lispy_event, WEBKIT_FN_INIT)
(Fxwidget_resize, Fxwidget_size_request)
(Fxwidget_info, Fxwidget_plist)
(Fset_xwidget_buffer, Fset_xwidget_plist)
(Fset_xwidget_query_on_exit_flag)
(Fxwidget_query_on_exit_flag)
(Fxwidget_webkit_search)
(Fxwidget_webkit_next_result)
(Fxwidget_webkit_previous_result)
(Fxwidget_webkit_finish_search)
(Fxwidget_webkit_load_html): Check for live xwidgets instead of
just xwidgets.
(xwidget_button, xwidget_motion_or_crossing)
(xv_do_draw, x_draw_xwidget_glyph_string)
(Fdelete_xwidget_view): Ignore killed xwidgets.
(syms_of_xwidget): Define new symbols and subrs and define
appropriate weakness of id_to_xwidget map.
(kill_buffer_xwidgets): Check live xwidgets instead of
killed xwidgets, set xwidget buffer to nil, and rely on GC to
free the hash table for us instead.
* src/xwidget.h (XWIDGET_LIVE_P, CHECK_LIVE_XWIDGET): New
macros.
---
doc/lispref/display.texi | 14 ++++-
src/xwidget.c | 116 +++++++++++++++++++++++++++------------
src/xwidget.h | 7 +++
3 files changed, 101 insertions(+), 36 deletions(-)
diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi
index 094bb5a5f3..63d2838eaa 100644
--- a/doc/lispref/display.texi
+++ b/doc/lispref/display.texi
@@ -6804,6 +6804,12 @@ Xwidgets
is used internally by the WebKit widget, and specifies another WebKit
widget that the newly created widget should share settings and
subprocesses with.
+
+The xwidget that is returned will be killed alongside its buffer
+(@pxref{Killing Buffers}). Once it is killed, the xwidget may
+continue to exist as a Lisp object and act as a @code{display}
+property until all references to it are gone, but most actions that
+can be performed on live xwidgets will no longer be available.
@end defun
@defun xwidgetp object
@@ -6811,6 +6817,11 @@ Xwidgets
@code{nil} otherwise.
@end defun
+@defun xwidget-live-p object
+This function returns @code{t} if @var{object} is an xwidget that
+hasn't been killed, and @code{nil} otherwise.
+@end defun
+
@defun xwidget-plist xwidget
This function returns the property list of @var{xwidget}.
@end defun
@@ -6821,7 +6832,8 @@ Xwidgets
@end defun
@defun xwidget-buffer xwidget
-This function returns the buffer of @var{xwidget}.
+This function returns the buffer of @var{xwidget}. If @var{xwidget}
+has been killed, it returns @code{nil}.
@end defun
@defun set-xwidget-buffer xwidget buffer
diff --git a/src/xwidget.c b/src/xwidget.c
index ace63e3742..4c18c531b9 100644
--- a/src/xwidget.c
+++ b/src/xwidget.c
@@ -273,6 +273,16 @@ DEFUN ("make-xwidget",
return val;
}
+DEFUN ("xwidget-live-p", Fxwidget_live_p, Sxwidget_live_p,
+ 1, 1, 0, doc: /* Return t if OBJECT is an xwidget that has not been killed.
+Value is nil if OBJECT is not an xwidget or if it has been killed. */)
+ (Lisp_Object object)
+{
+ return ((XWIDGETP (object)
+ && !NILP (XXWIDGET (object)->buffer))
+ ? Qt : Qnil);
+}
+
#ifdef USE_GTK
static void
set_widget_if_text_view (GtkWidget *widget, void *data)
@@ -305,7 +315,7 @@ DEFUN ("xwidget-perform-lispy-event",
GtkWidget *temp = NULL;
#endif
- CHECK_XWIDGET (xwidget);
+ CHECK_LIVE_XWIDGET (xwidget);
xw = XXWIDGET (xwidget);
if (!NILP (frame))
@@ -807,6 +817,9 @@ xwidget_button (struct xwidget_view *view,
bool down_p, int x, int y, int button,
int modifier_state, Time time)
{
+ if (NILP (XXWIDGET (view->model)->buffer))
+ return;
+
record_osr_embedder (view);
if (button < 4 || button > 8)
@@ -857,22 +870,29 @@ xwidget_button (struct xwidget_view *view,
void
xwidget_motion_or_crossing (struct xwidget_view *view, const XEvent *event)
{
- GdkEvent *xg_event = gdk_event_new (event->type == MotionNotify
- ? GDK_MOTION_NOTIFY
- : (event->type == LeaveNotify
- ? GDK_LEAVE_NOTIFY
- : GDK_ENTER_NOTIFY));
+ GdkEvent *xg_event;
struct xwidget *model = XXWIDGET (view->model);
int x;
int y;
- GtkWidget *target = find_widget_at_pos (model->widgetwindow_osr,
- (event->type == MotionNotify
- ? event->xmotion.x + view->clip_left
- : event->xcrossing.x + view->clip_left),
- (event->type == MotionNotify
- ? event->xmotion.y + view->clip_top
- : event->xcrossing.y + view->clip_top),
- &x, &y);
+ GtkWidget *target;
+
+ if (NILP (model->buffer))
+ return;
+
+ xg_event = gdk_event_new (event->type == MotionNotify
+ ? GDK_MOTION_NOTIFY
+ : (event->type == LeaveNotify
+ ? GDK_LEAVE_NOTIFY
+ : GDK_ENTER_NOTIFY));
+
+ target = find_widget_at_pos (model->widgetwindow_osr,
+ (event->type == MotionNotify
+ ? event->xmotion.x + view->clip_left
+ : event->xcrossing.x + view->clip_left),
+ (event->type == MotionNotify
+ ? event->xmotion.y + view->clip_top
+ : event->xcrossing.y + view->clip_top),
+ &x, &y);
if (!target)
target = model->widget_osr;
@@ -969,6 +989,13 @@ xv_do_draw (struct xwidget_view *xw, struct xwidget *w)
{
GtkOffscreenWindow *wnd;
cairo_surface_t *surface;
+
+ if (NILP (w->buffer))
+ {
+ XClearWindow (xw->dpy, xw->wdesc);
+ return;
+ }
+
block_input ();
wnd = GTK_OFFSCREEN_WINDOW (w->widgetwindow_osr);
surface = gtk_offscreen_window_get_surface (wnd);
@@ -1651,14 +1678,25 @@ x_draw_xwidget_glyph_string (struct glyph_string *s)
a redraw. It seems its possible to get out of sync with emacs
redraws so emacs background sometimes shows up instead of the
xwidgets background. It's just a visual glitch though. */
- if (!xwidget_hidden (xv))
+ /* When xww->buffer is nil, that means the xwidget has been killed. */
+ if (!NILP (xww->buffer))
{
+ if (!xwidget_hidden (xv))
+ {
#ifdef USE_GTK
- gtk_widget_queue_draw (xww->widget_osr);
+ gtk_widget_queue_draw (xww->widget_osr);
#elif defined NS_IMPL_COCOA
- nsxwidget_set_needsdisplay (xv);
+ nsxwidget_set_needsdisplay (xv);
#endif
+ }
+ }
+#ifdef USE_GTK
+ else
+ {
+ XSetWindowBackground (xv->dpy, xv->wdesc,
+ FRAME_BACKGROUND_PIXEL (s->f));
}
+#endif
#ifdef USE_GTK
unblock_input ();
@@ -1677,7 +1715,7 @@ xwidget_is_web_view (struct xwidget *xw)
/* Macro that checks xwidget hold webkit web view first. */
#define WEBKIT_FN_INIT() \
- CHECK_XWIDGET (xwidget); \
+ CHECK_LIVE_XWIDGET (xwidget); \
struct xwidget *xw = XXWIDGET (xwidget); \
if (!xwidget_is_web_view (xw)) \
{ \
@@ -1856,7 +1894,7 @@ DEFUN ("xwidget-resize", Fxwidget_resize, Sxwidget_resize, 3, 3, 0,
doc: /* Resize XWIDGET to NEW_WIDTH, NEW_HEIGHT. */ )
(Lisp_Object xwidget, Lisp_Object new_width, Lisp_Object new_height)
{
- CHECK_XWIDGET (xwidget);
+ CHECK_LIVE_XWIDGET (xwidget);
int w = check_integer_range (new_width, 0, INT_MAX);
int h = check_integer_range (new_height, 0, INT_MAX);
struct xwidget *xw = XXWIDGET (xwidget);
@@ -1907,7 +1945,7 @@ DEFUN ("xwidget-size-request",
Emacs allocated area accordingly. */)
(Lisp_Object xwidget)
{
- CHECK_XWIDGET (xwidget);
+ CHECK_LIVE_XWIDGET (xwidget);
#ifdef USE_GTK
GtkRequisition requisition;
gtk_widget_size_request (XXWIDGET (xwidget)->widget_osr, &requisition);
@@ -1942,7 +1980,7 @@ DEFUN ("xwidget-info",
Currently [TYPE TITLE WIDTH HEIGHT]. */)
(Lisp_Object xwidget)
{
- CHECK_XWIDGET (xwidget);
+ CHECK_LIVE_XWIDGET (xwidget);
struct xwidget *xw = XXWIDGET (xwidget);
return CALLN (Fvector, xw->type, xw->title,
make_fixed_natnum (xw->width), make_fixed_natnum (xw->height));
@@ -2005,7 +2043,7 @@ DEFUN ("delete-xwidget-view",
unblock_input ();
}
- if (xw->embedder_view == xv)
+ if (xw->embedder_view == xv && !NILP (xw->buffer))
{
w = gtk_widget_get_window (xw->widgetwindow_osr);
@@ -2054,7 +2092,7 @@ DEFUN ("xwidget-plist",
doc: /* Return the plist of XWIDGET. */)
(Lisp_Object xwidget)
{
- CHECK_XWIDGET (xwidget);
+ CHECK_LIVE_XWIDGET (xwidget);
return XXWIDGET (xwidget)->plist;
}
@@ -2074,7 +2112,7 @@ DEFUN ("set-xwidget-buffer",
doc: /* Set XWIDGET's buffer to BUFFER. */)
(Lisp_Object xwidget, Lisp_Object buffer)
{
- CHECK_XWIDGET (xwidget);
+ CHECK_LIVE_XWIDGET (xwidget);
CHECK_BUFFER (buffer);
XXWIDGET (xwidget)->buffer = buffer;
@@ -2088,7 +2126,7 @@ DEFUN ("set-xwidget-plist",
Returns PLIST. */)
(Lisp_Object xwidget, Lisp_Object plist)
{
- CHECK_XWIDGET (xwidget);
+ CHECK_LIVE_XWIDGET (xwidget);
CHECK_LIST (plist);
XXWIDGET (xwidget)->plist = plist;
@@ -2104,7 +2142,7 @@ DEFUN ("set-xwidget-query-on-exit-flag",
This function returns FLAG. */)
(Lisp_Object xwidget, Lisp_Object flag)
{
- CHECK_XWIDGET (xwidget);
+ CHECK_LIVE_XWIDGET (xwidget);
XXWIDGET (xwidget)->kill_without_query = NILP (flag);
return flag;
}
@@ -2115,7 +2153,7 @@ DEFUN ("xwidget-query-on-exit-flag",
doc: /* Return the current value of the query-on-exit flag for XWIDGET. */)
(Lisp_Object xwidget)
{
- CHECK_XWIDGET (xwidget);
+ CHECK_LIVE_XWIDGET (xwidget);
return (XXWIDGET (xwidget)->kill_without_query ? Qnil : Qt);
}
@@ -2148,7 +2186,7 @@ DEFUN ("xwidget-webkit-search", Fxwidget_webkit_search, Sxwidget_webkit_search,
#endif
CHECK_STRING (query);
- CHECK_XWIDGET (xwidget);
+ CHECK_LIVE_XWIDGET (xwidget);
#ifdef USE_GTK
xw = XXWIDGET (xwidget);
@@ -2192,7 +2230,7 @@ DEFUN ("xwidget-webkit-next-result", Fxwidget_webkit_next_result,
WebKitFindController *controller;
#endif
- CHECK_XWIDGET (xwidget);
+ CHECK_LIVE_XWIDGET (xwidget);
xw = XXWIDGET (xwidget);
if (!xw->find_text)
@@ -2224,7 +2262,7 @@ DEFUN ("xwidget-webkit-previous-result", Fxwidget_webkit_previous_result,
WebKitFindController *controller;
#endif
- CHECK_XWIDGET (xwidget);
+ CHECK_LIVE_XWIDGET (xwidget);
xw = XXWIDGET (xwidget);
if (!xw->find_text)
@@ -2256,7 +2294,7 @@ DEFUN ("xwidget-webkit-finish-search", Fxwidget_webkit_finish_search,
WebKitFindController *controller;
#endif
- CHECK_XWIDGET (xwidget);
+ CHECK_LIVE_XWIDGET (xwidget);
xw = XXWIDGET (xwidget);
if (!xw->find_text)
@@ -2294,7 +2332,7 @@ DEFUN ("xwidget-webkit-load-html", Fxwidget_webkit_load_html,
WebKitWebView *webview;
char *data, *uri;
- CHECK_XWIDGET (xwidget);
+ CHECK_LIVE_XWIDGET (xwidget);
CHECK_STRING (text);
if (NILP (base_uri))
base_uri = build_string ("about:blank");
@@ -2415,7 +2453,9 @@ syms_of_xwidget (void)
{
defsubr (&Smake_xwidget);
defsubr (&Sxwidgetp);
+ defsubr (&Sxwidget_live_p);
DEFSYM (Qxwidgetp, "xwidgetp");
+ DEFSYM (Qxwidget_live_p, "xwidget-live-p");
defsubr (&Sxwidget_view_p);
DEFSYM (Qxwidget_view_p, "xwidget-view-p");
defsubr (&Sxwidget_info);
@@ -2474,7 +2514,8 @@ syms_of_xwidget (void)
Fprovide (intern ("xwidget-internal"), Qnil);
- id_to_xwidget_map = CALLN (Fmake_hash_table, QCtest, Qeq);
+ id_to_xwidget_map = CALLN (Fmake_hash_table, QCtest, Qeq,
+ QCweakness, Qvalue);
staticpro (&id_to_xwidget_map);
#ifdef USE_GTK
@@ -2700,9 +2741,10 @@ kill_buffer_xwidgets (Lisp_Object buffer)
Vxwidget_list = Fdelq (xwidget, Vxwidget_list);
/* TODO free the GTK things in xw. */
{
- CHECK_XWIDGET (xwidget);
+ CHECK_LIVE_XWIDGET (xwidget);
struct xwidget *xw = XXWIDGET (xwidget);
- Fremhash (make_fixnum (xw->xwidget_id), id_to_xwidget_map);
+ xw->buffer = Qnil;
+
#ifdef USE_GTK
if (xw->widget_osr && xw->widgetwindow_osr)
{
@@ -2719,6 +2761,10 @@ kill_buffer_xwidgets (Lisp_Object buffer)
xfree (xmint_pointer (XCAR (cb)));
ASET (xw->script_callbacks, idx, Qnil);
}
+
+ xw->widget_osr = NULL;
+ xw->widgetwindow_osr = NULL;
+ xw->find_text = NULL;
#elif defined NS_IMPL_COCOA
nsxwidget_kill (xw);
#endif
diff --git a/src/xwidget.h b/src/xwidget.h
index 6e6b39c8b4..4377b50e84 100644
--- a/src/xwidget.h
+++ b/src/xwidget.h
@@ -138,9 +138,16 @@ #define XWIDGETP(x) PSEUDOVECTORP (x, PVEC_XWIDGET)
#define XXWIDGET(a) (eassert (XWIDGETP (a)), \
XUNTAG (a, Lisp_Vectorlike, struct xwidget))
+#define XWIDGET_LIVE_P(w) (!NILP ((w)->buffer))
+
#define CHECK_XWIDGET(x) \
CHECK_TYPE (XWIDGETP (x), Qxwidgetp, x)
+#define CHECK_LIVE_XWIDGET(x) \
+ CHECK_TYPE ((XWIDGETP (x) \
+ && XWIDGET_LIVE_P (XXWIDGET (x))), \
+ Qxwidget_live_p, x)
+
/* Test for xwidget_view pseudovector. */
#define XWIDGET_VIEW_P(x) PSEUDOVECTORP (x, PVEC_XWIDGET_VIEW)
#define XXWIDGET_VIEW(a) (eassert (XWIDGET_VIEW_P (a)), \
--
2.31.1
[-- Attachment #3: Type: text/plain, Size: 112 bytes --]
Thanks, how does this look to you? And perhaps Eli has something to
say about it as well.
Thanks in advance.
^ permalink raw reply related [flat|nested] 23+ messages in thread
* Re: shr using `make-xwidget' incorrectly
2021-11-11 1:54 ` shr using `make-xwidget' incorrectly Po Lu
2021-11-11 3:26 ` Lars Ingebrigtsen
@ 2021-11-11 6:58 ` Eli Zaretskii
2021-11-11 7:05 ` Po Lu
1 sibling, 1 reply; 23+ messages in thread
From: Eli Zaretskii @ 2021-11-11 6:58 UTC (permalink / raw)
To: Po Lu; +Cc: larsi, emacs-devel
> From: Po Lu <luangruo@yahoo.com>
> Cc: larsi@gnus.org
> Date: Thu, 11 Nov 2021 09:54:51 +0800
>
> Which reminds me of another problem (in the Emacs 28 xwidget code as
> well): If an xwidget's buffer is killed, but references to it still
> exist somewhere, crashes can happen, because the GTK resources allocated
> to the xwidget are killed in `kill_buffer_xwidgets' and not during
> garbage collection.
>
> I think the best thing to do in this case would be to introduce a
> `dead' state for xwidgets, not unlike killed buffers and dead frames,
> which an xwidget is set to after being killed.
>
> Then, performing any sort of operation on a killed xwidget can either
> throw an error, or do nothing.
Why can't we release the GTK resources when such a buffer is killed?
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: shr using `make-xwidget' incorrectly
2021-11-11 6:58 ` shr using `make-xwidget' incorrectly Eli Zaretskii
@ 2021-11-11 7:05 ` Po Lu
2021-11-11 8:01 ` Eli Zaretskii
0 siblings, 1 reply; 23+ messages in thread
From: Po Lu @ 2021-11-11 7:05 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: larsi, emacs-devel
Eli Zaretskii <eliz@gnu.org> writes:
>> Which reminds me of another problem (in the Emacs 28 xwidget code as
>> well): If an xwidget's buffer is killed, but references to it still
>> exist somewhere, crashes can happen, because the GTK resources allocated
>> to the xwidget are killed in `kill_buffer_xwidgets' and not during
>> garbage collection.
>>
>> I think the best thing to do in this case would be to introduce a
>> `dead' state for xwidgets, not unlike killed buffers and dead frames,
>> which an xwidget is set to after being killed.
>>
>> Then, performing any sort of operation on a killed xwidget can either
>> throw an error, or do nothing.
> Why can't we release the GTK resources when such a buffer is killed?
We are releasing the GTK resources when such a buffer is killed. This
is the problem here: code that uses `CHECK_XWIDGET' won't catch the case
where the GTK resources are released, but there are still references to
the xwidget, which causes use-after-frees when trying to redisplay the
xwidget, or when calling, say, `xwidget-webkit-goto-uri' on the xwidget.
The comment in kill_buffer_xwidgets that says:
/* TODO free the GTK things in xw. */
Is probably outdated and likely should be removed. But I am still
investigating through the history of that file to make sure of that, so
please bear with me for a while.
Thanks.
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: Introduce "killed" state for xwidgets (Re: shr using `make-xwidget' incorrectly)
2021-11-11 6:37 ` Introduce "killed" state for xwidgets (Re: shr using `make-xwidget' incorrectly) Po Lu
@ 2021-11-11 7:59 ` Eli Zaretskii
2021-11-11 9:28 ` Po Lu
2021-11-11 12:23 ` Lars Ingebrigtsen
1 sibling, 1 reply; 23+ messages in thread
From: Eli Zaretskii @ 2021-11-11 7:59 UTC (permalink / raw)
To: Po Lu; +Cc: larsi, emacs-devel
> From: Po Lu <luangruo@yahoo.com>
> Cc: emacs-devel@gnu.org
> Date: Thu, 11 Nov 2021 14:37:49 +0800
>
> +DEFUN ("xwidget-live-p", Fxwidget_live_p, Sxwidget_live_p,
> + 1, 1, 0, doc: /* Return t if OBJECT is an xwidget that has not been killed.
> +Value is nil if OBJECT is not an xwidget or if it has been killed. */)
> + (Lisp_Object object)
> +{
> + return ((XWIDGETP (object)
> + && !NILP (XXWIDGET (object)->buffer))
> + ? Qt : Qnil);
> +}
What if the xwidget's buffer was itself killed? should this also test
that situation?
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: shr using `make-xwidget' incorrectly
2021-11-11 7:05 ` Po Lu
@ 2021-11-11 8:01 ` Eli Zaretskii
2021-11-11 9:27 ` Po Lu
0 siblings, 1 reply; 23+ messages in thread
From: Eli Zaretskii @ 2021-11-11 8:01 UTC (permalink / raw)
To: Po Lu; +Cc: larsi, emacs-devel
> From: Po Lu <luangruo@yahoo.com>
> Cc: larsi@gnus.org, emacs-devel@gnu.org
> Date: Thu, 11 Nov 2021 15:05:19 +0800
>
> Eli Zaretskii <eliz@gnu.org> writes:
>
> >> I think the best thing to do in this case would be to introduce a
> >> `dead' state for xwidgets, not unlike killed buffers and dead frames,
> >> which an xwidget is set to after being killed.
> >>
> >> Then, performing any sort of operation on a killed xwidget can either
> >> throw an error, or do nothing.
>
> > Why can't we release the GTK resources when such a buffer is killed?
>
> We are releasing the GTK resources when such a buffer is killed. This
> is the problem here: code that uses `CHECK_XWIDGET' won't catch the case
> where the GTK resources are released, but there are still references to
> the xwidget, which causes use-after-frees when trying to redisplay the
> xwidget, or when calling, say, `xwidget-webkit-goto-uri' on the xwidget.
Isn't there some indication in the xwidget that its GTK resources were
freed? If not, can we add such an indication and set it when we free
those resources?
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: shr using `make-xwidget' incorrectly
2021-11-11 8:01 ` Eli Zaretskii
@ 2021-11-11 9:27 ` Po Lu
0 siblings, 0 replies; 23+ messages in thread
From: Po Lu @ 2021-11-11 9:27 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: larsi, emacs-devel
Eli Zaretskii <eliz@gnu.org> writes:
>> We are releasing the GTK resources when such a buffer is killed. This
>> is the problem here: code that uses `CHECK_XWIDGET' won't catch the case
>> where the GTK resources are released, but there are still references to
>> the xwidget, which causes use-after-frees when trying to redisplay the
>> xwidget, or when calling, say, `xwidget-webkit-goto-uri' on the xwidget.
> Isn't there some indication in the xwidget that its GTK resources were
> freed? If not, can we add such an indication and set it when we free
> those resources?
There isn't, but I added one in the patch I sent Lars.
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: Introduce "killed" state for xwidgets (Re: shr using `make-xwidget' incorrectly)
2021-11-11 7:59 ` Eli Zaretskii
@ 2021-11-11 9:28 ` Po Lu
0 siblings, 0 replies; 23+ messages in thread
From: Po Lu @ 2021-11-11 9:28 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: larsi, emacs-devel
Eli Zaretskii <eliz@gnu.org> writes:
>> From: Po Lu <luangruo@yahoo.com>
>> Cc: emacs-devel@gnu.org
>> Date: Thu, 11 Nov 2021 14:37:49 +0800
>>
>> +DEFUN ("xwidget-live-p", Fxwidget_live_p, Sxwidget_live_p,
>> + 1, 1, 0, doc: /* Return t if OBJECT is an xwidget that has not been killed.
>> +Value is nil if OBJECT is not an xwidget or if it has been killed. */)
>> + (Lisp_Object object)
>> +{
>> + return ((XWIDGETP (object)
>> + && !NILP (XXWIDGET (object)->buffer))
>> + ? Qt : Qnil);
>> +}
>
> What if the xwidget's buffer was itself killed? should this also test
> that situation?
When the buffer is killed, all of its xwidgets are killed first, which
means XXWIDGET (object)->buffer will always be nil in that case.
Thanks.
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: Introduce "killed" state for xwidgets (Re: shr using `make-xwidget' incorrectly)
2021-11-11 6:37 ` Introduce "killed" state for xwidgets (Re: shr using `make-xwidget' incorrectly) Po Lu
2021-11-11 7:59 ` Eli Zaretskii
@ 2021-11-11 12:23 ` Lars Ingebrigtsen
2021-11-11 12:25 ` Po Lu
1 sibling, 1 reply; 23+ messages in thread
From: Lars Ingebrigtsen @ 2021-11-11 12:23 UTC (permalink / raw)
To: Po Lu; +Cc: emacs-devel
Po Lu <luangruo@yahoo.com> writes:
> Subject: [PATCH] Prevent crashes in xwidgets whose buffers have been killed
Looks good to me.
--
(domestic pets only, the antidote for overdose, milk.)
bloggy blog: http://lars.ingebrigtsen.no
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: Introduce "killed" state for xwidgets (Re: shr using `make-xwidget' incorrectly)
2021-11-11 12:23 ` Lars Ingebrigtsen
@ 2021-11-11 12:25 ` Po Lu
2021-11-11 15:10 ` Eli Zaretskii
0 siblings, 1 reply; 23+ messages in thread
From: Po Lu @ 2021-11-11 12:25 UTC (permalink / raw)
To: Lars Ingebrigtsen; +Cc: emacs-devel
Lars Ingebrigtsen <larsi@gnus.org> writes:
> Looks good to me.
Thanks. If it looks good to Eli, I'll push.
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: shr using `make-xwidget' incorrectly
2021-11-11 5:10 ` Po Lu
@ 2021-11-11 12:33 ` Lars Ingebrigtsen
2021-11-11 12:37 ` Po Lu
0 siblings, 1 reply; 23+ messages in thread
From: Lars Ingebrigtsen @ 2021-11-11 12:33 UTC (permalink / raw)
To: Po Lu; +Cc: emacs-devel
Po Lu <luangruo@yahoo.com> writes:
>> The same is true for overlays -- you can use `overlays-in' to find all
>> the overlays in the buffer, even if they aren't otherwise available. I
>> think modelling xwidget behaviour on overlays makes a lot of sense from
>> an UI point of view.
>
> Hmm, I will try to think of a reasonable way to implement this. But
> IMO, it should be optional -- the existing behavior makes sense for many
> use-cases.
Yes, indeed.
(And I was wondering why the xwidgets were still playing video when I
hit "back" in the eww history, and landed on a page with a video
again -- but they'd been updating the whole time, even if they'd not
been on screen, I understand now.)
> No, that killing a widget might take an unreasonable amount of time and
> be surprising to be implemented like evaporating overlays are.
>
> Imagine if the erasure of a few characters took upwards of 1 second,
> deleting dozens of on-disk cache files. That is a situation that might
> result from implementing evaporation of xwidgets like with overlays.
Oh, sure. I don't expect anybody to be doing exactly that with videos,
for instance, but I think it's a reasonable expectation that a mode that
inserts a video into the buffer shouldn't have to do ... a lot of work
to remove the video, either. I mean, if that's feasible, it would be
nice.
> Better comparison: imagine if `struct image' was a Lisp object (and not
> an internal structure created on the basis of an image spec), held tens
> of megabytes of memory, a lot of non-replicable state, an entire
> language interpreter, and control over many cache files on-disk.
That describes animated images quite well. :-) (OK, the animation
itself is controlled from Lisp land, but there's a bunch of caches and
megabytes of data...)
Hm... looking at the code in `image-animate-timeout', it may suffer
from some of the same issues...
--
(domestic pets only, the antidote for overdose, milk.)
bloggy blog: http://lars.ingebrigtsen.no
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: shr using `make-xwidget' incorrectly
2021-11-11 12:33 ` Lars Ingebrigtsen
@ 2021-11-11 12:37 ` Po Lu
2021-11-11 12:43 ` Lars Ingebrigtsen
0 siblings, 1 reply; 23+ messages in thread
From: Po Lu @ 2021-11-11 12:37 UTC (permalink / raw)
To: Lars Ingebrigtsen; +Cc: emacs-devel
Lars Ingebrigtsen <larsi@gnus.org> writes:
> Oh, sure. I don't expect anybody to be doing exactly that with videos,
> for instance, but I think it's a reasonable expectation that a mode that
> inserts a video into the buffer shouldn't have to do ... a lot of work
> to remove the video, either. I mean, if that's feasible, it would be
> nice.
We could have a separate kind of xwidget for multimedia. I think there
would be no need to abuse WebKit for this, if that existed.
GStreamer and GTK seem to provide the necessary APIs for dealing with
video streams over the network.
I will look into that, thanks.
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: shr using `make-xwidget' incorrectly
2021-11-11 12:37 ` Po Lu
@ 2021-11-11 12:43 ` Lars Ingebrigtsen
2021-11-11 12:47 ` Po Lu
0 siblings, 1 reply; 23+ messages in thread
From: Lars Ingebrigtsen @ 2021-11-11 12:43 UTC (permalink / raw)
To: Po Lu; +Cc: emacs-devel
Po Lu <luangruo@yahoo.com> writes:
> We could have a separate kind of xwidget for multimedia. I think there
> would be no need to abuse WebKit for this, if that existed.
>
> GStreamer and GTK seem to provide the necessary APIs for dealing with
> video streams over the network.
>
> I will look into that, thanks.
That's be great -- I think most of the "lightweight" incantations of an
xwidget would be for videos and audio, so avoiding firing up Webkit
would be nice.
But the programming UI niceties would still be the same, though (i.e.,
an expectation that we can "make it go away" by deleting it).
--
(domestic pets only, the antidote for overdose, milk.)
bloggy blog: http://lars.ingebrigtsen.no
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: shr using `make-xwidget' incorrectly
2021-11-11 12:43 ` Lars Ingebrigtsen
@ 2021-11-11 12:47 ` Po Lu
0 siblings, 0 replies; 23+ messages in thread
From: Po Lu @ 2021-11-11 12:47 UTC (permalink / raw)
To: Lars Ingebrigtsen; +Cc: emacs-devel
Lars Ingebrigtsen <larsi@gnus.org> writes:
> That's be great -- I think most of the "lightweight" incantations of an
> xwidget would be for videos and audio, so avoiding firing up Webkit
> would be nice.
>
> But the programming UI niceties would still be the same, though (i.e.,
> an expectation that we can "make it go away" by deleting it).
Yes, it would be reasonable to implement such a feature with a separate
video xwidget. It's just that doing this wth WebKitWebViews makes me
shudder...
Thanks.
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: Introduce "killed" state for xwidgets (Re: shr using `make-xwidget' incorrectly)
2021-11-11 12:25 ` Po Lu
@ 2021-11-11 15:10 ` Eli Zaretskii
2021-11-12 0:18 ` Po Lu
0 siblings, 1 reply; 23+ messages in thread
From: Eli Zaretskii @ 2021-11-11 15:10 UTC (permalink / raw)
To: Po Lu; +Cc: larsi, emacs-devel
> From: Po Lu <luangruo@yahoo.com>
> Cc: emacs-devel@gnu.org
> Date: Thu, 11 Nov 2021 20:25:43 +0800
>
> Lars Ingebrigtsen <larsi@gnus.org> writes:
>
> > Looks good to me.
>
> Thanks. If it looks good to Eli, I'll push.
Yes, LGTM. Thanks.
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: Introduce "killed" state for xwidgets (Re: shr using `make-xwidget' incorrectly)
2021-11-11 15:10 ` Eli Zaretskii
@ 2021-11-12 0:18 ` Po Lu
0 siblings, 0 replies; 23+ messages in thread
From: Po Lu @ 2021-11-12 0:18 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: larsi, emacs-devel
Eli Zaretskii <eliz@gnu.org> writes:
>> From: Po Lu <luangruo@yahoo.com>
>> Cc: emacs-devel@gnu.org
>> Date: Thu, 11 Nov 2021 20:25:43 +0800
>>
>> Lars Ingebrigtsen <larsi@gnus.org> writes:
>>
>> > Looks good to me.
>>
>> Thanks. If it looks good to Eli, I'll push.
>
> Yes, LGTM. Thanks.
Thanks, pushed.
^ permalink raw reply [flat|nested] 23+ messages in thread
end of thread, other threads:[~2021-11-12 0:18 UTC | newest]
Thread overview: 23+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <87sfw31mok.fsf.ref@yahoo.com>
2021-11-11 1:54 ` shr using `make-xwidget' incorrectly Po Lu
2021-11-11 3:26 ` Lars Ingebrigtsen
2021-11-11 3:38 ` Po Lu
2021-11-11 3:41 ` Lars Ingebrigtsen
2021-11-11 3:43 ` Lars Ingebrigtsen
2021-11-11 4:46 ` Po Lu
2021-11-11 4:56 ` Lars Ingebrigtsen
2021-11-11 5:10 ` Po Lu
2021-11-11 12:33 ` Lars Ingebrigtsen
2021-11-11 12:37 ` Po Lu
2021-11-11 12:43 ` Lars Ingebrigtsen
2021-11-11 12:47 ` Po Lu
2021-11-11 6:37 ` Introduce "killed" state for xwidgets (Re: shr using `make-xwidget' incorrectly) Po Lu
2021-11-11 7:59 ` Eli Zaretskii
2021-11-11 9:28 ` Po Lu
2021-11-11 12:23 ` Lars Ingebrigtsen
2021-11-11 12:25 ` Po Lu
2021-11-11 15:10 ` Eli Zaretskii
2021-11-12 0:18 ` Po Lu
2021-11-11 6:58 ` shr using `make-xwidget' incorrectly Eli Zaretskii
2021-11-11 7:05 ` Po Lu
2021-11-11 8:01 ` Eli Zaretskii
2021-11-11 9:27 ` Po Lu
Code repositories for project(s) associated with this public inbox
https://git.savannah.gnu.org/cgit/emacs.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).