Prevent crashes when embedding Emacs in a nonexistent parent

* src/xfns.c (x_window, Fx_create_frame): Handle X errors while
trying to reparent the frame onto an explicitly specified
parent.
* src/xterm.c (handle_one_xevent): Handle unparenting embedded
windows correctly.  This only works if the embedder is aware of
the fixes extension and has put the window into the right save
set.
(x_embed_frame): New function.
* src/xterm.h (FRAME_X_EMBEDDED_P): Fix coding style.
This commit is contained in:
Po Lu 2022-09-02 17:19:29 +08:00
parent 0ec831b91c
commit 2ff5763836
3 changed files with 48 additions and 7 deletions

View file

@ -3955,10 +3955,6 @@ x_window (struct frame *f, long window_prompting)
XtManageChild (pane_widget);
XtRealizeWidget (shell_widget);
if (FRAME_X_EMBEDDED_P (f))
XReparentWindow (FRAME_X_DISPLAY (f), XtWindow (shell_widget),
f->output_data.x->parent_desc, 0, 0);
FRAME_X_WINDOW (f) = XtWindow (frame_widget);
initial_set_up_x_back_buffer (f);
validate_x_resource_name ();
@ -4132,7 +4128,7 @@ x_window (struct frame *f)
block_input ();
FRAME_X_WINDOW (f)
= XCreateWindow (FRAME_X_DISPLAY (f),
f->output_data.x->parent_desc,
FRAME_DISPLAY_INFO (f)->root_window,
f->left_pos,
f->top_pos,
FRAME_PIXEL_WIDTH (f), FRAME_PIXEL_HEIGHT (f),
@ -4958,6 +4954,12 @@ This function is an internal primitive--use `make-frame' instead. */)
x_window (f);
#endif
#ifndef USE_GTK
if (FRAME_X_EMBEDDED_P (f)
&& !x_embed_frame (dpyinfo, f))
error ("The frame could not be embedded; does the embedder exist?");
#endif
x_icon (f, parms);
x_make_gc (f);

View file

@ -18416,6 +18416,20 @@ handle_one_xevent (struct x_display_info *dpyinfo,
f = x_top_window_to_frame (dpyinfo, event->xreparent.window);
if (f)
{
#ifndef USE_GTK
if (FRAME_OUTPUT_DATA (f)->parent_desc
&& FRAME_X_EMBEDDED_P (f))
{
/* The frame's embedder was destroyed; mark the frame as
no longer embedded, and map the frame. An
UnmapNotify event must have previously been received
during the start of save-set processing. */
FRAME_X_OUTPUT (f)->explicit_parent = false;
x_make_frame_visible (f);
}
#endif
/* Maybe we shouldn't set this for child frames ?? */
f->output_data.x->parent_desc = event->xreparent.parent;
@ -27456,6 +27470,31 @@ x_get_atom_name (struct x_display_info *dpyinfo, Atom atom,
return value;
}
#ifndef USE_GTK
/* Set up XEmbed for F, and change its save set to handle the parent
being destroyed. */
bool
x_embed_frame (struct x_display_info *dpyinfo, struct frame *f)
{
bool rc;
x_catch_errors (dpyinfo->display);
/* Catch errors; the target window might no longer exist. */
XReparentWindow (dpyinfo->display, FRAME_OUTER_WINDOW (f),
FRAME_OUTPUT_DATA (f)->parent_desc, 0, 0);
rc = x_had_errors_p (dpyinfo->display);
x_uncatch_errors_after_check ();
if (rc)
return false;
return true;
}
#endif
/* Setting window manager hints. */

View file

@ -1209,7 +1209,6 @@ enum
FOCUS_EXPLICIT = 2
};
/* Return the X output data for frame F. */
#define FRAME_X_OUTPUT(f) ((f)->output_data.x)
#define FRAME_OUTPUT_DATA(f) FRAME_X_OUTPUT (f)
@ -1588,6 +1587,7 @@ extern void x_wm_set_size_hint (struct frame *, long, bool);
&& defined HAVE_CLOCK_GETTIME
extern void x_sync_init_fences (struct frame *);
#endif
extern bool x_embed_frame (struct x_display_info *, struct frame *);
extern void x_delete_terminal (struct terminal *);
extern Cursor x_create_font_cursor (struct x_display_info *, int);
@ -1827,7 +1827,7 @@ extern void mark_xterm (void);
/* Is the frame embedded into another application? */
#define FRAME_X_EMBEDDED_P(f) (FRAME_X_OUTPUT(f)->explicit_parent != 0)
#define FRAME_X_EMBEDDED_P(f) (FRAME_X_OUTPUT (f)->explicit_parent != 0)
#define STORE_NATIVE_RECT(nr,rx,ry,rwidth,rheight) \
((nr).x = (rx), \