mirror of
https://git.savannah.gnu.org/git/emacs.git
synced 2026-09-10 07:46:51 -04:00
In pgtk_free_frame_resources transfer keyboard focus to parent (Bug#64625)
* src/pgtkterm.c (pgtk_new_focus_frame): Declare static. (pgtk_free_frame_resources): If this frame currently holds keyboard focus, explicitly transfer focus to its parent frame before releasing resources (Bug#64625). Copyright-paperwork-exempt: yes
This commit is contained in:
parent
6f9ac7ffdb
commit
e560eacf6d
|
|
@ -109,6 +109,7 @@ static bool current_drop_context_drop;
|
|||
static guint32 current_drop_time;
|
||||
|
||||
static void pgtk_delete_display (struct pgtk_display_info *);
|
||||
static void pgtk_new_focus_frame (struct pgtk_display_info *, struct frame *);
|
||||
static void pgtk_clear_frame_area (struct frame *, int, int, int, int);
|
||||
static void pgtk_fill_rectangle (struct frame *, unsigned long, int, int,
|
||||
int, int, bool);
|
||||
|
|
@ -467,9 +468,62 @@ pgtk_free_frame_resources (struct frame *f)
|
|||
#define CLEAR_IF_EQ(FIELD) \
|
||||
do { if (f == dpyinfo->FIELD) dpyinfo->FIELD = 0; } while (false)
|
||||
|
||||
CLEAR_IF_EQ (x_focus_frame);
|
||||
/* If this frame currently holds keyboard focus, explicitly transfer
|
||||
focus to its parent frame before releasing resources.
|
||||
|
||||
On X11 the X server delivers a FocusIn event to the parent when a
|
||||
child window is destroyed, so focus was restored automatically.
|
||||
On Wayland there is no such mechanism: the compositor does nothing,
|
||||
leaving Emacs with x_focus_frame == NULL permanently and ignoring
|
||||
all keyboard input (bug#64625).
|
||||
|
||||
IMPORTANT: we must clear highlight_frame from f BEFORE calling
|
||||
pgtk_new_focus_frame. pgtk_new_focus_frame calls
|
||||
pgtk_frame_rehighlight, which calls frame_unhighlight(old_highlight)
|
||||
where old_highlight = dpyinfo->highlight_frame. If that is still f,
|
||||
frame_unhighlight -> gui_update_cursor(f) would try to use f's face
|
||||
cache, which was already freed by free_frame_faces(f) above ->
|
||||
segfault. By clearing highlight_frame first, pgtk_frame_rehighlight
|
||||
sees old_highlight == NULL and skips frame_unhighlight entirely. */
|
||||
if (f == dpyinfo->x_focus_frame)
|
||||
{
|
||||
struct frame *new_focus = FRAME_PARENT_FRAME (f);
|
||||
|
||||
/* Clear highlight_frame from f so pgtk_frame_rehighlight will not
|
||||
call frame_unhighlight on the dying frame whose faces are freed. */
|
||||
if (dpyinfo->highlight_frame == f)
|
||||
dpyinfo->highlight_frame = NULL;
|
||||
|
||||
if (new_focus != NULL
|
||||
&& FRAME_LIVE_P (new_focus)
|
||||
&& FRAME_GTK_WIDGET (new_focus) != NULL
|
||||
&& gtk_widget_get_realized (FRAME_GTK_WIDGET (new_focus)))
|
||||
{
|
||||
/* Transfer Emacs's internal focus/highlight to the parent. */
|
||||
pgtk_new_focus_frame (dpyinfo, new_focus);
|
||||
/* Physically move the GTK/Wayland keyboard focus to the parent
|
||||
widget. The Wayland compositor will not do this automatically
|
||||
when the child widget is destroyed. */
|
||||
gtk_widget_grab_focus (FRAME_GTK_WIDGET (new_focus));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Parent is gone or unrealized; just clear focus state. */
|
||||
dpyinfo->x_focus_frame = NULL;
|
||||
pgtk_frame_rehighlight (dpyinfo);
|
||||
}
|
||||
}
|
||||
|
||||
/* CLEAR_IF_EQ is now a no-op for highlight_frame if we already cleared
|
||||
it above, which is correct. */
|
||||
CLEAR_IF_EQ (highlight_frame);
|
||||
CLEAR_IF_EQ (x_focus_event_frame);
|
||||
|
||||
/* Clear x_focus_event_frame directly so that any focus-out event
|
||||
emitted by gtk_widget_destroy below is a no-op in
|
||||
pgtk_focus_changed, preventing a spurious
|
||||
pgtk_new_focus_frame(dpyinfo, NULL) that would undo the transfer. */
|
||||
if (f == dpyinfo->x_focus_event_frame)
|
||||
dpyinfo->x_focus_event_frame = NULL;
|
||||
CLEAR_IF_EQ (last_mouse_frame);
|
||||
CLEAR_IF_EQ (last_mouse_motion_frame);
|
||||
CLEAR_IF_EQ (last_mouse_glyph_frame);
|
||||
|
|
|
|||
Loading…
Reference in a new issue